天天看點

MongoDB Sharding 請勿複用已删除的 namespace

SERVER-17397: Dropping a Database or Collection in a Sharded Cluster may not fully succeed

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

MongoDB Sharding 請勿複用已删除的 namespace

集合分片原理

MongoDB sharding 分片原理參考

MongoDB Sharded cluster架構原理

總的來說,當使用者對集合執行開啟分片之後,集合分片的中繼資料會儲存在 config server 的 config 集合裡

  • config.collections

    記錄集合分片的中繼資料,根據哪個 shardKey 分片,集合是否已經被删除等中繼資料
  • config.chunks

    ,記錄各個 chunk(shardKey的某一段範圍)對應的 shard 資訊,用于路由請求
  • 各個 shard 裡存儲集合實際的資料

删除分片集合流程

  1. 删除所有 shard 裡的對應的資料
  2. 删除 config.chunks 這個集合相關的chunk資訊
  3. 修改 config.collections,标記集合已經删除

注:3.2+都是按上述流程操作,删除 Database 過程類似,還需要再額外操作 config.databases 集合,但本質上存在的問題類似

上述動作需要操作 config server 以及 所有的 shard,如果中間有步驟失敗(一些很老的版本,并不是按照上述步驟執行,而且執行過程中可能沒有嚴格檢查傳回的錯誤碼,即使傳回成功實際上内部可能執行失敗),最終導緻集合的部分資料仍然殘留,沒有完全清理幹淨。

如果這個集合名字重新被使用,再次調用 shardCollection 産生新的分片中繼資料,可能導緻

  1. 在 shard 上的一些殘留資料可能被讀取到,而這些資料實際上應該被删除了
  2. mongos 沒有成功更新路由資訊,最終可能出現多個 mongos 看到的資料視圖也不一緻,有的 mongos 能讀到資料,有的讀不到(通過 `flushRouterConfig 指令可以強制重新整理路由資訊可解決)

解決方案

MongoDB sharding 删除集合/資料庫涉及到多個節點進行操作,這些動作無法做到原子性,可能導緻一個集合最終處于某種中間狀态;複用該集合可能導緻一寫資料一緻性問題。

  1. 使用 MongoDB 3.2+ 以上版本,大部分case,隻要沒有異常,删除集合動作都能正常完成的,複用集合名字問題一般問題也不大,但無法完全避免問題。
  2. 建議 Sharding 環境下,namespace 名字一旦被删除,不要再次複用
  3. 在需要複用 Namespace 的情況下,如果要確定不會有資料問題,每次可以按 drop collection workaround 確定相關資料被正确清理,并且路由資訊被更新。