psync scheduled to be closed ASAP for overcoming of output buffer limits


从日志我们可以知道为什么主库不能对从库进行部分同步:Unable to partial resync with slave 10.242.117.36:6666 for lack of backlog (Slave request was: 1688184130)。这个涉及到Redis的部分同步的实现。在2.8版本,redis使用了新的复制方式,引入了replication backlog以支持部分同步。

The master then starts background saving, and starts to buffer all new commands received that will modify the dataset. When the background saving is complete, the master transfers the database file to the slave, which saves it on disk, and then loads it into memory. The master will then send to the slave all buffered commands. This is done as a stream of commands and is in the same format of the Redis protocol itself.

当主服务器进行命令传播的时候,maser不仅将所有的数据更新命令发送到所有slave的replication buffer,还会写入replication backlog。当断开的slave重新连接上master的时候,slave将会发送psync命令(包含复制的偏移量offset),请求partial resync。如果请求的offset不存在,那么执行全量的sync操作,相当于重新建立主从复制。

replication backlog是一个环形缓冲区,整个master进程中只会存在一个,所有的slave公用。backlog的大小通过repl-backlog-size参数设置,默认大小是1M,其大小可以根据每秒产生的命令、(master执行rdb bgsave) +(master发送rdb到slave) + (slave load rdb文件)时间之和来估算积压缓冲区的大小,repl-backlog-size值不小于这两者的乘积。

所以在主从同步的时候,slave会落后master的时间 =(master执行rdb bgsave)+ (master发送rdb到slave) + (slave load rdb文件) 的时间之和。 然后如果在这个时间master的数据变更非常巨大,超过了replication backlog,那么老的数据变更命令就会被丢弃,导致需要全量同步。

那么我们这个Redis的数据变更量有多大呢?这个可以大概从redis的日志猜测出来:RDB: 474 MB of memory used by copy-on-write。发现这个COW的内存大小变化挺大的,有时候是2M ,有时候能够达到1414 MB。而整个Redis数据内存大小也才10G左右。这么大的变更量,默认的1M repl-backlog-size根本不够用。

那现在明白了为什么每次都全量同步的原因了,剩下最根本的问题,就是主从链接为什么会每隔1分钟左右就断开一次,导致需要重新同步?

从日志还是能够看出一些端倪:

Client id=17 addr=10.242.117.36:46501 fd=5 name= age=62 idle=62 flags=S db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=15882 oll=7597 omem=131532334 events=rw cmd=psync scheduled to be closed ASAP for overcoming of output buffer limits.

注意到这么一句话:psync scheduled to be closed ASAP for overcoming of output buffer limits。看起来是psync因为超过output buffer limits将被close。

谷歌一下,发现有挺多人遇到一样的问题:redis 2.8 psync #1400。然后设置

set "client-output-buffer-limit slave 0 0 0 

就没有问题了。

于是查看了一下client-output-buffer-limit。发现这是Redis的一个保护机制。配置格式是:

client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>

具体参数含义如下:

  • class: 客户端种类,包括Normal,Slaves和Pub/Sub
    • Normal: 普通的客户端。默认limit 是0,也就是不限制。
    • Pub/Sub: 发布与订阅的客户端的。默认hard limit 32M,soft limit 8M/60s。
    • Slaves: 从库的复制客户端。默认hard limit 256M,soft limit 64M/60s。
  • hard limit: 缓冲区大小的硬性限制。
  • soft limit: 缓冲去大小的软性限制。
  • soft seconds: 缓冲区大小达到了(超过)soft limit值的持续时间。

client-output-buffer-limit参数限制分配的缓冲区的大小,防止内存无节制的分配,Redis将会做如下自我保护:

  1. client buffer的大小达到了soft limit并持续了soft seconds时间,将立即断开和客户端的连接
  2. client buffer的大小达到了hard limit,server也会立即断开和客户端的连接

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值