AI / 自動化 2026年5月19日

租用 Mac mini 上的 OpenClaw MCP 子程序殘留:退出衛生與 launchd 回收實務(2026-05-19)

ProxyMac 工程團隊 2026年5月19日 約 18 分鐘閱讀

若你在 ProxyMac 香港、日本、韓國、新加坡或美國 節點租用的 Mac mini M4 上同時執行 OpenClawModel Context Protocol(MCP)stdio 工具,卻遇到閒置時 RSS 仍持續上升node 程序數量異常、或閘道升級後工具呼叫「偶發卡死」,本篇提供可複現的排障路徑:先區分孤兒程序堆疊JSON 行緩衝卡死,再以五欄決策矩陣對齊訊號與動作,最後執行九步對 launchd 友善的清理。文中與 並行代理並發stdio 行緩衝閘道重啟恢復 互相連結,方便嵌入值班手冊。

症狀:在換頁抖動之前就看得到的「程序漂移」

社群與上游議題已有案例:某些 CLI/MCP 組合在父程序結束後仍長期占用記憶體,單一 Node 子程序可能穩定持有數十 MB 級別的常駐集(RSS)。單租戶實體機不像共享容器替你遮掩,問題會直接反映在 top、磁碟 I/O 與 launchd 的 CPU 配額上。

  • 程序列表漂移:徹夜無人 SSH,但 pgrep -lf mcp / pgrep -lf modelcontextprotocol 行數比冷啟動後明顯更多。
  • 工具延遲階梯化:首批呼叫成功,後續排隊;根因常是某條管道讀端未收到 EOF,因仍有殭屍讀者占著 stdin。
  • 版本錯位:本機 CLI 已升級,而舊閘道仍監督舊 semver 拉起的子樹,訊號語意與預期不一致。
  • 誤判「模型掛了」:供應商延遲正常,但本機 fork 壓力飆升;務必先查本機再歸咎 LLM。
別與緩衝問題混淆:若日誌裡 JSON 行斷斷續續、CPU 卻平穩,請先讀 stdio 行緩衝。孤兒堆疊更常見的是閒置時 RSS 仍攀升多餘 PID

根因:為什麼 stdio MCP 容易留下「黏性子樹」

stdio 方案避免任意暴露 TCP 埠,但承襲 POSIX 語意:只要寫端未關閉,讀端就永遠等不到 EOFnpx 類引導器亦可能留下脫離中繼 shell 的孫程序。OpenClaw 跑在 LaunchAgent 下時,環境比筆電互動 shell 更「瘦」——HOMEPATH 與鑰匙圈脈絡若不一致,子程序可能在短循環重啟裡自我繁殖,看起來像攻擊排程器,其實只是自動化腳本的邊界條件。

再搭配 ulimit 與記憶體上限:許多 macOS 工作負載上單程序軟限制 2560 個檔案描述子聽起來寬裕,但當並發工具呼叫把「每呼叫 × 三根管道」的乘法做起來,中途觸頂就會留下半開描述子,為 MCP 兄弟程序並存創造條件。

現場處置矩陣(訊號 → 動作)

首要訊號第一反應(順序敏感)必須留存的資料誤判回滾升級負責人
20 分鐘內 RSS 無故上漲約 200 MBps -o pid,ppid,rss,command 快照,再談重啟PPID 鏈 CSV + JSONL 時間戳未標示父 PID 前勿批量 kickstart平台 SRE
管理埠(如 18999)出現雙監聽閘道恢復 單一監聽檢查表執行lsof -nP -iTCP:18999 -sTCP:LISTEN若兩枚 plist 互搶,bootout 錯誤標籤自動化負責人
429 風暴但本機 CPU 不高先降並發,參考 並行代理指南每 5 分鐘桶的 429 計數還原舊的 maxConcurrentTasksFinOps + 演算法
RSS 平穩但工具卡死優先查緩衝/PTY,而非 SIGKILL 日取樣級系統呼叫日誌(政策允許時)撤銷無緩衝實驗參數用戶端工程

九步清理手冊(SSH 登入 ProxyMac mini)

  1. 廣播維護窗口:哪怕只回收 90 秒,也要避免 CI 靜默踩雷。
  2. 匯出證據:閘道日誌尾部 500 行 + launchctl print gui/$UID 過濾 OpenClaw 相關 label。
  3. 凍結新任務:暫停排程或 Webhook 入口,避免「邊殺邊生」。
  4. 標示父程序:畫清 PPID;在子程序分類完成前,不要對 launchd 託管的閘道直接 kill -9
  5. TERM 波:對確認的 MCP 葉程序送 SIGTERM,等待 15 秒再計數。
  6. KILL 只給已驗證 argv 的頑固分子。
  7. 回收閘道:使用廠商文件支援的 launchctl kickstart -k 或 bootout/bootstrap 組合。
  8. 冒煙:以唯讀工具連續呼叫 兩次,觀察 10 分鐘內 RSS 是否回到基線。
  9. 復盤工單:若每週復發,附上 PPID CSV 並連結本文,推動設定層修復。
給財務/採購可引用的數字:在 M4、設定中等的前提下,閒置閘道基線 RSS 通常顯著低於 512 MB;無流量卻長期突破,應視為衛生債而非「模型變貴了」。

launchd 視角:回收紀律與 ThrottleInterval

LaunchAgent 不是 systemd:ThrottleIntervalKeepAliveSuccessfulExit 會共同決定 macOS 以多激進策略 respawn 閘道。若只重啟 Node 二進位卻遺留舊 stdio 控點掛在失效 PTY 上,launchd 仍會認為閘道「健康」,工具側卻隨機連到半死管道。任何手動 kill 後,都要用 launchctl print 對齊 plist,並確認 EffectiveUserID~/Library/LaunchAgents 擁有者一致。

若每次大版本需一次性點 TCC/鑰匙圈授權,可短期使用 VNC 完成 GUI 步驟,再回到 說明中心 所述的無頭 SSH 流程——把 GUI 審批與無人值守 launchd 週期混在同一台機器上,最容易把 MCP 伺服器拉起兩份。

預防:並發、逾時與爆炸半徑

治理孤兒比事後殺程序便宜:

  • 把並行工具呼叫壓在拐點之前,佇列心智模型見 並行 OpenClaw
  • 為每個 MCP server 設定硬逾時(鍵名隨發行版不同):網路型工具可先以 120 秒 為上限,唯讀檔案 stat 可嘗試 15 秒 量級。
  • 每個自動化身分獨立工作目錄,避免多代理爭用 git 與套件管理員鎖。
  • 實驗性 MCP 與正式編排分機器——HK/JP/KR/SG/US 多區域讓「加一台沙盒 mini」變成定價頁勾選,而不是先買硬體再後悔。

常見問題

為什麼閘道停了,MCP stdio 程序還在? 閘道異常結束、SIGTERM 未層層傳遞到孫程序,或 npx 啟動的中繼 shell 已結束但 Node 孫程序仍存活,都會留下半連線 MCP。launchd 若依 KeepAlive 立刻拉起新閘道,舊管道仍被占用時,就會出現工具隨機卡住而模型延遲正常的假象。

正式環境可以直接 kill 疑似 MCP 孤兒嗎? 先 SIGTERM 並保留 ps/lsof 證據,確認命令列與 argv 屬於 MCP 工具後再考慮 SIGKILL。共享自動化主機上務必核對開啟檔案,避免誤殺同事連線。清理後依廠商 LaunchAgent 流程重啟閘道,並以 lsof 確認管理埠僅有一個監聽程序。

這與 stdio 行緩衝卡死有何不同? 行緩衝問題常表現為 JSON 片段遲遲不完整、CPU 並未飆升;孤兒堆疊則常見 RSS 單調上升與多餘 node 程序。前者優先查 PTY/無緩衝參數,後者要收緊並發、逾時與閘道回收紀律。

為什麼把 MCP 副作用 containment 放在 ProxyMac Mac mini 上更划算

MCP 放大了作業系統面:每次工具呼叫都是一次 fork、一組 fd、一次訊號傳播機會。Apple Silicon M4 在單執行緒與能效上給 stdio 多程序留足餘量;macOS 與桌面腳本堆疊一致;香港/日本/韓國/新加坡/美國 節點選擇讓你把自動化放在離 SaaS 與登錄檔更近的位置。ProxyMac 的租賃模型意味著你可以為高風險 MCP 整合另外開一台可犧牲的沙盒 mini,用同一張 定價 頁面說服利害關係人,把機器回收當作軟體衛生的一部分,而不是先買硬體再後悔。

把高風險 MCP 隔離到專用金屬

於香港/日本/韓國/新加坡/美國租用 Mac mini 跑 OpenClaw + MCP 實驗