MongoDB Sharding 請勿復用已刪除的 namespace

  • 2019 年 10 月 4 日
  • 筆記

SERVER-17397: Dropping a Database orCollection in a Sharded Cluster may not fully succeed 是MongoDB 里老大難的問題,庫或集合刪除操作如果沒有完全執行成功,再新建相同名字的集合,可能導致讀到老版本數據的問題。

集合分片原理

MongoDB sharding 分片原理參考 MongoDB Sharded cluster架構原理。

總的來說,當用戶對集合執行開啟分片之後,集合分片的元數據會保存在 configserver 的 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 確保相關數據被正確清理,並且路由資訊被更新。

MongoDB中文社區(微信公眾號:mongoing-mongoing)

作者:張友東

阿里雲高級技術專家 MongoDB中文社區聯席主席

主要關注分散式存儲與資料庫等技術領域,先後參與淘寶分散式文件系統TFS、阿里雲資料庫(PolarDB、MySQL、MongoDB、Redis)等項目的開發工作,致力於讓開發者用上最好的雲資料庫服務。