服务在systemctl stop时卡死本质是systemd等待服务“干净退出”失败,常因进程未响应信号、清理逻辑阻塞、依赖未释放或底层资源无法回收;需通过list-jobs、status、ps、lsof查任务队列与进程状态,结合journalctl、show命令分析日志与超时配置,并验证D-Bus通信及依赖链,必要时用systemctl kill强制终止。

服务在 systemctl stop 时卡死,本质是 systemd 等待该服务“干净退出”失败,通常卡在停止流程的某个环节——可能是进程未响应信号、清理逻辑阻塞、依赖未释放,或底层资源(如挂载点、socket、cgroup)无法回收。排查需从服务行为、通信链路、系统状态三方面入手。
看当前任务队列和卡点服务
执行 systemctl list-jobs,确认是否有该服务相关的 job 处于 running 或 waiting 状态(例如 stop myservice.service)。若存在,说明 systemd 正在等待它完成停止动作,但迟迟收不到完成通知。此时不要重复执行 stop,避免堆积更多 job。
接着运行:
-
systemctl status myservice.service—— 查看 Main PID 是否仍存在、State 是否为 deactivating 或 stopping;注意Active:行是否显示 start/stop-post 等子阶段卡住 -
ps -o pid,ppid,comm,state -C mybinary(替换为实际二进制名)—— 确认进程是否还在运行,状态是否为 D(不可中断睡眠,常见于 I/O 卡死)或 T(被跟踪/暂停) -
lsof -p $(systemctl show --property=MainPID myservice.service | cut -d= -f2)—— 检查该进程是否还持有文件、网络连接、挂载点等资源未释放
查日志与超时配置
服务停止卡死往往不写完整日志,因为进程在退出前就僵住了。需主动拉取全量上下文:
-
journalctl -u myservice.service -n 200 --no-pager -o cat—— 查看最近输出,重点关注 Stopping... 后是否还有日志;若完全空白,说明ExecStop脚本或主进程根本没执行到写日志阶段 -
systemctl show myservice.service | grep -E "(Timeout|Kill)"—— 检查是否自定义了过长的TimeoutStopSec(默认 90s),或设置了KillMode=none导致 systemd 不发信号,只能靠ExecStop自行处理 - 若服务有
ExecStop=脚本,用sudo /usr/bin/my-stop-script手动执行一次,观察是否卡住、卡在哪一行(比如umount /mnt/data或curl -X POST http://localhost:8080/shutdown)
验证 systemd 通信与依赖链
有时不是服务本身问题,而是 systemd 无法感知其状态变化:
- 运行
busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager GetUnitState s myservice.service—— 直接通过 D-Bus 查询单元状态,绕过 systemctl 命令层。若返回错误(如 No such unit 或超时),说明 D-Bus 到 systemd 的通信已中断 -
systemctl list-dependencies --reverse --all myservice.service—— 查看哪些单元依赖它;若上游有RequiresMountsFor=或BindsTo=关系,而对应挂载点或服务无法卸载/停止,也会拖住本服务 - 检查是否涉及文件系统:运行
findmnt | grep $(systemctl show --property=MountFlags myservice.service 2>/dev/null),确认相关路径是否可卸载(umount -l可尝试懒卸载)
强制终止与事后分析
若需快速恢复操作,可在确认无数据风险后执行:
-
systemctl kill --signal=SIGTERM --kill-who=main myservice.service—— 仅向主进程发信号,不触及其他子进程 -
systemctl kill --signal=SIGKILL --kill-who=control-group myservice.service—— 杀掉整个 cgroup(含所有子进程),适用于 fork 后 daemonize 的服务 - 停止后立即执行
dmesg -T | tail -30和journalctl -b -p 3 | grep -i "myservice\|cgroup\|freezer",查找内核级冻结、OOM 或 cgroup freezer 异常线索


















