从 secondary 读会读到多旧的数据?怎么限制?这篇用 failpoint 制造一个落后 95 秒的 secondary,对比不设和设 maxStalenessSeconds 的读,看驱动怎样把它排除在外。
10 个样本中各 secondary 的延迟(秒)范围: 9902: 0~2, 9903: 0~2
# hello 里的 lastWrite:客户端据此估计 staleness
test> var h = db.hello(); ({lastWrite: h.lastWrite.lastWriteDate, majorityWrite: h.lastWrite.majorityWriteDate})
{
lastWrite: ISODate('2026-10-12T03:47:37.000Z'),
majorityWrite: ISODate('2026-10-12T03:47:37.000Z')
}用 replSetGetStatus 里 primary 与 secondary 的 optimeDate 之差;秒级精度,健康时 0~2 秒。
停止拉取后 5 s:延迟 9902(被停的) = 5 s;9903(正常的) = 1 s 停止拉取后 35 s:延迟 9902(被停的) = 35 s;9903(正常的) = 1 s 停止拉取后 65 s:延迟 9902(被停的) = 65 s;9903(正常的) = 1 s 停止拉取后 95 s:延迟 9902(被停的) = 95 s;9903(正常的) = 1 s
停止拉取的 secondary,延迟等于停止的时长:95 秒后延迟 95 秒。
50 次 secondary 读:服务端分布 {'9902': 19, '9903': 31};读到明显落后(比 primary 少 5 次以上更新)的值 19 次读偏好是 secondary 时,请求在两个 secondary 间分摊,落后的那台贡献了 19 次旧值读。
50 次 secondary + maxStalenessSeconds=90 的读:服务端分布 {'9902': 1, '9903': 49};明显落后的值 1 次(被停的 9902 延迟约 95 s,已超过 90 s)设 90 后驱动排除 staleness 超过 90 秒的节点,50 次读只有 1 次漏到旧节点(估算靠心跳,有滞后)。
max_staleness=30:读失败 ConfigurationError: maxStalenessSeconds must be at least 90. maxStalenessSeconds is set to 30. max_staleness=90:读成功
最小 90 秒,也不能小于心跳间隔 + 10 秒;设 30 会报 ConfigurationError。
failpoint 关闭后 3.0 s 延迟降到 0 s(积压的 oplog 一口气应用)
恢复拉取后积压的 oplog 批量应用,95 秒的积压 3 秒追平。