news 2026/5/9 11:07:54

Linux Systemd 停止服务时杀死子进程的机制及 KillMode 参数详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux Systemd 停止服务时杀死子进程的机制及 KillMode 参数详解

Systemd 停止服务时杀死子进程的机制

1.Systemd 的进程控制原理

Cgroup 控制组

Systemd 利用 Linux 的 cgroup 机制来管理进程树:

# 查看服务的cgroupsystemctl show aservice --property=ControlGroup systemd-cgls /system.slice/aservice.service

进程树关联

当 systemd 启动服务时:

  1. 服务进程(通常是 ExecStart 指定的进程)被放入专用的 cgroup
  2. 该进程的所有子进程会自动继承相同的 cgroup
  3. systemd 监控整个 cgroup 中的所有进程

2.停止服务时的默认行为

默认信号发送

# 默认发送 SIGTERMsystemctl stop aservice# 等同于kill-TERM<main_pid>

超时后的强制终止

[Service] TimeoutStopSec=90 # 默认90秒后发送SIGKILL KillMode=control-group # 默认:杀死cgroup中的所有进程

3.KillMode 参数详解

[Service] # 默认值:杀死cgroup中的所有进程 KillMode=control-group # 可选值: # control-group: 杀死cgroup中所有进程(默认) # process: 只杀死主进程 # mixed: 向主进程发SIGTERM,向子进程发SIGKILL # none: 不杀死任何进程

4.避免子进程被停止的方法

方法1:使用 KillMode=none

[Service] Type=simple ExecStart=/usr/bin/aservice KillMode=none

问题:主进程退出后,子进程变成僵尸或继续运行但systemd认为服务已停止。

方法2:分离子进程到不同cgroup

使用setsidnohup
[Service] Type=forking ExecStart=/usr/bin/aservice-wrapper # 包装脚本 # wrapper脚本示例 #!/bin/bash /usr/bin/nohup /usr/bin/real-daemon > /dev/null 2>&1 & # 或 /usr/bin/setsid /usr/bin/real-daemon exit 0

方法3:使用 Type=forking 和正确的 PIDFile

[Service] Type=forking PIDFile=/var/run/aservice-main.pid ExecStart=/usr/bin/aservice-daemonize KillMode=process # 只杀死主进程

方法4:通过 Systemd 的 Scope 机制

[Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/bash -c "systemd-run --scope --unit=aservice-children.service /usr/bin/child-process"

方法5:使用 Systemd 单元分离

# aservice-parent.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/bin/systemctl start aservice-children.service # aservice-children.service [Service] Type=simple ExecStart=/usr/bin/child-process

5.完整的最佳实践示例

方案1:双服务模式

# /etc/systemd/system/aservice-main.service [Unit] Description=AService Main Controller After=network.target Wants=aservice-workers.service [Service] Type=simple ExecStart=/usr/bin/aservice-controller Restart=always KillMode=process # 只杀控制器 [Install] WantedBy=multi-user.target # /etc/systemd/system/aservice-workers.service [Unit] Description=AService Workers PartOf=aservice-main.service # 主服务停止时,这个服务也会停止 BindsTo=aservice-main.service # 主服务重启时,这个服务也重启 [Service] Type=forking ExecStart=/usr/bin/aservice-worker-manager KillMode=none # 不杀工作进程

方案2:分离进程组

[Service] Type=simple ExecStart=/bin/bash -c 'cd / && /usr/bin/setsid /usr/bin/real-daemon &' KillSignal=SIGINT SendSIGKILL=no

6.生命周期管理策略

使用启动脚本分离

#!/bin/bash# /usr/libexec/aservice-starter# 创建独立会话{# 脱离当前控制组execsetsid"$@"&child_pid=$!# 将子进程移出当前cgroupecho$child_pid>/sys/fs/cgroup/systemd/tasks2>/dev/null||true# 等待主进程结束wait$child_pidexit$?}&

Cgroup 手动管理

[Service] Type=oneshot ExecStart=/bin/bash -c ' # 启动子进程到独立cgroup mkdir -p /sys/fs/cgroup/systemd/independent echo $$ > /sys/fs/cgroup/systemd/independent/tasks exec /usr/bin/child-process '

7.信号转发机制

信号处理器方案

#!/usr/bin/env python3# signal-forwarder.pyimportosimportsignalimportsubprocessimporttimedefsignal_handler(signum,frame):# 不转发SIGTERM给子进程ifsignum==signal.SIGTERM:print("Received SIGTERM, exiting without killing children")os._exit(0)defmain():# 设置信号处理器signal.signal(signal.SIGTERM,signal_handler)# 启动子进程child=subprocess.Popen(["/usr/bin/real-daemon"])# 等待子进程或信号whileTrue:time.sleep(1)if__name__=="__main__":main()

8.注意事项和风险

  1. 僵尸进程风险:如果父进程退出而不等待子进程,可能产生僵尸进程
  2. systemd 状态不一致KillMode=none可能导致服务状态不准确
  3. 资源泄露:脱离管理的进程可能导致资源无法回收
  4. 日志管理:分离的进程需要独立的日志处理

9.推荐的架构设计

推荐架构: ┌─────────────────┐ │ Systemd │ │ (主服务单元) │ └─────────┬───────┘ │ control-group ▼ ┌─────────────────┐ │ 控制器进程 │ ← SIGTERM │ (轻量级) │ └─────────┬───────┘ │ 通过IPC/套接字 ▼ ┌─────────────────┐ │ 工作进程池 │ ← 独立管理生命周期 │ (setsid启动) │ └─────────────────┘

关键原则

  • 主进程作为"监督者",负责启动/停止工作进程
  • 工作进程通过 setsid 创建独立会话
  • 使用 IPC 机制而不是父子进程关系进行通信
  • 工作进程优雅处理自己的终止逻辑

这种方法既保持了 systemd 的管理能力,又允许工作进程有独立的生命周期。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 12:58:03

ue 动作拷贝

拷贝 Base Pose在 AnimGraph 中用 “Use Cached Pose” 节点或者 Save Cached Pose这样你就有一份 Base Pose 可以随时取用计算 Additive通过 Control Rig 或者动画资产得到 Additive Pose如果需要放大动作幅度&#xff0c;可以在叠加前乘系数&#xff1a;AdditivePose * 1.5 相…

作者头像 李华
网站建设 2026/5/9 19:46:53

【Android毕设源码分享】基于springboot+Android的智能校园点餐管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/9 8:58:34

Thinkphp和Laravel无人智慧超市购物商城管理系统_niyfl

目录ThinkPHP与Laravel在无人智慧超市系统中的应用技术选型对比智慧超市核心模块实现性能优化策略部署与运维建议项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理ThinkPHP与Laravel在无人智慧超市系统中的应用 ThinkPHP作为国内流行的PHP框架&…

作者头像 李华
网站建设 2026/5/8 2:42:42

小程序计算机毕设之基于springboot的校园畅聊交友平台大学生线上聊天交友系统的设计与实(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华