Tag-Aware Sharding必须依赖分片集群,仅在副本集节点打标签对写入无效;冷热数据物理分离需配合sh.addShardTag()、sh.addTagRange()及开启balancer,且分片键须覆盖全量数据范围并确保chunk迁移完成。
副本集里给节点加 tags 只能影响读请求路由(readPreferenceTags),对写入完全无效。冷热数据真正物理分离,必须用分片集群 + tag-aware sharding。否则所谓“分离”只是读走冷节点、写仍打到主节点再同步——冷节点磁盘照样要承受复制流量,起不到降本或隔离效果。
关键判断点:
- 如果你只有副本集,别折腾 tags 控制写入,它不支持;
- 如果你已上分片集群,但没开 balancer 或没设 tag range,那 sh.addShardTag() 单独调用只是存了个元数据,数据不会自动迁移。
sh.status(),输出中要有 shards 和 balancer 状态shard 上,不是 mongod 进程或副本集成员上"tier": "cold",不能写 "tier": 0 或 "tier": false
常见错误是只给旧数据加 tag range,例如:sh.addTagRange("db.col", { createdAt: MinKey }, { createdAt: ISODate("2023-01-01") }, "cold")。这会导致新写入的数据(createdAt > 2023-01-01)落在默认 chunk 分配路径上,很可能集中到某一个 shard,打破冷热边界。
正确做法是用两段互斥 range 覆盖全部键空间:
sh.addTagRange("db.col", { createdAt: MinKey }, { createdAt: ISODate("2023-01-01") }, "cold")sh.addTagRange("db.col", { createdAt: ISODate("2023-01-01") }, { createdAt: MaxKey }, "hot")
注意:
- MinKey / MaxKey 是 MongoDB 内置常量,不是字符串;
- 两个 range 必须首尾相接,中间不留空隙,也不重叠;
- shard key 必须是 createdAt 或其前缀,否则 range 不生效。
执行完 sh.addShardTag() 和 sh.addTagRange() 后,数据不会秒级挪到目标 shard。MongoDB 靠 balancer 周期性检查 chunk 分布,发现不合规时才触发 moveChunk。这意味着:
sh.status() 里 chunk 仍显示在原 shard 上,属正常现象sh.setBalancerState(false)),迁移永远不发生sh.startBalancer()(若已关)+ 等待几分钟,再查 sh.status()
验证是否生效,别只看配置,要看实际 chunk 分布:db.getSiblingDB("config").chunks.find({ "min.createdAt": { $lt: ISODate("2023-01-01") } }).count(),再比对该 count 是否与目标 cold shard 的 chunk 数一致。
用时间字段(如 createdAt)做 shard key + 范围分片,容易产生写热点:所有新数据都落到同一个 chunk 的末尾,该 chunk 所在 shard 成为瓶颈。这不是 tag 的问题,而是分片策略缺陷。
缓解方式有限且需权衡:
{ createdAt: "hashed" },但会失去按时间范围查询的能力{ region: 1, createdAt: 1 },把地域维度前置,分散写入压力sh.splitAt() 主动切好 chunk,避免初期全挤在一个 shard真正难处理的点在于:tag-aware sharding 解决的是“数据在哪”,不是“数据怎么写”。写入性能瓶颈得回到 shard key 设计本身,标签只是后续路由的过滤器。
逐浪 · 第十一篇: Vibe Coding 下的效率定义与规范建设
硅谷大佬都在聊的 Loop Engineering:到底在卷什么?
BoxAgnts 工具系统(6):多 Provider 适配与 Agent 查询循环
同行月球逃脱船员舱隐藏物资位置一览
AI Coding框架:打好TDD和SDD这两拳
从 PDD DDD SDD 到 TDD:我是如何用一套 Agent 工程方法论推进 My-Notion 的