問題概述 #
發生現象:
- 當索引大量知識庫文件時,外掛程式守護程序(plugin_daemon)會持續產生無數執行緒,最終在「約 30,000 個」時無法建立新執行緒。
- 容器日誌中出現
can't start new thread錯誤,服務凍結。
推測原因:
- 容器/cgroup v2 的 pids.max(處理程序+執行緒上限)設定為 29958(約 3 萬),超過此值時執行緒建立失敗。
- 外掛程式守護程序端的執行緒洩漏,或因大量並行處理導致執行緒數在短時間內激增。
嘗試與錯誤:
- 即使在 Docker Compose 或容器內調整 pids_limit: 0 或 ulimit,由於主機的 cgroup 固定為 29958,因此沒有效果。
- 確認
/sys/fs/cgroup/system.slice/docker-的實際值後,發現為 29958。.scope/pids.max
根本解決方案 #
- 修正外掛程式守護程序端的執行緒洩漏(套用更新或修補程式)。
- 將一次處理的文件數分批處理,避免執行緒數過度增長。
當前因應措施 #
- 變更主機的 cgroup 設定,將 pids.max 提升至 max(無限制)或較大的值。
- 同時在 systemd 的 slice 單元(如 system.slice)中設定 TasksMax=infinity,確保重新啟動後不會恢復原值。
因應措施步驟(逐步指南) #
步驟 1. 從容器的「主機端 PID」識別 cgroup 路徑 #
確認容器 ID:
docker ps
外掛程式守護程序的 ID 如 998eb0c50703 等。
使用 docker top <容器ID> 取得主機上的 PID:
docker top 998eb0c50703
例如:/app/main 的處理程序為 1012512(主機 PID)等。
參考 /proc/<主機PID>/cgroup:
cat /proc/1012512/cgroup
輸出範例:0::/system.slice/docker-998eb0c5070321...scope
步驟 2. 變更實際上限值(pids.max) #
移至對應目錄並確認 pids.max:
cd /sys/fs/cgroup/system.slice/docker-998eb0c5070321...scope
cat pids.max
若值為 29958 等數值則有限制,若為 max 則無限制。
變更為無限制:
echo max | sudo tee pids.max
這樣「當場」可解除限制,但重新啟動或重新建立容器後很可能會恢復原值。
步驟 3. 透過 systemd 設定將 TasksMax 永久設為無限制 #
為避免 cgroup 設定被重設,在 systemd 的 slice 單元(system.slice)中覆寫 TasksMax:
3-1. 建立覆寫檔案: #
sudo systemctl edit --force --full system.slice
編輯器開啟後,在 [Slice] 區段中新增以下內容並儲存:
[Slice]
TasksMax=infinity
3-2. 重新載入守護程序並重新啟動: #
sudo systemctl daemon-reload
sudo systemctl restart docker
若使用 docker-compose,請執行 docker-compose down && docker-compose up -d 等指令重新啟動容器。
新建立的容器將會套用 TasksMax=infinity。
3-3. 確認套用: #
systemctl show system.slice -p TasksMax
# => 若為 TasksMax=infinity 則正常
cat /sys/fs/cgroup/system.slice/pids.max
# => 若為 max 則正常
容器啟動後,再次使用「步驟 1~2」的方法確認 /sys/fs/cgroup/system.slice/docker- 是否為 max。
步驟 4.(必要時)檢查核心參數等 #
核心的執行緒/PID 上限:
sysctl kernel.threads-max
sysctl kernel.pid_max
若為較小的值(3 萬~6 萬左右),則需進一步提高。
sudo sysctl -w kernel.threads-max=200000
若要永久化,請在 /etc/sysctl.conf 中新增 kernel.threads-max=200000 等設定。
systemd 整體的預設 TasksMax:
cat /etc/systemd/system.conf
若 /etc/systemd/system.conf 中有 DefaultTasksMax=65535 等記述,可能會套用至所有服務。
將其變更為 infinity 並重新啟動,可更為確實。
總結 #
- 問題原因:cgroup v2 的 pids.max 固定為約 30000,外掛程式守護程序產生大量執行緒時達到限制。
- 因應措施:將
/sys/fs/cgroup/system.slice/docker-變更為 max 以放寬限制。同時在 systemd slice 中設定 TasksMax=infinity,確保重新啟動後不會恢復原值。.scope/pids.max - 補充:若不修正執行緒數異常增加的根本原因(應用程式的執行緒洩漏),最終可能會發生記憶體不足等其他問題。建議盡可能透過軟體更新或批次分割處理等方式根治。
透過以上步驟,可避免「達到約 29958 上限而凍結的問題」。