bigywater.tech
Redis · 95

min-replicas-max-lag

上一篇看到 min-replicas-to-write 会在联系不上从库时拒绝写入。这一篇看它的另一半:max-lag 的「lag」究竟是什么,以及把这个设置放进脑裂场景里,它能挽回多少数据。

lag = 距上次 ACK 的秒数
冻结一个从库,它在主库 INFO 里的 lag 每秒 +1
1226 → 63
同一个脑裂实验里,加 min-replicas 前后丢失的已确认写入
1164 次
旧主库拒绝的写入(NOREPLICAS)

lag 是什么

实测 · 本机执行输出
  冻结前: [['lag=1', 'io-thread=0'], ['lag=0', 'io-thread=0']]
  冻结后 1 s:slave0 lag = 2,slave1 lag = 0
  冻结后 2 s:slave0 lag = 3,slave1 lag = 0
  冻结后 3 s:slave0 lag = 4,slave1 lag = 0
  冻结后 4 s:slave0 lag = 5,slave1 lag = 1
  冻结后 5 s:slave0 lag = 6,slave1 lag = 1
  冻结后 6 s:slave0 lag = 7,slave1 lag = 1
  冻结后 7 s:slave0 lag = 8,slave1 lag = 1

主库 INFO replication 的 slaveN 行里有 lag=:从库每秒发一次 REPLCONF ACK,主库记录最近一次收到的时间,lag 就是「现在减去那个时间」的秒数。冻结一个从库后,它的 lag 每秒加 1;另一个正常的从库保持在 1 以内。min-replicas-max-lag 3 意思是 lag ≤ 3 的从库才算「好」。

放进脑裂实验

实测 · 本机执行输出
  sentinel 切换 4.2 s;客户端 A(直连旧主库)共 376 次写入被回复 OK,其中分区期间 303 次;失败 1454 次 [('NOREPLICAS Not enough good replicas to w', 1164), ('BrokenPipeError', 289)]
  最终在新主库上还在的 313 条,丢失 63 条

同样是第 91 篇的分区(sentinel 切换主库,客户端 A 继续写旧主库),只是旧主库多了 min-replicas-to-write 1 和 min-replicas-max-lag 3。故障转移后从库都离开了旧主库,它的好从库数变成 0,约 3 秒后开始拒绝 A 的写入(NOREPLICAS,1164 次)。A 收到 OK 的写入只有 376 条(无保护时 1540 条),最终丢失 63 条(无保护时 1226 条)。剩下的 63 条丢失,来自 max-lag 那 3 秒窗口里仍被接受的写入——min-replicas 缩小了窗口,没有消除它。

代价

同样的设置在没有故障、只是从库重启或网络抖动时也会让主库停写(第 94 篇)。所以这是一个「宁可不可用也不丢数据」的取舍,并且窗口大小由 max-lag 决定:设得越小,窗口越小,误停写的概率越高。

分步演示:min-replicas 对脑裂的作用

min-replicas-max-lag
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。实验条件同第 91 篇(代理切断 sentinel 与主库的通路;客户端 A 直连旧主库,每 10 ms 一次同步 SET),仅多了 min-replicas 两项配置;每种配置只跑一次
    • 没有验证:多次重复的方差、max-lag 取 1 或 10 时丢失量的变化、客户端 A 同时读写时的行为、真实网络分区
    京ICP备2026067502号-1京公网安备11010502063487号