staleconfig 错误是 mongodb 分布式事务中因 mongos 缓存的分片元数据过期而拒绝执行事务,常见于分片迁移、增删分片等拓扑变更后;需通过 flushrouterconfig 命令强制刷新,并在应用层捕获错误码 13388 进行幂等重试。

为什么分布式事务里会突然报 StaleConfig 错误
这个错误不是你代码写错了,而是 MongoDB 在执行分布式事务时,发现当前节点缓存的分片集群元数据(比如 chunk 分布、shard 路由表)已经过期。它拒绝继续执行事务,因为继续下去可能读到旧数据、路由到错误分片,甚至导致事务不一致。
常见触发场景:分片集群刚完成迁移(moveChunk)、添加/删除分片、修改 zone range 后立刻开启新事务;或者某个 mongos 进程长时间没刷新配置,而集群拓扑已变。
- 不是所有事务都会触发——只影响跨分片的写操作(比如向两个不同分片的集合插入数据)
-
mongos是关键角色:它负责合并配置并下发给客户端,配置陈旧就直接报错 - 错误信息典型长这样:
StaleConfig: exception: { ok: 0.0, errmsg: "stale config detected", code: 13388 }
怎么让 mongos 主动刷新配置而不是等超时
默认情况下,mongos 每 30 秒拉一次 config server 的配置。但出错时不能干等,得手动“唤醒”它。
最直接有效的方式是向 mongos 发送 flushRouterConfig 命令,强制它丢弃本地缓存、重新全量同步:
db.runCommand({ flushRouterConfig: 1 })
- 必须在
admin数据库下执行(连接任意mongos) - 对整个
mongos实例生效,不是单个连接或事务 - 生产环境建议加到部署脚本里:每次做完分片变更(如
sh.moveChunk)后,自动调用该命令 - 注意权限:执行用户需有
clusterAdmin角色
应用层如何避免事务中途被 StaleConfig 中断
不能指望每次出错都人工 flush,得在代码里做防御性处理。核心思路是:捕获错误 + 退避重试 + 限制重试次数。
- 只重试幂等事务:确保事务内所有操作可安全重复(例如用
upsert替代insert,用$setOnInsert控制字段写入时机) - 不要无脑重试:遇到
StaleConfig时,先 sleep 100–500ms(给mongos时间刷新),再重试;最多 2–3 次 - 驱动差异要注意:Node.js 的
mongodb驱动 v4+ 默认不自动重试分布式事务,需手动 catcherror.code === 13388;Python 的pymongo同理,检查exc.code - 别在重试时新建 session:复用同一个
ClientSession,否则可能触发新事务分配到更旧的mongos
哪些操作会悄悄加剧 StaleConfig 风险
有些看似无关的操作,其实在后台频繁变更集群状态,容易让 mongos 缓存来不及跟上。
- 高频使用
sh.splitAt()或sh.splitFind()手动切分 chunk(尤其在业务高峰期) - 同时运行多个
moveChunk(即使目标分片不同),config server 压力大,同步延迟升高 - 部署了多个
mongos实例但没做健康检查,部分实例卡在旧配置里,流量打过去就报错 - 监控缺失:没采集
shardingStatistics中的configServerState和lastSeenConfigServer字段,无法及时发现配置滞后
真正麻烦的不是报错本身,而是它往往出现在高并发写入场景下——这时候 flush 和重试的节奏稍一失控,就会引发雪崩式重试和连接堆积。所以得把配置刷新、重试策略、分片运维三者串起来看,不能只盯一个点。










