灰度切流不能直接在mongos层实现,因其仅支持基于分片键的固定路由,缺乏按用户ID等特征动态分流能力;强行绕过将导致shard key冲突、元数据不一致及迁移失败。

灰度切流在 MongoDB 分片集群中不是原生支持的功能,必须靠应用层或中间件控制,否则直接改 mongos 路由规则会破坏分片逻辑、引发数据不一致甚至写丢失。
为什么不能直接在 mongos 层做灰度路由
MongoDB 的 mongos 不提供按请求特征(如用户 ID、业务标签)动态分流的能力。它只依据分片键(shard key)哈希或范围路由到对应分片,所有写入都严格遵循该规则。强行绕过会导致:
-
shard key冲突:同一逻辑记录被写入不同分片,后续查询无法聚合 - 元数据不一致:配置服务器(
config server)中 chunk 分布信息与实际数据错位 - 迁移失败风险:正在执行的
moveChunk操作可能因非预期写入中断
真正的灰度切流必须落在应用 DAO 层
生产实践中唯一可控、可验证的灰度方式,是让应用自己决定“这条数据写 mongo 还是写新库”,再通过双写 + 切量开关实现渐进式迁移。关键点:
- 所有数据库访问必须收口到统一 DAO 接口,不能存在直连
mongoClient的散落调用 - 灰度开关建议用配置中心(如 Apollo/Nacos)动态控制,避免重启生效
- 切流比例不能简单按请求计数,要按业务实体维度(如
user_id % 100 )保证同一用户/订单始终走同一路由 - 写失败必须有补偿机制:
mongo成功但新库失败时,需发 MQ 触发异步重试,不能丢数据
如何验证灰度过程中的数据一致性
仅靠日志比对不可靠,必须做实时字段级校验。推荐方案是双写完成后,由应用主动触发一次读取比对:
- 从
mongo和新库分别查出同一主键记录,逐字段比对(排除_id、createdAt等非业务字段) - 差异结果打标后写入专用监控表,触发告警(例如字段
status不一致率 > 0.1% 立即暂停切流) - 不要依赖
mongodump+mongorestore做一致性校验——它们不校验索引、TTL、权限等元数据,且无法覆盖正在变更的热数据
切流完成前最容易忽略的三个点
很多团队卡在收尾阶段,不是因为技术做不到,而是漏掉了这些隐性依赖:
-
mongos的连接池里还缓存着旧分片拓扑,切流后需滚动重启所有应用实例,否则部分请求仍发往已下线分片 - 应用中硬编码的
shard key逻辑(如shardKey: { userId: 1, createTime: -1 })如果和新库分片策略冲突,会导致写倾斜 - 监控指标只看 QPS/错误率,没采集
sh.status()中的 chunk 均衡度、db.printShardingStatus()中的迁移队列长度,导致热点分片长期未被发现


















