reshardcollection不能边跑边治事务堆积,因其非在线操作,会阻塞写入约2秒、禁用元数据命令、依赖长事务完成,且不可暂停或回退;必须停写、腾空间、确保查询带分片键。

直接结论:热点片键引发的事务堆积,本质是写入集中导致单分片 I/O 和锁竞争激增,5.0 中不能靠“改片键”实时缓解,必须用 reshardCollection 重建分布,但操作前必须停写、腾空间、禁广播查询。
为什么 reshardCollection 不能边跑边治事务堆积
重新分片不是在线索引重建,它会启动全量数据迁移和重哈希。期间:
• 所有写入在两秒窗口内被阻塞(writeConcernMajorityJournalDefault=true 强制要求);
• collMod、createIndexes、drop 等元数据命令全部失败,事务若依赖这些操作会卡住;
• 如果应用层有长事务或未提交的跨分片事务,resharding 会等待其完成,进一步拖慢进度。
执行 reshardCollection 前必须确认的三件事
- 集群写入可接受两秒级暂停 —— 不是“尽量避开高峰”,而是必须确保无长事务正在运行(查
db.currentOp({ "secs_running": { "$gt": 30 } })) - 每个目标分片剩余空间 ≥
(collection_size + index_size) * 2 / shard_count—— 少一点都会导致迁移中途失败并回滚,已写入的数据不会自动清理 - 所有查询必须带分片键 —— 否则
mongos会广播到所有分片,而 resharding 期间不支持explain("executionStats")类诊断命令,你无法快速定位哪条查询在拖慢均衡器
替代方案:当 reshardCollection 不可行时怎么压热点
如果业务完全无法停写,或磁盘已满,只能临时缓解:
- 对当前单调片键(如
order_id)加后缀做复合键,例如{ order_id: 1, user_hash: 1 },再建唯一索引;但这只是“优化”,不改变已有数据分布,新写入才受益 - 启用哈希分片(
{ user_id: "hashed" }),但注意:已有集合不能直接切换,必须导出→新建哈希分片集合→导入→切流量 - 手动拆分热点 chunk:
sh.splitAt("db.coll", { user_id: ObjectId("...") }),但仅限 chunk 未达 jumbo(即仍可分裂);若已是 jumbo,则此命令直接报错cannot split jumbo chunk
真正棘手的点不在命令怎么敲,而在于:resharding 一旦开始,就无法暂停或回退;失败后残留的中间状态(比如部分分片上多出的临时命名空间 system.resharding.*)必须人工清理,且可能影响后续分片操作。别低估那两秒写入阻塞——它往往暴露了应用层没处理好的事务超时逻辑。











