为什么副本集里放 arbiter 会让 w:majority 出问题?这篇搭一个 PSA,停掉唯一的 secondary,看 primary、写关注、majority 读和提交点的表现,并和 PSS 对比。
成员: 9901=PRIMARY, 9902=SECONDARY, 9903=ARBITER
# 有 arbiter 时的默认写关注
test> var r = db.adminCommand({getDefaultRWConcern: 1}); ({defaultWriteConcern: r.defaultWriteConcern, defaultWriteConcernSource: r.defaultWriteConcernSource})
{
defaultWriteConcern: undefined,
defaultWriteConcernSource: 'implicit'
}
arbiter 9903:hello.arbiterOnly = True;向它读数据:NotPrimaryError: node is not in primary or recovering state, full error: {'topologyVersion': {'pr(它没有数据)primary + secondary + arbiter:arbiter 参与投票但不存数据,所以只有 2 个数据节点。
w:1 0.2 ms;w:majority 5.0 ms
primary + arbiter 仍是多数,primary 不降级,但 w:majority 需要的是“多数节点持久化了这次写入”,arbiter 无法确认,于是超时。
primary 还是 primary: isWritablePrimary = True w:1 的 insert:成功,0.6 ms 不指定写关注(集群默认写关注是 implicit):insert 成功,0.3 ms——有 arbiter 时隐式默认是 w:1,不是 w:majority w:majority(wtimeout=2000):2012 ms 后 WTimeoutError(code 64)
有 arbiter 时隐式的默认写关注是 w:1,所以不显式指定写关注的写入看起来一切正常——它们并没有被多数确认。
刚写入的 {k: "w1"}:readConcern local → True;readConcern majority → False提交点停住,readConcern: majority 读不到新数据;local 读得到。
已多写 2000 个文档:appliedOpTime.ts = 1791777439.4;lastCommittedOpTime.ts = 1791777434.122(提交点相对开始时 没动);落后 5 秒 已多写 4000 个文档:appliedOpTime.ts = 1791777440.4;lastCommittedOpTime.ts = 1791777434.122(提交点相对开始时 没动);落后 6 秒 已多写 6000 个文档:appliedOpTime.ts = 1791777441.4;lastCommittedOpTime.ts = 1791777434.122(提交点相对开始时 没动);落后 7 秒 已多写 8000 个文档:appliedOpTime.ts = 1791777442.4;lastCommittedOpTime.ts = 1791777434.122(提交点相对开始时 没动);落后 8 秒 已多写 10000 个文档:appliedOpTime.ts = 1791777443.4;lastCommittedOpTime.ts = 1791777434.122(提交点相对开始时 没动);落后 9 秒
写入继续,但多数提交点不前进,差距越来越大,存储引擎要保留更多历史版本。
secondary 回来后:appliedOpTime.ts = 1791777443.4;lastCommittedOpTime.ts = 1791777443.4 w:majority 又能成功了:5.8 ms PSS(primary + 2 个 secondary)停掉一个 secondary:w:majority 成功,28.1 ms
三个数据节点停掉一个,另外两个就能确认多数,w:majority 不受影响。