標籤:mongodb 塊區間平衡原理
1、平衡簡介
如果存在多個可用的分區,只要塊得數量足夠多,MongoDB就會把資料移轉到其他分區上,這個遷移過程叫做平衡(balancing),由叫做平衡器(balancer)的進程負責執行。
2、平衡工作流程
平衡器會把資料區塊從一個分區挪到另外一個分區上,其優點在於自動化,即你無需擔心如何保持資料在分區間的均勻分布,這項工作已經由平衡器替你搞定,不過這也是它的缺點,因為自動意味著如果你不喜歡塔做負載平衡的方式,那隻能算你不走運,如果不想讓某個塊存在於分區3上,你可以手動移動到分區2上,但是平衡器很可能把它再挪回分區3,你只能選擇要麼對集合重新分區(re-shard),要麼關閉平衡化。
在此之前平衡器的演算法還不是很智能,它每Apsara Infrastructure Management Framework於分區整體大小來移動塊,在不久的將來它將變得更加先進。
平衡器的目標不僅是要保持資料均勻分布,還要最小化被移動的資料量,因此觸發平衡器需要很多條件,要觸發一輪平衡,一個分區必須比塊最小的分區多出至少9個塊,到那時候,塊就會被遷移出擁擠的分區,直到與其他分區平衡為止。
平衡器並不非常激進的原因在於MongoDB希望能夠避免將相同資料來回移動,如果平衡器要平衡掉沒一點微小的區別,那很可能會不停地浪費資源:分區1比分區2多兩個塊時,它就發送一個塊給分區2,接著一些寫操作落到分區2上,使得分區2又比分區1多出兩個塊,結果同一塊資料又被折騰回去,通過等待更嚴重的不平衡發生,MongoDB能夠最小化無意義的資料轉送,要知道差9個塊其實也不是那麼不平衡,因為這還不到2GB資料呢?
說明:
如果如所示,每一點輕微的不平衡都被修正,則最終必然導致大量不必要的資料移動。
3、技巧
大家都希望通過看到資料移動來向自己證明分區可以工作,這產生了一個問題:觸發一輪平衡所需的資料量遠遠比大多數人想象的大。
比如說正在嘗試分區,於是寫了一個命令列指令碼來插入50萬份文檔到分區集合中:
for(i=0;i<500000;i++){db.foo.insert({"_id":i,"x":1,"y:2"});}等插入完成,我應該能看見一些資料飛來飛去了,對不對?錯,如果我看一眼資料庫狀態,就會發生還差得遠呢?這些資料大致約40MB,這不夠一個塊,甚至不夠一個塊的1/4,前面講到了一個塊預設是200MB,真要想看到資料移動話,需要插入2GB資料,也就是2500萬份這樣的文檔,或者說現在已插入資料的50倍。
開始使用分區時,人們希望看到資料到處移動,這是人的本性使然,儘管如此,在生產系統中你不會希望發生太多遷移,因為這種操作代價極其高昂,因此一方面我們希望看到遷移實際發生,而另外一方面事實又是如果它不是看上去慢慢得讓人煩躁就不可能工作的很好,對於這個矛盾,MongoDB需要實現兩個技巧,讓分區更善解人意,同時又不對生產希望造成破性的影響。
第一次啟動mongos時,可以聲明--chunkSize N參數,其中N就是你想要的塊大小,單位是MB,如果只是想試試分區,可以設定--chunkSize 1,這樣只要插入幾MB的資料就能看到遷移發生了。
即使是部署一個真正的應用程式,要達到2GB看起也遙遙無期,所以對於前十幾個塊,MongoDB會特意自動降低塊大小,從200MB降至64MB,而這就是為了更好地照顧一下使用者的感受,一旦資料區塊多起來,它會自動把塊大小遞增回200MB。
塊大小可以通過啟動時指定--chunkSize N參數或者修改config.settings集合并整體性重啟來改變,儘管如此,除非是為了好玩試試1MB的塊大小,否則別啟動改動其大小。
第五部分 架構篇 第十八章 MongoDB Sharding 架構(平衡)