本文介紹如何查看增加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命令擷取分區表的分布資訊並重點關注資料量的均勻情況。樣本如下:mongos> db.xxx.getShardDistribution() Shard d-xxx at xxx data : 379.26MiB docs : 8277367 chunks : 1 estimated data per chunk : 379.26MiB estimated docs per chunk : 8277367 Shard d-xxx at xxx data : 379.11MiB docs : 8272852 chunks : 1 estimated data per chunk : 379.11MiB estimated docs per chunk : 8272852 Shard d-xxx at xxx data : 379.18MiB docs : 8275108 chunks : 1 estimated data per chunk : 379.18MiB estimated docs per chunk : 8275108 Totals data : 1.11GiB docs : 24825327 chunks : 3 Shard d-xxx contains 33.34% data, 33.34% docs in cluster, avg obj size on shard : 48B Shard d-xxx contains 33.32% data, 33.32% docs in cluster, avg obj size on shard : 48B Shard d-xxx contains 33.33% data, 33.33% docs in cluster, avg obj size on shard : 48B您也可以使用以下的命令擷取更加詳細的分布資訊(包括文檔數及總大小,孤立文檔數及總大小):
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)返回樣本如下:
mongos> db.getSiblingDB("config").changelog.aggregate(pipeline) { "_id" : { "date" : "2024-09-24" }, "chunks_moved" : 91, "docs_moved" : NumberLong(33071040), "bytes_moved" : NumberLong("11532786734") } { "_id" : { "date" : "2024-09-23" }, "chunks_moved" : 294, "docs_moved" : NumberLong(109806635), "bytes_moved" : NumberLong("38294757573") } { "_id" : { "date" : "2024-09-22" }, "chunks_moved" : 737, "docs_moved" : NumberLong(266800041), "bytes_moved" : NumberLong("93047288531") } { "_id" : { "date" : "2024-09-21" }, "chunks_moved" : 1448, "docs_moved" : NumberLong(525308393), "bytes_moved" : NumberLong("183117965820") } { "_id" : { "date" : "2024-09-20" }, "chunks_moved" : 1459, "docs_moved" : NumberLong(530020503), "bytes_moved" : NumberLong("184390749022") } { "_id" : { "date" : "2024-09-19" }, "chunks_moved" : 1478, "docs_moved" : NumberLong(557833705), "bytes_moved" : NumberLong("186910196651") } { "_id" : { "date" : "2024-09-18" }, "chunks_moved" : 1360, "docs_moved" : NumberLong(508484825), "bytes_moved" : NumberLong("173486932689") }通過該返回結果可以看到
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()命令的返回資訊樣本如下所示。
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Balancer lock taken at Wed Sep 30 2020 02:03:11 GMT+0800 (CST) by ConfigServer:Balancer
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "report", "primary" : "d-0xixxx", "partitioned" : true }
report.report
shard key: { "GsId" : "hashed" }
unique: false
balancing: true
chunks:
d-0xixxx 9
d-0xixxx 2133
d-0xixxx 2152
d-0xixxx 2116
d-0xixxx 2133
too many chunks to print, use verbose if you want to force print出現上述問題可能是因為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)等因素導致。處理前,建議先區分Jumbo Chunk屬於以下哪一類:
可拆分型:Chunk中包含多個分區索引值(例如此前資料已刪除變小,或jumbo標誌為歷史殘留)。此類Chunk執行clearJumboFlag命令清除jumbo標誌後,均衡器(Balancer)即可自動對其進行拆分和遷移。
不可拆分型:Chunk中絕大部分資料屬於同一個分區索引值(熱點Key),資料量超過chunkSize且無法拆分。此類Chunk需要通過下述方法處理。
您可以根據業務情況嘗試使用以下方法解決:
方法一:最佳化分區鍵設計(根治熱點Key問題)
如果您的MongoDB資料庫的大版本為4.4及以上,可以通過refineCollectionShardKey命令為原分區鍵添加尾碼欄位,使分區鍵的基數更大,添加尾碼後原本不可拆分的Jumbo Chunk將變為可拆分。
如果您的MongoDB資料庫的大版本為5.0及以上,還可以通過reshardCollection命令將指定分區表按照新的分區鍵重新分區。更多介紹,請參見Reshard a Collection。
方法二:遷移Jumbo Chunk(適用於4.4及以上版本,例如刪除分區節點時Jumbo Chunk無法遷出導致流程被阻塞的情境)
方式1(推薦):先執行clearJumboFlag命令清除該Chunk的jumbo標誌,再將Balancer的
attemptToBalanceJumboChunks設定為true,由Balancer自動遷移該Chunk。此方式在資料拷貝期間不阻塞業務寫入,僅遷移收尾階段會短暫阻塞寫入。重要若該Chunk上寫入量較大,遷移可能因增量緩衝超限而失敗,且失敗後該Chunk會被重新標記為jumbo,需再次清除標誌後重試。
遷移成功後請立即將
attemptToBalanceJumboChunks恢複為false。對於6.0及以上版本,由於Balancer按分區間資料量差異進行均衡,超大Chunk遷移到任何分區後都會使該分區成為資料量差異點,若不及時恢複設定,Balancer會將該Chunk在分區間反覆遷移,造成持續的資料轉送和孤兒文檔清理開銷。恢複設定後該Chunk會在下一次普通遷移嘗試失敗時被重新標記為jumbo並不再被搬動,屬於預期現象,無需再次清除標誌。
方式2:手動執行
moveChunk命令並附加forceJumbo: true選項。此方式在整個資料拷貝期間會阻塞該集合在源分區上的所有寫入,Chunk較大時可能持續數小時,建議僅在業務低峰期或可暫停寫入時使用,並建議在阿里雲支援人員工程師的協助下操作。
方法三:刪除資料。如果您確認部分業務資料可刪除,則可以刪除對應Jumbo Chunk中的資料以減小其大小。注意:Chunk變小後jumbo標誌不會自動清除,還需要執行
clearJumboFlag命令(或等待該Chunk被成功拆分)後,Balancer才會將其遷出。方法四:調大chunkSize參數。您可以調大
chunkSize參數來改變Jumbo Chunk的判定閾值。此方法僅在Chunk實際大小略超當前閾值時有效,對熱點Key形成的超大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")提交工單聯絡支援人員對相關核心參數進行調整。