最直接办法是执行db.runCommand({getShardVersion:"db.collection"})比对version字段与config server最新版本是否一致,不一致即缓存脏;mongos默认30秒拉取更新,迁移高峰易错过轮询窗口。

怎么确认 mongos 当前路由缓存是否脏
最直接的办法是连上 mongos,执行
db.runCommand({ getShardVersion: "db.collection" })</p>
<p>观察返回里的 <code>version 字段:如果它和 config server 上该 chunk 的最新版本不一致(可通过 sh.status() 或查 config.chunks 确认),就说明这个 mongos 实例缓存没更新。注意,不同 mongos 实例之间缓存可能各自滞后,不能只查一个。
常见错误现象包括:StaleConfig 报错、查询结果重复、部分数据查不到但实际存在。
为什么 getShardVersion 返回的 version 会落后
mongos 默认每 30 秒主动拉取一次 config server 的元数据更新(通过 configRefreshIntervalMS 控制),但迁移高峰时可能错过轮询窗口;更关键的是,moveChunk 过程中 config server 元数据已更新,而 mongos 缓存尚未刷新,导致它仍把请求发往旧分片。
以下情况会加剧问题:
- 配置了过长的
--configRefreshIntervalMS(比如默认 30000,线上建议设为 5000–10000) - mongos 启动后长时间未触发首次刷新(冷启动延迟)
- 网络抖动或 config server 响应慢,导致某次拉取失败且未重试
如何安全地刷新单个 mongos 的路由缓存
不要一上来就用 db.adminCommand({ flushRouterConfig: 1 }) ——它是全库级刷新,高频调用会给 config server 带来压力,且无法指定范围。
更轻量的做法是按需触发:
- 在关键业务查询前,先执行
db.runCommand({ getShardVersion: "db.collection" }),比对版本;若发现落后,可等待 1–2 秒再重试,或调用db.adminCommand({ flushRouterConfig: 1 })后立即重查 - 应用层捕获
StaleConfig错误后,自动重试并强制刷新(而非无脑重试) - 运维侧可用脚本定期轮询所有 mongos 实例的
getShardVersion结果,对比 config server 版本生成告警
哪些操作会让路由不一致风险陡增
不是所有运维动作都平等。以下几类操作极易放大缓存不一致窗口:
- 执行
movePrimary:会重置整个数据库的路由版本,影响面广 - 批量
splitChunk:短时间内产生大量新 chunk,mongos 缓存来不及同步 - 手动在某个 shard 上建/删索引但未同步到其他 shard:后续
checkMetadataConsistency会报InconsistentIndex,间接干扰路由决策 - 滚动升级 mongos 时未灰度——新旧版本对 ChunkVersion 解析逻辑有细微差异,可能造成短暂路由错乱
真正难处理的不是“缓存滞后”本身,而是它和分片键设计、查询模式耦合后产生的隐性问题:比如用非 _id 字段做分页游标,在路由错乱时会导致同一批数据被重复扫描。这类细节往往在线上压测阶段才暴露。



















