是 MongoDB 裡老大難的問題,庫或集合删除操作如果沒有完全執行成功,再建立相同名字的集合,可能導緻讀到老版本資料的問題。

集合分片原理
MongoDB sharding 分片原理參考
MongoDB Sharded cluster架構原理總的來說,當使用者對集合執行開啟分片之後,集合分片的中繼資料會儲存在 config server 的 config 集合裡
-
記錄集合分片的中繼資料,根據哪個 shardKey 分片,集合是否已經被删除等中繼資料config.collections
-
,記錄各個 chunk(shardKey的某一段範圍)對應的 shard 資訊,用于路由請求config.chunks
- 各個 shard 裡存儲集合實際的資料
删除分片集合流程
- 删除所有 shard 裡的對應的資料
- 删除 config.chunks 這個集合相關的chunk資訊
- 修改 config.collections,标記集合已經删除
注:3.2+都是按上述流程操作,删除 Database 過程類似,還需要再額外操作 config.databases 集合,但本質上存在的問題類似
上述動作需要操作 config server 以及 所有的 shard,如果中間有步驟失敗(一些很老的版本,并不是按照上述步驟執行,而且執行過程中可能沒有嚴格檢查傳回的錯誤碼,即使傳回成功實際上内部可能執行失敗),最終導緻集合的部分資料仍然殘留,沒有完全清理幹淨。
如果這個集合名字重新被使用,再次調用 shardCollection 産生新的分片中繼資料,可能導緻
- 在 shard 上的一些殘留資料可能被讀取到,而這些資料實際上應該被删除了
- mongos 沒有成功更新路由資訊,最終可能出現多個 mongos 看到的資料視圖也不一緻,有的 mongos 能讀到資料,有的讀不到(通過 `flushRouterConfig 指令可以強制重新整理路由資訊可解決)
解決方案
MongoDB sharding 删除集合/資料庫涉及到多個節點進行操作,這些動作無法做到原子性,可能導緻一個集合最終處于某種中間狀态;複用該集合可能導緻一寫資料一緻性問題。
- 使用 MongoDB 3.2+ 以上版本,大部分case,隻要沒有異常,删除集合動作都能正常完成的,複用集合名字問題一般問題也不大,但無法完全避免問題。
- 建議 Sharding 環境下,namespace 名字一旦被删除,不要再次複用
- 在需要複用 Namespace 的情況下,如果要確定不會有資料問題,每次可以按 drop collection workaround 確定相關資料被正确清理,并且路由資訊被更新。