本文介紹如何查看增加Shard節點或刪除Shard節點的任務進度,以及檢查是否有異常阻塞任務進程的方法。
背景資訊
當您對分區叢集執行個體執行增加Shard節點或刪除Shard節點操作後,可能會出現任務提交後很長時間都沒完成的情況,以下內容將指導您如何檢查上述問題。
在進行操作前,您需要瞭解以下基本知識:
瞭解MongoDB複本集執行個體和分區叢集執行個體的部署模式以及兩種架構之間的區別。更多介紹,請參見複本集架構和分區叢集架構。
瞭解均衡器Balancer的基本工作原理。更多介紹,請參見管理MongoDB均衡器Balancer。
瞭解MongoDB資料的劃分方式,MongoDB的資料是根據Chunk(塊)進行劃分的。
瞭解MongoDB分區叢集執行個體中常見的營運命令,例如
sh.status()等。瞭解mongo shell、mongosh或其他視覺化檢視的基礎使用方式。
檢查任務進程
步驟一:檢查Balancer是否開啟
在增加或刪除分區任務中,Chunk的遷移是依賴Balancer完成的。如果未開啟Balancer則會導致如下情況:
新增Shard節點:Chunk資料無法遷移到新的Shard節點上,同時也無法承載業務流量。
刪除Shard節點:待刪除Shard節點上的Chunk資料無法遷移,導致刪除Shard節點的任務被阻塞。
因此,您需要開啟Balancer來保障Chunk資料的正常遷移。開啟Balancer的方法,請參見管理MongoDB均衡器Balancer。
確認Balancer是否開啟有如下兩種方法:
方法一:
sh.status()命令Balancer已開啟的狀態下,返回樣本如下。
... autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: yes Balancer active window is set between 08:30 and 11:30 server local time ...如果顯示
“Currently enabled: no”,則表示Balancer未開啟。方法二:
sh.getBalancerState()命令如果返回
true,則表示已開啟Balancer。如果返回
false,則表示未開啟Balancer。
步驟二:檢查Balancer視窗期是否過小
Balancer控制了Chunk資料移轉的速度,Balancer僅會在視窗期時間段內遷移Chunk資料,若當前視窗期未遷移完成,會在下個視窗期繼續遷移,直至遷移完成。當視窗期過小時,可能會拖慢增加Shard節點或刪除Shard節點任務流的整體進度。調整Balancer視窗期的方法,請參見管理MongoDB均衡器Balancer。
您可以通過如下兩種方法檢查Balancer的視窗期:
方法一:
sh.status()命令返回樣本如下,可以瞭解到Balancer的視窗期為當地時間的08:30至11:30,共計3個小時。
... autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: yes Balancer active window is set between 08:30 and 11:30 server local time ...方法二:
sh.getBalancerWindow()命令返回樣本如下,當執行個體中的分區集合較多時,採用此方法能夠更直觀地顯示視窗期時間。
{ "start" : "08:30", "stop" : "11:30" }
步驟三:擷取預估任務進度的必要資訊
MongoDB 6.0之前版本操作方法
以下內容適用版本如下:
MongoDB 6.0之前版本執行個體.
核心小版本為7.0.1(基準版本為6.0.3)之前的MongoDB 6.0執行個體。如何查看核心小版本,請參見MongoDB小版本說明。
評估任務進度前,您需要擷取Balancer的運行結果(成功和失敗數量的統計)以及待遷移分區表的Chunk資訊。
您可以通過如下兩種方法擷取Balancer的運行結果和待遷移分區表Chunk資訊:
方法一:通過
sh.status()命令的輸出結果擷取sh.status()命令的輸出結果僅需要關注兩部分資訊,第一部分為最近時間Balancer啟動並執行結果,樣本如下。... balancer: Collections with active migrations: <db>.<collection> started at Wed Sep 27 2023 10:25:21 GMT+0800 (CST) Failed balancer rounds in last 5 attempts: 0 Migration Results for the last 24 hours: 300 : Success databases: ...第二部分為待遷移的分區表的Chunk資訊,樣本如下。
... databases: ... { "_id" : "<db>", "primary" : "d-xxxxxxxxxxxxxxx3", "partitioned" : true, "version" : { "uuid" : UUID("3409a337-c370-4425-ad72-8b8c6b0abd52"), "lastMod" : 1 } } <db>.<collection> shard key: { "<shard_key>" : "hashed" } unique: false balancing: true chunks: d-xxxxxxxxxxxxxxx1 13630 d-xxxxxxxxxxxxxxx2 13629 d-xxxxxxxxxxxxxxx3 13652 d-xxxxxxxxxxxxxxx4 13630 d-xxxxxxxxxxxxxxx5 3719 too many chunks to print, use verbose if you want to force print ...以上樣本中的“d-xxxxxxxxxxxxxxx5”即為新增的Shard節點。您也可以在分區表所在的庫執行
getShardDistribution命令來擷取Chunk資料的分布資訊,樣本如下。use <db> db.<collection>.getShardDistribution()方法二:直接讀取config庫中的相關資訊
查看Chunks統計,按分區彙總,樣本如下。
db.getSiblingDB("config").chunks.aggregate([{$group: {_id: "$shard", count: {$sum: 1}}}])查看指定分區上的Chunks,按namespace彙總,樣本如下。
db.getSiblingDB("config").chunks.aggregate([{$match: {shard: "d-xxxxxxxxxxxxxx"}},{$group: {_id: "$ns", count: {$sum: 1}}}])查看過去1天內成功遷移到指定Shard節點的Chunk數量,樣本如下。
// details.to指定chunk遷移的目標shard // time欄位用ISODate指定時間範圍 db.getSiblingDB("config").changelog.find({"what" : "moveChunk.commit", "details.to" : "d-xxxxxxxxxxxxx","time" : {"$gte": ISODate("2023-09-26T00:00:00")}}).count()
MongoDB 6.0之後版本操作方法
以下內容適用版本如下:
MongoDB 6.0之後版本執行個體.
核心小版本為7.0.1(基準版本為6.0.3)及以後的MongoDB 6.0執行個體。如何查看核心小版本,請參見MongoDB小版本說明。
評估任務進度前,您需要關注各分區上資料量分布情況。您依然可以使用sh.status()的結果作為參考,但是在得到結果後,需要減少對各個分區上Chunks數量不均的關注,轉而關注分區上的資料量分布情況。
擷取分區表的分布資訊以及資料量的均勻情況。
建議您優先通過
getShardDistribution命令擷取分區表的分布資訊並重點關注資料量的均勻情況。樣本如下:
您也可以使用以下的命令擷取更加詳細的分布資訊(包括文檔數及總大小,孤立文檔數及總大小):
db.getSiblingDB("admin").aggregate( [{ $shardedDataDistribution: { } },{ $match: { "ns": "<db>.<collection>" } }] ).pretty()返回樣本如下,您可以看到分區間存在比較明顯的資料不均勻的情況。
{ "ns" : "<db>.<collection>", "shards" : [ { "shardName" : "d-xxxxxxxxxxxxxxx1", "numOrphanedDocs" : 0, "numOwnedDocuments" : 504298920, "ownedSizeBytes" : NumberLong("833101815840"), "orphanedSizeBytes" : 0 }, { "shardName" : "d-xxxxxxxxxxxxxxx2", "numOrphanedDocs" : 0, "numOwnedDocuments" : 250283901, "ownedSizeBytes" : NumberLong("409714745937"), "orphanedSizeBytes" : 0 }, { "shardName" : "d-xxxxxxxxxxxxxxx3", "numOrphanedDocs" : 0, "numOwnedDocuments" : 109098088, "ownedSizeBytes" : NumberLong("178157177704"), "orphanedSizeBytes" : 0 }, { "shardName" : "d-xxxxxxxxxxxxxxx4", "numOrphanedDocs" : 0, "numOwnedDocuments" : 382018055, "ownedSizeBytes" : NumberLong("630329790750"), "orphanedSizeBytes" : 0 } ] }通過該返回結果,您可以擷取到以下資訊:執行個體中有4個Shard節點,分區表
<db>.<collection>的總資料量約為2051303530231位元組(833101815840+409714745937+178157177704+630329790750=2051303530231),摺合約為1910.4 GB。查看過去一天內成功遷移的資料量。
查詢命令如下:
pipeline = [ { '$match': { 'what': 'moveChunk.commit', } }, { '$group': { '_id': { 'date': { '$dateToString': { 'format': '%Y-%m-%d', 'date': '$time'} }, }, 'chunks_moved': { '$sum': 1 }, 'docs_moved': { '$sum': '$details.counts.cloned' }, 'bytes_moved': { '$sum': '$details.counts.clonedBytes' }, } }, { '$sort': { '_id.date': -1} }, ] db.getSiblingDB("config").changelog.aggregate(pipeline)返回樣本如下:

通過該返回結果可以看到
2024-09-21這一天內,移動的資料量為183117965820位元組,摺合約為170.5 GB。
步驟四:預估任務進度及完成時間
MongoDB 6.0之前版本操作方法
以下內容適用版本如下:
MongoDB 6.0之前版本執行個體.
核心小版本為7.0.1(基準版本為6.0.3)之前的MongoDB 6.0執行個體。如何查看核心小版本,請參見MongoDB小版本說明。
擷取分區表已成功遷移的Chunk數量以及當前分區表資料分布情況後,您就可以預估出任務的整體進度和預期完成時間。
假如當前增加Shard節點的情境中,總Chunk數量保持不變,Shard節點數量也保持不變(期間不會有新增或刪除Shard節點的任務),增加Shard節點的過程中業務負載基本保持固定,且Balancer的參數設定均為預設值。以步驟三的MongoDB 6.0之前版本操作方法中樣本為例,可以得知以下資訊:
Shard節點數量為5。
在Balancer視窗期內,成功遷移的Chunk數量為300個。
分區表
<db>.<collection>的總Chunk數量為58260個(13630+13629+13652+13630+3719=58260)。
因此可以計算出:
達到均衡狀態時,每個分區上的Chunk數量應為11652個(58260÷5=11652)。
按照當前的遷移速度,任務完成還需要26.4天((11652-3719)÷300≈26.4)。
該增加Shard節點任務進度為32%(3719÷11652=32%)。
實際的業務情境中,總Chunk數量還會隨著業務寫入以及Chunk分裂而增加。因此假設條件為理想情況,實際耗時可能會更久。
MongoDB 6.0之後版本操作方法
以下內容適用版本如下:
MongoDB 6.0之後版本執行個體.
核心小版本為7.0.1(基準版本為6.0.3)及以後的MongoDB 6.0執行個體。如何查看核心小版本,請參見MongoDB小版本說明。
假如分區叢集執行個體中只有一個表需要均衡。以步驟三的MongoDB 6.0以後版本操作方法中樣本為例,可以得知以下資訊:
Shard節點數量為4。
2024-09-21一天內移動的資料量約為170.5GB(183117965820位元組)。分區表
<db>.<collection>的總資料量約為1910.4GB(833101815840+409714745937+178157177704+630329790750=2051303530231位元組)。
因此可以計算出:
達到均衡狀態時,每個Shard上的資料量應大致為477.6GB(512825882557.75位元組)。
各個分區上為了達到均衡狀態,需要移動的總資料量為875559682949位元組,摺合815.4GB。其中:
Shard1需要遷移的資料量為320275933282.25位元組(833101815840-512825882557.75)。
Shard2需要遷移的資料量為103111136620.75位元組(409714745937-512825882557.75)。
Shard3需要遷移的資料量為334668704853.75位元組(178157177704-512825882557.75)。
Shard4需要遷移的資料量為117503908192.25位元組(630329790750-512825882557.75)。
(320275933282.25+103111136620.75+334668704853.75+117503908192.25=875559682949)
按照當前的遷移速度,達到均衡狀態還需要大概4.8天(815.4 GB÷170.5 GB/天≈4.8天)。
步驟五:確認任務流是否阻塞(刪除Shard節點)
如果刪除Shard節點的任務被阻塞,執行sh.status()命令後,返回資訊中沒有看到過去時間段有Chunk資料移轉成功,且待刪除Shard節點上依然殘留部分Chunk資料未遷移走。此時刪除Shard節點任務無法完成,並且會影響您在ApsaraDB for MongoDB控制台對執行個體的其他營運操作。
上述情境中sh.status()命令的返回資訊樣本如下圖所示。

出現上述問題可能是因為Jumbo Chunk阻塞了刪除Shard節點的進程,您可以通過如下的命令確認。
db.getSiblingDB("config").chunks.aggregate([{$match: {shard: "d-xxxxxxxxxxxxxx", jumbo:true}},{$group: {_id: "$ns", count: {$sum: 1}}}])一般情況下,出現Jumbo Chunk是因為設計的分區鍵(Shard Key)不合理(例如存在熱點Key)等因素導致。您可以在業務側嘗試使用以下方法解決:
如果您的MongoDB資料庫的大版本為4.4,則可以通過refineCollectionShardKey命令來最佳化您的Shard key設計,通過為原本分區鍵添加尾碼的方式來使得分區鍵的基數更大,從而解決Jumbo Chunk的問題。
如果您的MongoDB資料庫的大版本為5.0及以上,則可以通過reshardCollection命令來將指定分區表按照新的分區鍵重新分區。更多介紹,請參見Reshard a Collection。
如果您確認部分業務資料可刪除,則可以刪除對應Jumbo Chunk中的資料,該方法可以減少Jumbo Chunk的大小。減少資料後Jumbo Chunk可能成為一個普通的Chunk,然後被均衡器Balancer遷出。
您可以調大
chunkSize參數來使判斷Jumbo Chunk的條件發生變化,建議在阿里雲支援人員工程師的協助下進行操作。
如果以上方法都無法解決您的問題,建議您提交工單聯絡支援人員協助解決。
加速新增或刪除任務進程
如果您希望增刪Shard節點的整體流程可以在更短的時間內完成,您可以嘗試以下加速方法:
將Balancer的視窗期時間調大,Chunk遷移過程帶來的額外負載可能會對業務側產生影響,請您評估風險後再進行調整。調整Balancer視窗期的方法,請參見管理MongoDB均衡器Balancer。
調整分區叢集執行個體的setParameter.chunkMigrationConcurrency參數修改Chunk遷移的並發數,該參數的使用說明,請參見參數調優建議。
在業務低峰期手動執行
moveChunk操作,更多介紹,請參見sh.moveChunk()。樣本如下。sh.moveChunk("<db>.<collection>", {"<shard_key>": <value>}, "d-xxxxxxxxxxxxx") // example: sh.moveChunk("records.people", { zipcode: "53187" }, "shard0019")提交工單聯絡支援人員對相關核心參數進行調整。