读关注到底决定读到什么?majority 为什么读不到刚写的数据?linearizable 代价多大?这篇在 3 节点副本集上先测健康时的延迟,再 kill 两个 secondary 制造“未被多数确认”的窗口,逐个读关注对比。
local 读到 'old';中位数 0.15 ms,p99 0.45 ms available 读到 'old';中位数 0.10 ms,p99 0.28 ms majority 读到 'old';中位数 0.09 ms,p99 0.20 ms snapshot 读到 'old';中位数 0.10 ms,p99 0.22 ms linearizable 读到 'old';中位数 4.81 ms,p99 8.05 ms
local、available、majority、snapshot 的读延迟几乎一样(约 0.1 ms);linearizable 要确认仍是 primary 且被多数认可,约 4.8 ms。
已 kill 两个 secondary,并在 primary 上用 w:1 把 v 改成 "NEW" readConcern local → v = 'NEW' readConcern majority → v = 'old' readConcern linearizable(max_time_ms=3000):3002 ms 后 ExecutionTimeout(code 50): operation exceeded time limit (configured timeouts: connectTimeoutMS: 20000.0ms), full err 同时 w:majority 的写:WTimeoutError(code 64)
kill 两个 secondary 后,primary 上 w:1 写入的值,local 读得到,majority 读到旧值,linearizable 等不到多数而超时(code 50)。
10 秒后 primary 因看不到多数降级:isWritablePrimary = False 已降级的节点上 readConcern local → v = 'NEW' 已降级的节点上 readConcern majority → v = 'old'
10 秒后 primary 因看不到多数而降级;local 读仍然是 NEW,majority 仍是 old。
恢复后 readConcern local → v = 'NEW' 恢复后 readConcern majority → v = 'NEW'
secondary 恢复、写入被复制到多数后,majority 读也看到了 NEW。w:majority 超时的写入最终也生效。
事务外 find 带 readConcern snapshot: {'_id': 1, 'v': 'NEW', 'x': 1}
事务内 snapshot 读: {'_id': 1, 'v': 'NEW', 'x': 1}事务里的默认读;事务外 find 指定 snapshot 在这个版本上也能执行。
# getDefaultRWConcern
test> db.adminCommand({getDefaultRWConcern: 1}).defaultReadConcern
{ level: 'local' }
# explain 里的读关注
test> db.t.find({_id: 1}).readConcern("majority").explain().command.readConcern
{ level: 'majority' }默认读关注是 local,集群可通过 setDefaultRWConcern 修改,单次读可用 .readConcern() 覆盖。