本文是對mongodb 世界大會上『life of a sharded write』主題分享的總結,這個分享很有意思,主要内容是介紹 mongodb sharded cluster 裡寫操作的路由政策,以及config server變為複制集後面臨的一些挑戰。

在 sharded cluster 裡,使用者可以将集合的資料以 chunk 為機關分散存儲到多個 shard 上。如下圖所示,集合的資料按照 shardkey 被切分為 [minkey, -200), [-200, -100), [-100, 0), [0, 100), [100, 200), [200, maxkey)等chunk 範圍,并存儲在 shard0, shard1, shard2等3個 shard 上。
config server 上對應的路由表(route table)類似下圖
當寫入新文檔時,mongos 從config server 上擷取集合的路由表本地,如寫入{shardkey: 150}的文檔,則請求被路由到shard1上寫入。
mongos 從 config server 上擷取到路由表後,會緩存在本地記憶體,避免每次寫入/查詢都去 config server 上取表。而在 sharded cluster 裡,mongos 會自動在 shard 之間遷移 chunk 以均衡負載(使用者也可以發送 movechunk 指令來手動遷移),那麼一旦 chunk 發生遷移後,mongos 本地緩存的路由表就會失效,進而請求被路由到錯誤的 shard,這個問題該如何解決?
mongodb 的做法是給路由表增加版本資訊,比如最初的路由表包含6個 chunk,路由資訊的版本為 v6(各個條目版本的最大值)。
當[0, 100)從 shard0遷到 shard1之後,條目的版本增加為路由表目前版本再加1, 即變為7,這個資訊會記錄在 shard 本地,同時也會更新到 config server 裡。
說明:上述的版本隻為介紹原理之用,實際上在3.2的實作裡版本是一個(majorversion, minorversion)的二進制組),當chunk 發生 split 之後,split 之後的所有 chunk minor version增加,當 chunk 在 shard 之間發生遷移時,遷移的 chunk 在目标上增加 major version,并且在遷移源上選擇一個 chunk 增加 其major version,這樣確定不論是通路到源還是目标,mongos 看到的版本都增加了。
3.2版本裡,config server 從以前的多個鏡像節點換成了複制集,換成複制集後,由于複制自身的特性,sharded cluster 在實作上也面臨一些挑戰。
挑戰2:複制集備節點的資料比主節點落後,如果僅從主節點上讀,讀能力不能擴充,如果從備節點上讀,可能讀到的資料不是最新的,對 mongos 的影響是『可能讀到過期的路由表,在上述例子中,mongos 發現自己的路由表版本低了,于是去 config server 拉取最新的路由表,而如果這時請求到未更新的備節點上,可能并不能成功的更新路由表』。
而一旦資料成功寫入到大多數成員,這樣的資料就肯定不會發生 rollback,mongos 在從 config server 讀取資料時,會指定 readconcern 為 majority 級别,確定讀取到的路由資訊肯定不會被復原。
應對第二個問題,mongodb 在majority 級别的基礎上,增加了 afteroptime 的參數,這個參數目前隻在 sharded cluster 内部使用。這個參數的意思是『被請求節點的最新oplog時間戳必須大于 afteroptime 指定的時間戳』。
mongos 帶着路由表版本資訊請求 某個 shard,shard發現自己的版本比 mongos 新(發生過 chunk 遷移),此時shard 除了告訴 mongos 自己應該去更新路由表,還會把自己遷移 chunk 後更新 config server 時的 optime告訴mongos,mongos 請求 config server 時,指定 readconcern 級别為 majority,并指定 afteroptime 參數,以確定不會從備節點讀到過期的路由表。
<a href="http://77g6ez.com1.z0.glb.clouddn.com/11-10-11-50_randolph%20tan_life%20of%20a%20sharded%20write.pptx" target="_blank">life of a sharded write</a>
<a href="http://experience.mongodb.com/" target="_blank">mongodb world 2016 ppt</a>
<a href="https://docs.mongodb.com/manual/core/replica-set-rollbacks/" target="_blank">replica-set-rollbacks</a>
<a href="https://docs.mongodb.com/manual/reference/read-concern/" target="_blank">mongodb readconcern</a>