systemd TasksMax 为什么会把线程也计入上限
来源:17golang原创
时间:2026-11-10 08:16:47 252浏览 收藏
systemd 的 TasksMax 限制的是服务 cgroup 中的任务数量,线程也单独计数。一个只有少量进程的服务,如果每个进程创建很多线程,仍然可能耗尽任务预算。原因在于它使用 pids 控制器,而该控制器按内核任务标识的口径计数。
官方文档:https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html
先把进程数和任务数分开
面对“进程明明不多,却无法创建线程”的现象,我会先看任务数量,再考虑是否需要加限额。只数 ps 列出的进程行数,很容易漏掉线程池、运行时辅助线程以及服务启动的子进程。
例如一个主进程带有多个工作线程,预算不是只扣一份。服务 cgroup 及其后代中的任务共同占用相应计数。这里讨论 systemd 管理、使用 cgroup v2 的 Linux 服务,不把用户级进程限制与服务任务预算混成同一个开关。

读取服务所属 cgroup 的任务预算
先读取管理器中的配置与路径,再查看对应内核接口。以下命令供在目标 Linux 主机按需使用,替换 worker.service 为实际服务名。本文未执行命令,也不提供虚构线程数或日志。
# 读取服务任务配置、当前任务数和所属层级 systemctl show worker.service -p TasksCurrent -p TasksMax -p Slice -p ControlGroup # 使用管理器返回的真实路径,不按进程名猜测 cgroup 位置 task_cgroup=$(systemctl show worker.service -p ControlGroup --value) if [ -n "$task_cgroup" ]; then # 读取当前任务计数和本级上限;不存在时先确认 cgroup v2 与控制器 cat "/sys/fs/cgroup$task_cgroup/pids.current" cat "/sys/fs/cgroup$task_cgroup/pids.max" # 事件值是累计记录,需结合故障窗口比较变化 cat "/sys/fs/cgroup$task_cgroup/pids.events" fi
把这几项记录在同一故障窗口:服务当前任务数、本级上限、父级配置和应用报错。不要用刚重启后的低计数来否定之前的耗尽,也不要拿累计事件值单独证明故障仍在持续。
给线程池制定有余量的限额
限额应覆盖正常峰值及启动、重载时的临时任务,同时约束异常扩张。我更倾向于先限制业务线程池和子进程并发,再按观察到的峰值设置服务预算,而不是直接去掉所有边界。
# 示例值不是推荐容量;先按正常线程和子进程峰值确定预算 sudo systemctl set-property --runtime worker.service TasksMax=640 # 读取当前配置,确认操作对象及返回值 systemctl show worker.service -p TasksMax -p TasksCurrent
--runtime 表示运行时设置,不作为跨重启保留的配置。若确认要长期使用,可在服务 drop-in 中保存对应配置,并按项目变更流程加载。先记录旧值,便于恢复;不要在多个位置留下含义冲突的设置。
# worker.service 的资源控制配置片段 [Service] # 按本服务的正常任务峰值及余量设置,不等于允许 640 个独立进程 TasksMax=640
增加 TasksMax 不会替代内存预算。线程本身也需要资源,盲目放大线程池可能只是把“创建失败”变成内存压力或调度开销。修正并发模型与调整资源边界应分别说明目的。
结合父级和失败记录判断原因
服务上方的 slice 可能还有更紧的 pids.max。子服务当前计数看似有空间,也可能因为祖先已接近预算而无法创建新任务。因此,需要沿真实 cgroup 层级查看父级,而不是只调高服务自己的 TasksMax。

| 观察 | 下一步判断 |
|---|---|
| 本级计数接近上限且事件增加 | 分析线程池与子进程峰值 |
| 本级有余量但创建仍失败 | 检查祖先预算及其他资源限制 |
| 任务数持续增长不回落 | 检查应用生命周期和并发释放 |
| 调整后只短暂恢复 | 不要继续盲目加额,查清增长来源 |
pids 控制器限制新任务创建,但降低限额不会自动杀掉已有线程。因此,看到当前数量高于配置也不一定是控制器失效。应用报错仍应结合其运行时与系统资源情况解释,不能把所有线程创建失败都归因于这一项。
TasksMax=100 就是最多 100 个进程吗?
不是。线程会计入预算,而且相关子进程也会贡献任务数。应按任务口径估算。
把线程池最大值设为同一个数就够了吗?
不够。还要考虑主线程、辅助线程、子进程以及阶段性峰值,两个数字的对象范围不同。
调大后还要看什么?
观察相同业务负载下任务数量是否稳定、应用创建失败是否消失,以及内存和响应是否符合目标。不要只看配置写入成功。
内核接口资料:https://docs.kernel.org/admin-guide/cgroup-v2.html。把线程计入预算是资源边界的一部分;真正需要修正的是进程行数与任务数之间的估算差异。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
348 收藏
-
379 收藏
-
291 收藏
-
349 收藏
-
119 收藏
-
162 收藏
-
261 收藏
-
181 收藏
-
361 收藏
-
140 收藏
-
256 收藏
-
文章 · linux | 3小时前 | Linux · systemd-journald RateLimitIntervalSec RateLimitBurst LogRateLimitBurst Linux 日志限流477 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习