6GB OOM 讓維運升級停在半路
我最近在 staging 複製一個多節點 gateway 的升級情境,才發現資料庫 schema migration 最難處理的地方,不是版本號,而是維護工具到底吃多少記憶體。
環境是 Linux x64、4 vCPU、16GB RAM、Node.js 24.21.0,約 810 個 configured agents,底下實際有 939 個 agent DB。從 schema v28 升到 v31 時,我原本把它當成一次性的 openclaw doctor --fix,想說停掉 gateway,跑完再啟動就好。結果第一輪因為 plugin migration obligations 改變而沒有完成,第二輪在 config flow 跑了約 841 秒,legacy cron inference 又花了 377 秒,進到 contributions 階段後,V8 heap 在接近 6GB 時直接 OOM。
這種問題在 production 最麻煩的不是指令失敗,而是你很難從表面知道它還要跑多久,也不知道重跑會不會重複處理已完成的項目。我的做法是先把升級拆成三個檢查點:
先盤點 agent 數量、DB 數量、plugin migration obligations,以及目前 Node 的
--max-old-space-size。不要只看機器總 RAM,V8 heap 上限和 process 的 RSS 是兩件事。在 staging 先保留完整的 doctor log,按 config flow、legacy cron、contributions 分段記錄耗時和記憶體峰值。以這次結果看,contributions 單段就可能吃掉約 20 分鐘,不能用一般 migration 的幾秒鐘心態估。
production 執行前先確認 rollback 還原點、systemd 的 restart 行為和監控告警。升級期間不要讓 watchdog 把一個尚未完成的維護程序誤判成服務故障後反覆重啟,也要把 OOM kill、disk usage、load average 分開告警。
第三輪成功完成總共約 2462 秒,gateway 之後約 35 秒開機,健康檢查在 52 秒內通過。這個結果讓我比較放心,但也證明一次維護可能要預留接近兩小時的窗口。
重點是,管理幾百個 agent 時,doctor --fix 已經不是普通的 CLI 指令,而是一次需要容量估算、可重入性和進度觀測的維運工作。16GB RAM 不代表可以安全處理 6GB heap 的尖峰,因為還要留給 gateway、資料庫、檔案快取和 systemd 監控。我的判斷標準是:如果 staging 沒有跑出單次完成、可預估、可回復三個條件,就不會直接排 production。寧可先加大隔離的 maintenance node,或把 contributions 拆批處理,也不要在尖峰時段拿正式 gateway 當壓力測試。
作者:Bo-Han Chen