轉載自:Mongodb movePrimary_大數據_運維開發網_運維開發技術經驗分享 (qedev.com)
move Primary
首先根據上一篇來短暫的回憶一下平衡器。Mongodb會開啓一個線程balance專門負責數據的平衡工作,查看系統中所有的shard,發現不平衡的情況就選擇將其中shard服務器的chunk遷移到其它服務器,讓整個系統達到平衡
平衡策略
- shard的數據大小超過了shard配置的數據大小,從中選擇chunk遷移到別處
- 找到shard中有違法tag規則的chunk,將這些chunk遷移到符合 tag規範的shard中
- 找出tag中各個shard中chunk數,如果chunk數的差值大於閾值,從較多的shard移動chunk到較少的shard中
平衡器工作內容
- 保持不同分片之間的數據平衡
- 儘量最小化不同分片之間交互的數據塊次數
主分片
在mongodb的分片集羣中,創建的第一個分片會被默認爲主分片,如果片鍵選擇不合理,會導致集羣不均衡,解決方法想到的有:
- 使用moveChunk將數據移動到某個分片
- 換片鍵,當然必須是沒有創建的集合
- 如果置換片鍵之後依舊失敗。比如寫入量太大,或者一下子import太多的數據。分享一個粗暴的方式,換主分片,因爲數據都會大量的寫入主分片,再開始移動。
在採用移動主分片之前,,我懷疑或許是我的片鍵設置的有問題,但是其實在數據量較小的情況下,一切運作良好,好吧,我開始利用其它的片鍵:
1.使用_id的哈希片鍵,且不論索引會佔多大的空間,結果是數據依舊無法平衡
2.使用time,儘管升序片鍵不被推薦,但是可以採用半人工干預:開始使用了addShardTag,然後addTagRange,給平衡器指定特定時間範圍數據位於某個shard上面,不過似乎沒有起作用,其實分析一下,在原來可以均衡的片鍵下都沒有成功,就平衡策略的第二種情形也是無法平衡的。
所以開始利用movePrimary力求數據全部寫到這個主分片中,以降低原來主分片中磁盤的壓力。其使用方法:
db.runCommand({"movePrimary":"test","to":"shard_1"})
上述命令將主分片移動到shard_1中。在移動的過程中或許會耗費非常多的時間,原因在於:
- 如果原來的主分片中存在大量的未分片的集合,在movePrimary中會將這部分集合全部移動過來,並創建索引。簡直驚人!
- 創建索引的方式採用的是前臺創建形式。所謂前臺創建索引,所有的集合都將被鎖住,包括讀寫,直到所有的索引都被創建完畢,是整個db的鎖,所以,在移動的過程中不能有任何其他的讀寫操作。索引創建過程默認是前臺方式,我們順便了解下後臺創建方式。後臺創建過程不會影響其他的操作,但是其代價是速度很慢。特別的如果索引的大小大於可用的RAM,那麼創建的過程將會非常漫長。
-
如果在移動的過程中沒有禁止其他的操作,你進入一個未分片的集合,那麼movePrimary也不會阻止對它的 讀寫,但是這個過程誰都無法保證最後的結果,行爲未知。所以,在movePrimary之前,進行了一些操作:
-
檢查所有的集合是否已經創建索引
- 檢查集合是否已經分片,就此還寫了個腳本
var getStats=function(name){ var col_stats=db.getCollection(name).stats(); if(col_stats.sharded) { db.shard_status.insert({"name":name,"shard":true}) } else { db.shard_status.insert({"name":name,"shard":false}) } } var nameArr=db.getCollectionNames(); var i=0; for(;i<nameArr.length;i++){ getStats(nameArr[i]); }
- 查看未分片的集合,對於一些小集合,我還是給予了分片, 避免db被鎖住太長時間,查看CurrentOp,如果有createIndex等操作,請等待
- 刪除shard_status,開始執行movePrimary命令,等待返回
- 在每個mongos使用
db.runCommand("flushRouterConfig")
*如果在使用movePrimary命令移動未分片集合,必須重新啓動所有的mongos,或者使用flushRouterConfig,這個命令必須執行在對數據庫的讀寫之前。它的本質告訴mongos這些集合位於新的分片中,更新mongos中元數據的配置。其實對於我們的操作,已經讓所有的集合使用了分片,這個過程可以不做。
出現的問題
- movePrimary之後,目標分片無法顯示對應的集合,發現在當前的主分片中這些集合的索引還沒有創建,因爲沒有創建索引完畢,就開始向裏面寫入數據
- 報錯
-
{ "ok" : 0, "errmsg" : "clone failed" }
進入到分片中的mongod,發現分片中出現相同的名字,這個過程發生在我試圖切換回原來的主分片。官方也對此給出了結論,指出如果原來的主分片中存在相同的集合名稱將會發生錯誤
-
性能影響
如果原來的集合已經不平衡,切換主分片,集合依舊不平衡,數據分在某個分片中,將會影響查詢的效率
如果從一臺較好的服務器切換到一個配置交差的服務器,其IO與平衡器的運行將會是一個問題,IO的增加,寫入會降低,查詢超時。只有那種主分片快滿了,沒有其他的當時下,短暫緩解主分片數據。