Dify 插件守护进程线程泄漏的变通方案

Dify 插件守护进程线程泄漏的变通方案

2 min read

 

问题概述 #

发生现象:

  • 索引大量知识库文档时,插件守护进程(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-.scope/pids.max 的实际值为 29958。

根本解决方案 #

  • 修复插件守护进程侧的线程泄漏(应用更新或补丁)。
  • 将一次性处理的文档数分批处理,避免线程数过度增长。

临时解决方法 #

  • 修改宿主机的 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-.scope/pids.max 是否为 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-.scope/pids.max 修改为 max 以缓解限制。同时在 systemd slice 中设置 TasksMax=infinity,防止重启后恢复原值。
  • 补充说明:若不修复线程数异常增长的根本原因(应用的线程泄漏),最终可能出现内存不足等其他问题。建议通过软件更新或分批处理等方式根治问题。

通过以上步骤,可以规避”达到约29958上限导致冻结的问题”。

 

Updated on 2026年6月9日

What are your feelings

  • Happy
  • Normal
  • Sad