19.Redis的各类缓冲区
缓冲区在客户端和服务器端交互的过程中非常常见,传统网络传输过程中,网卡收到了请求也会放入到内部缓冲中并触发一个软中断
但是缓冲区也存在相对应的隐患,即消费速度赶不上写入速度的话,会出现溢出的问题,从而导致应用程序崩溃
本章我们将会分别以服务器端的缓冲区 主从集群的缓冲多种维度来说Redis的缓冲区
1.服务器交互缓冲区
为了避免服务器端主线程压力,服务器端给每个接入的客户端都设置了一个输入和输出缓冲区
输入缓冲区会先将客户端发送的命令缓存起来,然后主线程读入,并处理完成后写到输出缓冲区
那么对于输入缓冲区溢出问题,主要可能的存在点在于
写入了bigkey,写入的数据量太大导致
服务器端处理速度跟不上,Redis主线程被阻塞了导致的
对于主线程阻塞的情况不是从缓冲区的方面能够直接解决的
对于写入bigkey,则可以考虑从缓冲区的方面解决,对于客户端输入缓冲区的情况,可以使用CLIENT LIST命令
CLIENT LIST
id=5 addr=127.0.0.1:50487 fd=9 name= age=4 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client
其中显示了不同客户端的IP号,并且显示了客户端的新执行命令
qbuf 缓冲区已经使用的大小,qbuf-free,尚未使用的大小
我们的观测点,也就是取自qbuf和qbuf-free两者之间的差
这样我们的思路就可以考虑扩大缓冲区和减少客户端每次发送的key的大小
但是在Redis中,并没有提供参数让我们调节客户端输入缓冲区的代销,所以我们只能避免在客户端写入bigkey,以及避免Redis主线程阻塞
对于服务器端的输出缓冲区的溢出,如何阻止呢?
Redis的输出缓冲区,存储的是Redis要返回给客户端的数据,主线程返回的数据可以分为两种,一种是固定大小的结果,比如OK.一种是大小并不固定的响应结果,比如HGET命令
对于缓冲区溢出的可能,很可能就是执行获取不固定的响应结果
服务器端返回bigkey的大量结果
执行MONITOR命令(一个持续不断输出Redis执行命令的操作,会一直占用输出缓冲区)
缓冲区设置不合理
对于输出缓冲区,我们是可以设置其大小的,通过client_output_buffer-limit配置项进行设置,设置缓冲区大小的上限阈值,设置缓冲区持续写入数据时的上限阈值,和持久写入时间时的时间阈值
对于这个client_out_buffer的设置,也是分为了不同的情况,这个区分的基准是根据客户端的类型判断的
分为了普通客户端,订阅客户端,集群同步客户端
普通客户端可以在配置文件中设置如下的参数
client-output-buffer-limit normal 0 0 0
normal表示式普通客户端,第一个0是缓冲区大小,第二个和第三个0分别是缓冲区写入量限制和持续写入时间限制
普通客户端每次发完一个请求,都会等待请求结果返回后再发送下一个请求,所以一般不会阻塞,故将其设置为0,表明不做限制
而订阅客户端,则是非阻塞式的,所以如果订阅频道消息过多的话,会占用过多的输出缓冲区空间,故将其可以设置为如下的参数
client-output-buffer-limit pubsub 8mb 2mb 60
pubsub表示对订阅客户端进行限制,8MB表示输出缓冲区大小为8MB,2MB + 60为60秒内写入量超过2MB的话,也会关闭客户端连接
最后是主从集群中的缓冲区问题
主从集群的数据复制包括全量复制和增量复制两种,全量复制是同步所有数据,而增量复制只会把主从库网络断链期间主库接收到命令传输过去
对于主从复制,如果从库接收加载RDB速度缓慢,会导致大量的数据积压在主节点的输出缓冲区中,最后超过限额后导致主从复制失败
对于这种问题的出现,我们可以通过控制主节点保存的数据量大小,避免一次性复制过多的命令
以及使用client-outputr-buffer-limit,设置合理的复制缓冲区代销
client-output-buffer-limit pubsub 8mb 2mb 60
上面就是主从节点的简单设置,但是主节点上复制缓冲区的大小,是每个从节点客户端输出缓冲区占用内存的总和,其次还需要控制启动时候从节点的启动顺序
最后说一下复制积压缓冲区,就是当主节点和从节点的网络发生闪断之后,主节点会先将其缓存起来,等待连接恢复之后,再次进行增量同步
对于此,我们需要设置repl_backlog_buffer的大小
总结下本章,我们说了Redis中的缓冲区,使用缓冲区的帮助和弊端
Redsi的缓冲区的问题可以分为,客户端和服务端连接中缓冲区溢出导致连接关闭和主从复制过程中环形缓冲区中新写入的数据会覆盖旧的命令数据
最后一个小问题,Redis采用了Client-server架构,服务器会维护缓冲区方便客户端输入
那么客户端是否有缓冲区
可以模仿Kafka那样,攒一波发送,减少交互,但如果需要即使消息处理的数据的话,缓冲可能误了大事