上一篇看到 min-replicas-to-write 会在联系不上从库时拒绝写入。这一篇看它的另一半:max-lag 的「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 决定:设得越小,窗口越小,误停写的概率越高。