bigywater.tech
Redis · 53

Replication Backlog

复制积压缓冲区(replication backlog)决定了「从库断开多久还能只补差量」。文档里的说法是一个固定大小的环形缓冲。这篇不复述,直接量:把 backlog 设成最小的 16 KB,用一个能随时切断的 TCP 转发让从库断线,看主库写多少字节之后就再也补不上了。

28032 B
repl-backlog-size=16 KB 时,断线期间仍能部分重同步的最大写入量(本次采样点)
32000 B
本次采样里第一个退回全量同步的写入量
1 MB
默认 repl-backlog-size

backlog 何时创建

实测 · 本机执行输出
> CONFIG GET repl-backlog-size
1) "repl-backlog-size"
2) "16384"
{'repl_backlog_active': '0', 'repl_backlog_size': '16384', 'repl_backlog_first_byte_offset': '0', 'repl_backlog_histlen': '0', 'master_repl_offset': '0'}
从库连上之后: {'repl_backlog_active': '1', 'repl_backlog_size': '16384', 'repl_backlog_first_byte_offset': '1', 'repl_backlog_histlen': '0', 'master_repl_offset': '0'}

没有从库连接过的主库 repl_backlog_active 是 0;第一个从库连上之后变成 1。参数 repl-backlog-size 这里设成 16 KB(CONFIG GET 显示 16384)。

backlog 里究竟保留了多少

实测 · 本机执行输出
master_repl_offset=   4119  histlen=  4119  first_byte_offset=      1
master_repl_offset=  12055  histlen= 12055  first_byte_offset=      1
master_repl_offset=  16407  histlen= 16407  first_byte_offset=      1
master_repl_offset=  30103  histlen= 30103  first_byte_offset=      1
master_repl_offset= 100119  histlen= 18359  first_byte_offset=  81761

写到 30103 字节时 repl_backlog_histlen 仍等于 offset(30103),已经超过了配置的 16384;写到 100119 字节时才丢头部,histlen = 18359、first_byte_offset = 81761。所以 backlog 实际保留量会略微超过配置值,不是严格的环形缓冲(这一点是从上面的数字看出来的;为什么会这样——猜测是按块分配、整块释放——我没有读源码验证)。

从库断线多久还能部分重同步

用可断开的 TCP 转发模拟网络中断
实测 · 本机执行输出
      断开期间写入         结果  sync_full  partial_ok
        1024      部分重同步          0           1   日志累计:Full resync requested 2 次,Partial resynchronization request 1 次
        8064      部分重同步          0           1   日志累计:Full resync requested 2 次,Partial resynchronization request 2 次
       16000      部分重同步          0           1   日志累计:Full resync requested 2 次,Partial resynchronization request 3 次
       20096      部分重同步          0           1   日志累计:Full resync requested 2 次,Partial resynchronization request 4 次
       24064      部分重同步          0           1   日志累计:Full resync requested 2 次,Partial resynchronization request 5 次
       28032      部分重同步          0           1   日志累计:Full resync requested 2 次,Partial resynchronization request 6 次
       32000       全量同步          1           0   日志累计:Full resync requested 3 次,Partial resynchronization request 6 次
       40087       全量同步          1           0   日志累计:Full resync requested 4 次,Partial resynchronization request 6 次
       64023       全量同步          1           0   日志累计:Full resync requested 5 次,Partial resynchronization request 6 次
      100119       全量同步          1           0   日志累计:Full resync requested 6 次,Partial resynchronization request 6 次

做法:从库通过一个我写的 TCP 转发连主库;cut() 关闭转发并断开连接,主库继续写入 X 字节,resume() 之后从库自动重连,看主库 INFO stats 里是 sync_partial_ok 还是 sync_full 增加(表里最后一列是主库日志中 Full resync requested 与 Partial resynchronization request 的累计次数,两种判断方式的分类一致)。结果:X 到 28032 字节都是部分重同步——比 16384 大得多;32000 字节起全量同步。断点在本次采样的 28032–32000 之间,没有做更细的二分,也没有多次重复确认边界是否稳定。不要把「16 KB 配置 ≈ 28 KB 可用」当成规律,只当作「实际余量不止配置值」的证据。

默认值

实测 · 本机执行输出
> CONFIG GET repl-backlog-size
1) "repl-backlog-size"
2) "1048576"
> CONFIG GET repl-backlog-ttl
1) "repl-backlog-ttl"
2) "3600"

默认 repl-backlog-size 是 1048576 字节(1 MB),repl-backlog-ttl 是 3600 秒。每秒写入量 × 预期最长断线时间,再留余量,就是该设的大小。

分步演示:断线补差量的边界

复制积压缓冲区
本步的数据

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。主库 repl-backlog-size=16kb;从库经过一个自写的 TCP 转发连接主库,转发被 cut()/resume() 模拟断线
    • 没有验证:同样设置在 Redis 其他版本上的边界、多个从库时的边界、断开时间对 repl-backlog-ttl 的影响、backlog 内部数据结构
    京ICP备2026067502号-1京公网安备11010502063487号