Redis 缓冲区的使用
Redis缓冲区的作用就是用一块内存空间来暂存命令数据,以免命令处理的速度慢于发送速度造成命令丢失或处理线程CPU争抢造成性能问题。如果写入命令持续大于处理命令的速度,由于缓冲区的大小固定,会造成缓冲区溢出。服务端给每一个客户端连接都设置了输入缓冲区和输出缓冲区。
如何正确的设置输入缓冲区呢?
首先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
需要关注的参数
cmd,表示客户端新执行的命令。这个例子中执行的是 CLIENT 命令。
qbuf,表示输入缓冲区已经使用的大小。这个例子中的 CLIENT 命令已使用了 26 字节大小的缓冲区。
qbuf-free,表示输入缓冲区尚未使用的大小。这个例子中的 CLIENT 命令还可以使用 32742 字节的缓冲区。qbuf 和 qbuf-free 的总和就是,Redis 服务器端当前为已连接的这个客户端分配的缓冲区总大小。这个例子中总共分配了 26 + 32742 = 32768 字节,也就是 32KB 的缓冲区。
如果qbuf-free太小 qbuf太大就意味着缓冲区溢出即将发生。原因可能是有bigkey写入,Redis处理速率变慢。
通常服务端不止一个客户端,如果多个客户端的内存占用量超过Redis的配置maxmemory(4G)的话,就会触发内存淘汰机制。
实践经验:客户端还可以使用Pipeline批量发送命令到服务端,以提高访问性能。不使用Pipeline时,客户端是发送一个命令、读取一次结果。而使用Pipeline时,客户端先把一批命令暂存到buffer中,然后一次性把buffer中的命令发送到服务端,服务端处理多个命令后批量返回结果,这样做的好处是可以减少来回网络IO的次数,降低延迟,提高访问性能。当然,Redis服务端的buffer内存也会相应增长,可以控制好Pipeline命令的数量防止buffer超限。
避免输入缓冲去的溢出:
调大输入缓冲区
从数据命令的发送和处理速度入手
客户端的默认输入缓冲区为1G上限,一般不用再调整了。再大可能会使得Redis内存占用太多資源,而奔溃。
如何正确的设置输出缓冲区呢?
Redis 为每个客户端设置的输出缓冲区也包括两部分:一部分,是一个大小为 16KB 的固定缓冲空间,用来暂存 OK 响应和出错信息;另一部分,是一个可以动态增加的缓冲空间,用来暂存大小可变的响应结果。造成输出缓冲区溢出的原因:
bigkey的大量返回结果
执行了Monitor命令
缓冲区设置大小不合理
三种限制输出缓冲区的配置
client-output-buffer-limit normal 0 0 0 普通客户端不做限制,请求是阻塞式的
client-output-buffer-limit pubsub 8mb 2mb 60 发布订阅式 总量8mb 60s内超过2mb就会自动关闭连接
避免溢出的方式显而易见:
避免bigkey
生产不使用Monitor操作
合理设置client-output-buffer-limit
主从集群中的缓冲区
在主从集群复制的场景下,无论是全量复制或增量复制,为了保证主从节点数据不一致,都需要用到缓冲区。在全量复制的过程中,主节点向从节点传输RDB文件,继续接收客户端发送的写命令会保存在复制缓冲区中,等RDB文件的传输完成后,再发送给从节点执行。这样就就形成了主节点会给每一个同步的从节点维护一个复制的缓冲区。
如果从节点接收加载RDB文件较慢,复制缓冲区中会积累,终导致溢出。一旦出现溢出主节点就会关闭和从节点的复制操作连接,导致全量复制失败。通常的经验是我们会把主节点的数据量控制在2~4GB,这样可以使全量同步执行更快,避免缓冲区的累积。
config set client-output-buffer-limit slave 512mb 128mb 60
上限512MB 60s写入超过128MB也会触发缓冲区溢出
首先复制挤压缓冲区repl_backlog_buffer是一个大小有限的环形缓冲区。如果写满,会覆盖缓冲区的旧命令。这样就会丢失数据,因此Redis选择重新开始执行全量复制,我们可以调整repl_backlog_size值来避免覆盖的情况。
作者:zhqqqq 链接:https://juejin.cn/post/6922356523834277896
相关文章