同mysql一样,执行时间超过设定值时,将命令以及耗时等信息记录下来。

redis的指令会放在一个队列中,单线程顺序获取执行。

1.慢查询设置

127.0.0.1:6379> config set slowlog-log-slower-than 10000
OK  -- 默认10ms
127.0.0.1:6379> config rewrite
OK  -- 刷新到配置文件

值设为0时:所有命令都记录

值为-1时:所有命令都不记录

或直接在配置文件中找到配配置修改。

2.慢查询原理

慢查询记录放在队列中。

使用slow-max-len查看记录的最大条数。

可以设置config set slow-max-len=100,当有100个慢查询记录后,后面再来的慢查询记录会让第一条命令出队,将新的命令插进来。

3.慢查询命令

1.获取队列里的慢查询

slowlog get

2.重置队列

slowlog reset

3.对于线上 slow-max-len 配置的建议:线上可加大 slow-max-len 的值,记录慢查询存
长命令时 redis 会做截断,不会占用大量内存,线上可设置 1000 以上
4.对于线上 slowlog-log-slower-than 配置的建议:默认为 10 毫秒,根据 redis 并发量
来调整,对于高并发比建议为 1 毫秒

4.性能测试

redis-benchmark -h 192.168.42.111 -p 6379 -c 100 -n 10000
-- 100 个并发连接,10000 个请求,检测服务器性能
redis-benchmark -h 192.168.42.111 -p 6379 -q -d 100
-- 测试存取大小为 100 字节的数据包的性能
redis-benchmark -h 192.168.42.111 -p 6379 -t set,get -n 100000 -q 
-- 只测试 set,lpush 操作的性能
redis-benchmark -h 192.168.42.111 -p 6379 -n 100000 -q script load
"redis.call('set','foo','bar')"
-- 只测试某些数值存取的性能

5.运行原理

发送命令->命令排队->执行命令->返回结果

6.PIPELINE

由于redis是单线程的,每次请求操作都需要等待上次的请求结束后才能继续执行,每次都需要建立网络连接。

因此如果进行批量操作,如:

public static void batchDel(String...keys){
        Jedis jedis = new Jedis("xxx",6379);
        for(String key:keys){
            jedis.del(key);
        }
        jedis.close();
    }

是十分耗时的。

而使用PIPELINE可以实现一次发送多个命令,不需要等待服务端返回,因此可以大大提高性能,减少网络往返时间。

public static void batchDel(String...keys){
        Jedis jedis = new Jedis("xxx",6379);
        Pipeline pipelined = jedis.pipelined();
        for(String key:keys){
            pipelined.del(key);
        }
        pipelined.sync();//
        jedis.close();
    }

7.弱事务性

一组事务要么成功要么失败。

那么redis的事务有什么不同呢?

语法:

multi: 开启事务

exec : 提交事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK

事务中的指令被放在队列中,执行exec的时候才会提交。

异常处理

127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd age 18
QUEUED
127.0.0.1:6379> sadd name wml
QUEUED
127.0.0.1:6379> incrby name 2
QUEUED
127.0.0.1:6379> exec 
1) (integer) 1
2) (integer) 1
3) (error) WRONGTYPE Operation against a key holding the wrong kind of value

最后一个命令报错。

127.0.0.1:6379> smembers age
1) "18"
127.0.0.1:6379> smembers name
1) "wml"

但仍可以拿到数据,说明未出错的命令都正常执行。

语法错误

127.0.0.1:6379> multi 
OK
127.0.0.1:6379> set haha wml
QUEUED
127.0.0.1:6379> sett heihe wml
(error) ERR unknown command `sett`, with args beginning with: `heihe`, `wml`, 
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get haha
(nil)

如上,出现语法错误直接报错,且事务执行失败。

watch

watch主要用于监控一个key,其实就类似于CAS操作,一旦被监控的key,在提交事务前被修改了,则该事务就会执行失败。

127.0.0.1:6379> set order spring
OK
127.0.0.1:6379> watch order
OK
127.0.0.1:6379> get order
"spring"
127.0.0.1:6379> multi
OK

如上,监控order,开启事务。

我们在另一个客户端修改该key:

127.0.0.1:6379> append order cloud
(integer) 11
127.0.0.1:6379> get order
"springcloud"

然后,我们再在第一个客户端操作该key:

127.0.0.1:6379> append order boot
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get order
"springcloud"

发现提交失败,order的值为第二个客户端修改的值。

而unwatch可以取消对某个key的监控。

8.发布订阅

非常简单的发布订阅模式。

订阅:

127.0.0.1:6379> subscribe channel_1 channel_2 channel_3
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel_1"
3) (integer) 1
1) "subscribe"
2) "channel_2"
3) (integer) 2
1) "subscribe"
2) "channel_3"
3) (integer) 3

订阅三个管道。

发布

新开个客户端发布消息:

127.0.0.1:6379> publish channel_1 "I am the first message"
(integer) 1

向管道1发送了一条消息。

此时第一个客户端收到消息:

1) "message"
2) "channel_1"
3) "I am the first message"

批量订阅和取消订阅

PSUBSCRIBE xxx*

PUNSUBSCRIBE xxx*

127.0.0.1:6379> psubscribe channel_*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel_*"
3) (integer) 1

查看订阅数:

127.0.0.1:6379> pubsub numsub channel_1
1) "channel_1"
2) (integer) 1

取消订阅

unsubscribe channel_1