Redis开发与运维学习笔记—(2)

  • 2020 年 3 月 31 日
  • 筆記

Redis的单线程架构

Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务,我们来看Redis的单线程命令处理机制。

我们同时打开三个窗口,第1个窗口输入:

127.0.0.1:6379> set hello world

OK

127.0.0.1:6379> get hello

"world"

第2窗口输入:

127.0.0.1:6379> incr counter

(integer) 1

第3个窗口输入:

127.0.0.1:6379> incr counter

(integer) 2

因为在redis中是单线程来处理命令的,所以一条命令从客户端到达服务器端之前不会被立即执行,而是会进入一个队列中,上面3个命令之间的执行顺序是不确定的,但是可以确定的是,肯定不会有两条命令被同时执行

为什么单线程的redis还能处理得那么快?

主要原因如下:

1、redis是纯内存访问,它将所有的数据存放在内存中,内存的相应时间大约为100ns,这是redis达到每秒万级别访问的基础。

2、非阻塞I/O,redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的时间处理模型将epoll中的连接、读写、关闭都转换为时间,不在网络I/O上浪费过多的时间。

3、单线程,避免了线程切换和资源竞争。这样服务端也就没有了锁争用

慢查询分析

要了解redis的慢查询,首先需要知道redis的查询模型:

redis的查询模型分为4步:

1、发送命令

2、排队

3、执行命令

4、返回结果

redis的慢查询只统计步骤3的时间。

慢查询的2个配置参数

对于慢查询,redis配置了2个关键参数,其中第一个是慢查询的阈值:slowlog-log-slower-than和slowlog-max-len配置来解决这两个问题。其中:

第一个参数单位是微妙(1s=1000ms=1000000ns),默认值是1000,加入某个命令执行时间超过这个值,那么他就会被记录在慢查询日志中。

这里还有一点需要注意:如果设置slowlog的参数值为0,则会记录所有的命令,如果slowlog值小于0,则对于任何命令都不会记录。

slowlog-max-len指的是慢查询日志列表的最大长度,如果这个值设置为5,则当慢查询到达6的时候,最早的一个命令将被移除列表。

在redis中,有2种修改参数的方法,第一种是修改配置文件,另一种是使用config set命令动态修改,如果要将redis的配置持久化到本地的配置文件,则需要执行config rewrite的命令。我们看看参数的默认值:

[root@VM_48_10_centos redis]# cat redis.conf |grep slowlog  slowlog-log-slower-than 10000  slowlog-max-len 128  

当我们使用config rewrite之后,可以看到:

[root@VM_48_10_centos redis]# redis-cli  127.0.0.1:6379> config set slowlog-max-len 256  OK  127.0.0.1:6379> config rewrite  20673:M 26 Mar 23:14:58.643 # CONFIG REWRITE executed with success.  OK  127.0.0.1:6379> exit  [root@VM_48_10_centos redis]# cat redis.conf |grep slowlog  slowlog-log-slower-than 10000  slowlog-max-len 256  

已经成功的将配置写入了配置文件中了。

慢查询如何查看?

redis的慢查询是存放在redis的内存列表中的,但是redis并没有暴露这个列表的键,而是通过一组命令来实现对慢查询日志的访问和管理:

slowlog get [n]

上面的命令可以返回当前redis的慢查询,参数n可以指定条数。下面是测试例子:

[root@VM_48_10_centos redis]# redis-cli  127.0.0.1:6379> config set slowlog-log-slower-than 0  OK  127.0.0.1:6379> set hello world  OK  127.0.0.1:6379> get hello  "world"  127.0.0.1:6379> slowlog get 2  1) 1) (integer) 4     2) (integer) 1585235910     3) (integer) 10     4) 1) "slowlog"        2) "get"        3) "1"  2) 1) (integer) 3     2) (integer) 1585235905     3) (integer) 4     4) 1) "get"        2) "hello"  

每条日志有4个属性,分别是redis慢日志的标识id、发生的时间戳、命令耗时和参数。

还有:

slowlog len命令用来查询慢查询当前的条数。

slowlog reset用来重置慢查询列表

127.0.0.1:6379> slowlog len  (integer) 6  127.0.0.1:6379> slowlog reset  OK  127.0.0.1:6379> slowlog len  (integer) 1  

我们由于配置了slowlog-log-slow..为0,所以清理之后,还会记录slowlog len本身。

几点注意:

1、线上的话,slowlog-max-len建议调大,因为记录慢查询时redis会对长命令做截断处理,所以并不会占用大量内存。线上的可以设置1000以上。

2、slowlog-log-slower-than默认值超过10ms就判定为慢查询,需要根据redis的并发量调整,如果某个应用是高并发的,如果命令执行时间在1ms以上,则OPS将不到1000,要根据实际情况来调整这个参数。

3、慢查询只记录命令的执行时间,并不包括命令排队和网络传输时间,因此客户端执行命令的时间会大于命令实际执行时间,因此当线上出现阻塞时,应当先分析慢查询,从而排除慢查询造成的阻塞。

4、因为慢查询日志是一个先进先出的队列,在慢查询比较多的情况下,可以定期执行slow get命令将慢查询日志持久化到其他存储中,然后定制可视化界面进行查询。