唯一可控的冷热分级路径是手动绑定标签、范围和分片键;需用mongos连接并赋予clustermanager权限,标签名区分大小写,添加顺序不可颠倒,sh.updateZoneKeyRange()范围须严丝合缝、左闭右开且不重叠,哈希分片键需先转换再设范围,存量数据需手动moveChunk迁移,业务时间窗口依赖外部系统判断。

不能靠自动识别,必须手动绑定标签、范围和分片键——这是唯一可控的冷热分级路径。
sh.addShardTag() 执行失败的常见原因
命令看似简单,但失败时往往不报明确错误。最常踩的坑是连接点不对或权限不足。
- 必须用
mongos连接执行,不能直连任意mongod;运行db.runCommand({isMaster: 1}),确认返回中有"msg" : "isdbgrid" - 用户需有
clustermanager角色,查法:db.getUsers({filter: {roles: {$elemMatch: {role: "clustermanager"}}}}) - 标签名区分大小写:
"SSD"和"ssd"是两个 zone,混用会导致后续updateZoneKeyRange()匹配不上 - 添加顺序不能颠倒:先
sh.addShardTag("shard01", "hot"),再sh.addTagRange();反过来会静默失败
sh.updateZoneKeyRange() 的范围必须严丝合缝
这个命令不是“建议”,而是路由强制策略。范围写错,数据就进不了目标分片,甚至写入失败。
- 键结构必须与分片键完全一致:若分片键是
{created_at: 1, user_id: 1},就不能只用{created_at: ISODate("2025-01-01")}定义范围 - 边界必须用
MinKey/MaxKey占位,不能用null、空对象或字符串"min" - 范围左闭右开,且不能重叠:比如
{created_at: MinKey}到{created_at: ISODate("2025-01-01")},和{created_at: ISODate("2025-01-01")}到{created_at: MaxKey}才合法 - 哈希分片键必须先调用
convertShardKeyToHashed()算出真实哈希值,再设范围;否则范围无效
存量数据不会自动迁移,moveChunk 是绕不开的手动操作
打完标签、划好范围,只是改了“未来写入”的路由规则。老数据还在原地,得自己搬。
- 迁移前先停写或切读写分离,避免
moveChunk过程中写入冲突 - 用
sh.status()查看 chunk 分布,定位属于冷范围的 chunk 列表,不要盲目全量迁移 - 逐个执行
sh.moveChunk("db.collection", {created_at: ISODate("2024-01-01")}, "shard02"),每次只动一个 chunk - 若报
conflicting operation,说明 balancer 正在干活,临时关掉:sh.stopBalancer(),迁移完再开 - chunk 太大(如 >128MB)时,先用
sh.splitAt()切小,否则容易超时或锁太久
真正难的不是命令,是业务时间窗口的判断
MongoDB 不提供访问热度指标,也没有“三个月没读就是冷数据”的内置逻辑。你得靠外部系统反推:
- 查业务日志或监控,确认哪些时间范围的数据基本只读不写、QPS 极低
- 结合归档策略:比如订单超过 180 天进入只读状态,就可定义
order_date范围为 cold zone - 一旦分片键选窄了(如只用
{status: 1}),chunk 根本无法按时间切分,整个 zone 策略直接失效 - 所有范围必须连续无空缺,否则新写入会报
no shard can fulfill the query











