问题概述 #
发生现象:
- 索引大量知识库文档时,插件守护进程(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 进程的宿主机PID为 1012512 等。
查看 /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 则OK
cat /sys/fs/cgroup/system.slice/pids.max
# => max 则OK
容器启动后,再次使用”步骤 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上限导致冻结的问题”。