systemctl stop 卡住本质是服务死锁导致进程残留,需先诊断状态再强制清理:查 status、日志、ps 确认 d/t 进程,用 kill -9、umount -l、fuser -k 及清空 cgroup 处置;永久方案为调整 killmode、timeoutstopsec、execstop,并让服务支持 type=notify 与异步超时。

当 systemctl stop 因服务内部死锁卡住、超时后被 systemd 强制终止,本质不是“命令失败”,而是 systemd 已按策略执行了清理动作,但服务进程残留或状态未收敛。关键不在延长超时,而在于让 stop 行为可中断、可感知、可收尾。
先确认是否真被 kill,还是只是卡在卸载/同步阶段
执行 systemctl status your-service,重点看三处:
- Active 状态是否显示
deactivating (stop)或长时间停在stopping - 日志末尾是否有
Killed process XXX (your-service)(来自 dmesg)或Timed out stopping(来自 journalctl) - 运行
ps aux | grep your-service,看主进程是否仍在,且状态为D(不可中断睡眠)或T(停止)——这是典型内核级死锁信号
立即止血:绕过 systemd 正常流程强行释放
不依赖 systemctl stop,直接干预底层资源:
一个OA雏形,主要是完成项目进程管理的功能。 主要实现: 1。新建项目,设定到期时间,如果超过时间自动转为过期项目。 2。过期项目自动提醒,可自定义设定提醒时间或设定几天一次提醒。 3。自己建立的项目只有自己和超级用户有操作权限。 3。重要的项目可设为重要,有醒目标记,如不想被别人看到的项目可以设为独享,此项目只有自己和管理员可以看到。 4。新项目建立人自动显示为登陆时的用户名,可指定多负责人,如
- 查该服务所属 cgroup:
systemctl show your-service --property=ControlGroup,然后systemd-cgls /sys/fs/cgroup/system.slice/your-service.service看完整进程树 - 对 D/T 状态进程,用
kill -9 PID强杀(kill -0 PID先验证是否响应) - 若进程已僵死但挂载点或文件锁仍占着,执行
umount -l /path/to/mount或fuser -k /path/to/locked/file - 最后手动清空 cgroup:
echo > /sys/fs/cgroup/system.slice/your-service.service/cgroup.procs(需 root)
永久规避:从 service 定义层切断死锁传导链
修改 /etc/systemd/system/your-service.service,重点加固三项:
-
KillMode=process:只杀主进程,避免子线程/守护进程被误伤拖累整体退出 -
TimeoutStopSec=30:设较短超时(如 30 秒),让 systemd 更早放弃等待,转而执行 kill 流程 -
ExecStop=/bin/sh -c 'kill -SIGTERM $MAINPID; sleep 5; kill -SIGKILL $MAINPID 2>/dev/null || true':显式控制信号节奏,不依赖 systemd 默认逻辑
根治源头:让服务自身具备抗死锁能力
systemd 只是调度器,真正要改的是服务代码或启动方式:
- 若服务含阻塞式初始化(如等数据库连接、NFS 挂载),改用异步轮询 + 超时退出,而非 while(true) 等待
- 使用
Type=notify并在代码中调用sd_notify("READY=1"),让 systemd 知道“启动完成”,避免因前台进程未退出而误判 - 对 Java/C++ 类服务,添加 JVM 参数
-XX:+UsePerfData或启用pthread_setcancelstate,确保信号能穿透到线程级










