如何应对输入缓冲区溢出?
输入缓冲区就是用来暂存客户端发送的请求命令的,所以可能导致溢出的情况主要是下面两种:
- 写入了 bigkey,比如一下子写入了多个百万级别的集合类型数据;
- 服务器端处理请求的速度过慢,例如,Redis 主线程出现了间歇性阻塞,无法及时处理正常发送的请求,导致客户端发送的请求在缓冲区越积越多。
要查看和服务器端相连的每个客户端对输入缓冲区的使用情况,我们可以使用 CLIENT LIST 命令。
与输入缓冲区相关的三个参数:
- cmd,表示客户端最新执行的命令。
- qbuf,表示输入缓冲区已经使用的大小。
- qbuf-free,表示输入缓冲区尚未使用的大小。
如果 qbuf 很大,而同时 qbuf-free 很小,就要引起注意了。
客户端输入缓冲区溢出,Redis 的处理办法就是把客户端连接关闭,结果就是业务程序无法进行数据存取了。
Redis 的客户端输入缓冲区大小的上限阈值,在代码中就设定为了 1GB。
我们可以从两个角度去考虑如何避免,一是把缓冲区调大,二是从数据命令的发送和处理速度入手。
如何应对输出缓冲区溢出?
Redis 为每个客户端设置的输出缓冲区也包括两部分:一部分,是一个大小为 16KB 的固定缓冲空间,用来暂存 OK 响应和出错信息;另一部分,是一个可以动态增加的缓冲空间,用来暂存大小可变的响应结果。
那什么情况下会发生输出缓冲区溢出呢? 我为你总结了三种:
- 服务器端返回 bigkey 的大量结果;
- 执行了 MONITOR 命令;
- 缓冲区大小设置得不合理。
MONITOR 的输出结果会持续占用输出缓冲区,并越占越多,最后的结果就是发生溢出。所以,我要给你一个小建议:MONITOR 命令主要用在调试环境中,不要在线上生产环境中持续使用 MONITOR。
我们可以通过 client-output-buffer-limit 配置项,来设置缓冲区的大小。
当我们给普通客户端设置缓冲区大小时,通常可以在 Redis 配置文件中进行这样的设置:
client-output-buffer-limit normal 0 0 0
其中,normal 表示当前设置的是普通客户端,第 1 个 0 设置的是缓冲区大小限制,第 2 个 0 和第 3 个 0 分别表示缓冲区持续写入量限制和持续写入时间限制。都设为0,也就是不做限制
我们会给订阅客户端设置缓冲区大小限制、缓冲区持续写入量限制,以及持续写入时间限制,可以在 Redis 配置文件中这样设置:
client-output-buffer-limit pubsub 8mb 2mb 60
其中,8mb 表示输出缓冲区的大小上限为 8MB,一旦实际占用的缓冲区大小要超过 8MB,服务器端就会直接关闭客户端的连接;2mb 和 60 表示,如果连续 60 秒内对输出缓冲区的写入量超过 2MB 的话,服务器端也会关闭客户端连接。
主从集群中的缓冲区
在全量复制过程中,主节点在向从节点传输 RDB 文件的同时,会继续接收客户端发送的写命令请求。这些写命令就会先保存在复制缓冲区中,等 RDB 文件传输完成后,再发送给从节点去执行。主节点上会为每个从节点都维护一个复制缓冲区,来保证主从节点间的数据同步。
复制缓冲区一旦发生溢出,主节点也会直接关闭和从节点进行复制操作的连接,导致全量复制失败。
解决方法:
- 一方面,我们可以控制主节点保存的数据量大小。
- 另一方面,我们可以使用 client-output-buffer-limit 配置项,来设置合理的复制缓冲区大小。设置的依据,就是主节点的数据量大小、主节点的写负载压力和主节点本身的内存大小。
config set client-output-buffer-limit slave 512mb 128mb 60
其中,slave 参数表明该配置项是针对复制缓冲区的。512mb 代表将缓冲区大小的上限设置为 512MB;128mb 和 60 代表的设置是,如果连续 60 秒内的写入量超过 128MB 的话,也会触发缓冲区溢出。
复制积压缓冲区的溢出问题
增量复制时使用的缓冲区,这个缓冲区称为复制积压缓冲区。
首先,复制积压缓冲区是一个大小有限的环形缓冲区。当主节点把复制积压缓冲区写满后,会覆盖缓冲区中的旧命令数据。如果从节点还没有同步这些旧命令数据,就会造成主从节点间重新开始执行全量复制。
其次,为了应对复制积压缓冲区的溢出问题,我们可以调整复制积压缓冲区的大小,也就是设置 repl_backlog_size 这个参数的值。
此文章为8月Day16学习笔记,内容来源于极客时间《redis核心技术与实战》