通過 delete 或 TTL 索引刪除資料後,物理磁碟空間不會自動釋放,未被複用的空閑空間即磁碟片段。本文介紹三種回收方式:自動回收計劃、控制台手動回收和命令列 compact。
選擇回收方式
在ApsaraDB for MongoDB中,通過 delete 或 TTL 索引刪除資料後,物理磁碟空間不會自動釋放。被刪除資料的空間會標記為空白閑、留待後續寫入複用,未被複用的部分即磁碟片段。片段累積導致磁碟使用率偏高時,需回收片段釋放物理空間。
三種回收方式對比如下:
對比維度 | 方式一:自動回收計劃 | 方式二:控制台手動回收 | 方式三:命令列 compact |
作用節點 | 僅 Hidden 節點 | 僅 Hidden 節點 | Primary節點或 Secondary節點 |
核心版本要求 |
|
| 無 |
每輪可回收空間上限 | 100 GB | 無 | 無 |
業務影響 | 無(可維護視窗執行) | 無(作用於 Hidden) | 有,具體請參見compact 對業務的影響 |
適用情境 | 適用於數量較多的可回收空間較小的集合 | 適用於可回收空間較大的集合 | 量大、精確控制、控制台回收不動 |
drop 整個集合或資料庫會立即釋放其佔用的物理空間,但這屬於刪除資料操作,僅建議在磁碟緊張或執行個體鎖定時應急使用,不作為常規片段回收手段。
方式一:設定自動回收計劃
ApsaraDB for MongoDB提供片段回收計劃,由 DAS(資料庫自治服務)在執行個體可維護視窗自動檢測並對 Hidden 節點執行 compact,無需人工幹預,不影響業務。
觸發條件與規則
系統只對同時滿足以下條件的集合自動回收:
集合的(索引空間 + 資料空間)之和大於 1 GB。
片段率大於 20%。
其他規則:
單輪迴收總量上限 100 GB,超出部分在後續輪次繼續回收。
上述閾值為系統內建,使用者不可自訂。
配置入口
登入MongoDB 管理主控台,進入目標執行個體。
在左側導覽列選擇 CloudDBA > 空間分析。
在資料空間列表中,找到片段率列的回收連結並單擊。
在彈出的片段回收計劃對話方塊中,單擊新增計劃並確認。
方式二:控制台手動回收
當集合的可回收空間超過 100 GB時,可使用手動回收。
集合的可回收空間超過100 GB時,回收時間可能超過1小時,請合理安排回收時間。
操作步驟
進入目標執行個體,在左側導覽列選擇 CloudDBA > 空間分析。
在資料空間列表中查看各集合的片段率與可回收空間。
對需要回收的高片段率集合,單擊對應的回收執行。
確認回收成功
回收完成後,重新執行空間分析,查看目的地組合片段率是否下降。請確認查看的節點與實際回收的節點一致(參見常見問題與排障)。
如果用命令列在主節點或從節點執行了 compact,控制台空間分析中的片段率不會變化,這不代表回收未生效。請到监控信息頁面切換到實際操作的節點確認效果。
方式三:命令列 compact
適用於單集合超過 100 GB、控制台回收無法滿足的情境。
許可權要求
執行 compact 需要帳號有dbAdmin許可權或者hostManager(版本>8.0)許可權。否則執行會報許可權錯誤:
not authorized on <database> to execute command { compact: ... }compact 對業務的影響
讀寫阻塞與效能影響
MongoDB 4.4之前:
compact命令會導致集合所屬的資料庫被鎖定,阻塞該資料庫的讀寫操作。片段過多時,compact命令的執行時間會比較長,此時可能會出現Hidden節點複寫延遲大的風險。建議您在業務低峰期操作,並根據業務寫入情況適當調大Oplog大小,或者升級資料庫大版本至MongoDB 4.4及之後再進行片段回收操作。MongoDB 4.4及之後:
compact命令不再阻塞業務讀寫,但執行過程中可能會影響效能,建議在業務低峰期操作。
節點重搭
MongoDB 3.4全版本、MongoDB 4.0全版本、MongoDB 4.2的早期小版本(小於等於4.0.22版本)、MongoDB 4.4的早期小版本(小於等於5.0.6版本):正在執行
compact命令的節點會進入RECOVERING狀態,如果期間過長,該節點會被執行個體探活組件認定為節點不健康從而觸發相應的重搭操作。查看MongoDB版本與版本資訊介紹,請參見MongoDB小版本說明。上述版本之後的MongoDB執行個體:執行
compact命令的節點將維持在SECONDARY狀態,不會觸發重搭操作。
無論哪個版本,都建議優先在 Hidden 或 Secondary 節點回收,避免影響主庫。回收磁碟片段前,建議對資料庫進行資料備份。
compact 執行耗時
耗時與集合資料量、系統負載等因素相關,無法精確預估。集合越大、片段越多耗時越長,超大集合(數百 GB)可能顯著更久。建議先用 dryRun: true 預估可釋放空間,並在業務低峰執行。
以下資料僅供量級參考:
實測參考(MongoDB 4.4):對約 2.5 GB、50% 片段的集合執行 compact,耗時約 5 秒、返還約 1.9 GB 空間。
compact 命令無效的情境
以下情境可能導致 compact 命令執行無效:
物理集合大小小於 1 MB。
片段率小於 20%。
檔案前 80% 的儲存空間中,空閑儲存空間小於 20%;檔案前 90% 的儲存空間中,空閑儲存空間小於 10%。
更多介紹請參見 block_compact。
複本集執行個體
不建議直連主節點(Primary)執行 compact。compact 會佔用較多 IO/CPU,在主節點執行會影響線上業務。建議對 Secondary 節點執行,再通過主備切換輪流回收各節點。
單節點(StandAlone)執行個體只有一個節點,直接連接該主節點執行 compact 即可。
在 Secondary 節點上串連後執行以下命令:
use <database>
// 回收前:查看資料庫佔用空間,便於回收後對比
db.stats()
// 預演:只估算可釋放空間,不實際回收
db.runCommand({ compact: "<collection>", dryRun: true })
// 實際回收
db.runCommand({ compact: "<collection>" })
// 回收後:再次查看,對比空間是否下降
db.stats()其中 dryRun: true 為預演模式,僅返回 estimatedBytesFreed(預估可釋放位元組數),不實際修改檔案。確認預演結果後再去掉該參數執行實際回收。回收前後分別執行 db.stats() 可對比資料庫佔用空間的變化,確認回收效果。
請確保上一次 compact 執行完成後,再對同一集合開始新的 compact。
分區叢集執行個體
分區叢集只需回收 Shard 組件中對應節點的磁碟片段。Mongos 和 ConfigServer 組件不儲存使用者資料,無需回收。
分區叢集執行個體的唯讀節點不支援compact命令,所以無法回收唯讀節點(ReadOnly節點)的磁碟片段。回收 Secondary 節點片段:執行 runCommandOnShard 時需將讀取喜好設定為 Secondary 節點,不同用戶端文法不同。請根據您使用的用戶端選擇對應的操作方法:
mongosh 2.x
mongosh 2.x 支援在 runCommand 的第二個參數中直接指定讀取偏好:
db.runCommand({runCommandOnShard:"<Shard ID>","command":{compact:"<collection_name>"}},{readPreference: "secondary"})mongosh 1.x
mongosh 1.x 需先通過 setReadPref 設定讀取偏好,再執行命令:
db.getMongo().setReadPref('secondary')
db.runCommand({runCommandOnShard:"<Shard ID>","command":{compact:"<collection_name>"}})Tab 2 本文
mongo shell(舊版)
mongo shell(舊版)需在命令中添加 $queryOptions 指定讀取偏好:
db.runCommand({runCommandOnShard:"<Shard ID>","command":{compact:"<collection_name>"},$queryOptions: {$readPreference: {mode: 'secondary'}}})回收 Primary 節點片段(不推薦):
為降低業務影響,建議您進行主備切換,將Primary節點切換到Secondary節點,再回收新Secondary節點的磁碟片段。主備切換的具體操作,請參考分區叢集執行個體設定主備切換。
db.adminCommand({
runCommandOnShard: "<shardId>",
dbName: "<database>",
command: { compact: "<collection>", force: true }
})
常見問題與排障
執行了回收但看不到效果
請按以下順序自查:
操作的節點與查看結果的節點是否一致(最常見原因):控制台空間分析的回收作用於 Hidden 節點,頁面片段率也預設顯示 Hidden 節點。命令列 compact 作用於您串連的節點。如果在主節點或從節點手動執行 compact,卻在控制台空間分析查看片段率,數字不會變化。正確做法:到监控信息頁面,切換到實際操作的節點查看磁碟空間使用率。
是否為檔案內部片段:compact 只能截斷檔案尾部的連續空閑空間,檔案中間的可重用空間無法回收。若片段主要分布在檔案內部,compact 後空間可能幾乎不變,這是 WiredTiger 儲存引擎的機制,並非故障。可通過
db.<collection>.stats()查看freeStorageSize占storageSize的比例來判斷可回收空間大小。是否未達回收條件:片段率小於 20%、集合物理大小小於 1 MB、或都是小表時,可回收的絕對空間很小,可能無法回收。
是否直連主節點被攔截:若報
use force:true to force,這是保護機制,說明在主節點執行了 compact。不建議強制,請改在 Hidden 或 Secondary 節點執行,或使用控制台空間分析回收 Hidden 節點。
片段率為什麼回收不到 0%
正常現象。compact 只回收檔案尾部的連續空閑空間,檔案內部的可重用空間會保留給後續寫入複用,因此片段率通常無法降到 0%。這是 WiredTiger 儲存引擎的儲存策略。
報 Interrupted ... cache eviction pressure
報錯原因:compact 執行期間會給 WiredTiger 儲存引擎的緩衝帶來驅逐壓力(cache eviction pressure)。低版本、小規格執行個體記憶體資源有限,當緩衝壓力過大、無法及時驅逐時,compact 會被中斷並提前退出。
處理辦法:可在業務低峰期重試、觸發一次主備切換後再試,或升級執行個體規格後再回收。
磁碟滿導致執行個體鎖定時能否執行 compact
可以。 磁碟寫滿後執行個體進入鎖定狀態,此時寫入(insert)和刪除(delete)操作會被拒絕並報錯cloud instance error, disk locked...,但find、compact 和 drop 操作仍可執行。
為何 delete 操作也被拒絕?
因為 delete 操作本身需寫入 oplog、仍會消耗磁碟,在鎖定狀態下同樣被拒絕;而 drop 和 compact 屬於中繼資料級/空間整理操作,被系統允許存取。鎖定態下可執行 compact 回收片段釋放空間,也可執行 drop 直接刪除集合釋放空間,兩者都是無需擴容的復原路徑。
最快恢複決策
你的情況 | 推薦做法 | 恢複速度 | 代價 |
有可安全刪除的無用集合/庫。 | 執行 | 釋放空間後約 4~5 分鐘自動解鎖(有檢測延遲,非即時)。 | 無需付費,但會刪除資料,需確認可刪除。 |
資料不能刪,但有較多片段可回收。 | 執行 compact(鎖定狀態下 compact 被允許存取)。 | compact 釋放空間後約 5 分鐘自動解鎖(有檢測延遲,非即時)。 |
|
沒有可刪資料 / 資料不能丟。 | 擴容完成後解鎖。 |
|
解鎖後請及時回收片段或清理無用資料,避免磁碟再次打滿。詳見解決因磁碟空間耗盡導致的鎖定。
控制台使用率與警示對不上(如控制台 60% 但警示 90%)
這是展示維度不同造成的,不是資料錯誤:
警示按"單個節點的最高值"觸發:複本集裡 Primary、Secondary、Hidden 各節點的磁碟使用率可能不同(Secondary/Hidden 常因 oplog、回收時機、臨時檔案等原因高於 Primary)。只要任一節點超過閾值就會警示。
控制台預設展示的不是"最高節點":執行個體基本資料頁展示彙總值,空間分析預設展示 Hidden 節點,都可能低於觸發警示的那個節點。
如何看各節點真實使用率:進入執行個體监控信息頁,將查看模式切換為子節點獨立,即可分別查看 Primary / Secondary 各節點的磁碟空間使用率,找到真正偏高、觸發警示的節點。
主從節點磁碟使用率為何不一致、如何進一步處置,詳見MongoDB 執行個體空間使用率高問題。
能不能縮小磁碟省錢
不支援縮容。ApsaraDB for MongoDB所有版本均不支援縮減已購買的磁碟空間。即使已清理大量資料、回收片段,也只能保持或擴大磁碟規格,無法直接調小。
如確需降低磁碟規格,只能建立一個更小規格的執行個體,再通過 DTS 將資料移轉過去,然後釋放原執行個體。請評估遷移成本與停機視窗後再操作。
變更配置與規格限制詳見變更複本集執行個體配置。
附錄
為什麼會產生磁碟片段
通過 delete 或 TTL 到期刪除的資料,只是被標記刪除,其佔用的空間不會立即歸還作業系統,而是保留為空白閑塊供後續寫入複用。當刪除多、寫入少時,這些空閑塊長期不被複用,就形成片段,表現為資料量下降但磁碟使用率不降。
何時需要回收磁碟片段
出現以下情況時,建議回收磁碟片段:
刪除大量資料後:刪除大量文檔後,釋放的空間不會歸還作業系統,而是保留供後續寫入複用,磁碟上會留下大量片段空間。
重要手動刪除(
delete)與 TTL 到期刪除都不會自動回收磁碟片段,需手動回收。長期高寫入負載後:持續的高寫入負載(頻繁 insert、update、delete)會在磁碟上逐漸累積片段空間。
磁碟緊張且片段率超過 20% 時:當磁碟使用率達到 85%~90% 或更高時,回收片段可釋放空間、緩解儲存壓力。
查看與預估可回收空間
串連執行個體後(複本集執行個體建議串連 Secondary 節點以減少對業務的影響),執行 db.runCommand({collStats: "<collection>"}) 查看集合的儲存狀況,關注以下欄位:
size:集合的邏輯儲存大小。storageSize:集合的實體儲存體大小。freeStorageSize:集合內可回收的空閑空間(MongoDB 4.4 及以上版本支援)。
使用 remove 刪除文檔後,size 會下降,但 storageSize 可能不變。freeStorageSize 在 storageSize 中的佔比越高,代表片段率越高。
也可執行以下命令預估某集合可回收的片段空間(返回可重用位元組數):
db.<collection>.stats().wiredTiger["block-manager"]["file bytes available for reuse"]對幾乎為空白的執行個體,freeStorageSize 可能返回空值,此時可結合 wiredTiger["block-manager"]["file bytes available for reuse"](可重用位元組)與 ["file size in bytes"](檔案總大小)來估算片段佔比。欄位說明詳見 collStats Output。