0. 概述
因为前后多次遇到关闭 systemd 服务遇到被取消的问题,所以我决定认真地去分析一下这个问题,这样下次我想就可以从容地应对了。
1. 问题详解
之前在测试一个应用的时候发现有时对 systemd service 的操作被取消了,情况类似于:
[[email protected]]# systemctl stop bbbb
Unable to stop service bbbb: Job for bbbb.service canceled.
一时没有思路,然后就忽略了。但是,后面我又遇到了这个问题,而且是另外一个服务:
[[email protected]]# systemctl stop aaa
Unable to stop service aaaa: Job for aaaa.service canceled.
这就有点郁闷了,所以我决定深入地了解一下为什么会这样。首先要先说一个前提,这里服务 aaaa 和 bbbb 有依赖关系:在服务 bbbb 的 service 配置里面是绑定了 aaaa 的:
[[email protected]]# cat /usr/lib/systemd/system/bbbb.service
[Unit]
BindsTo=aaaa.service
After=network.target aaaa.service
这里的意思就是如果要运行 bbbb,那么 aaaa 必须保持 running 的状态。同时 aaaa 和 bbbb 的业务关系是,当 aaaa 运行时,会检查 bbbb 是否在运行(Systemd 的状态是 runnig),如果 bbbb 不是运行状态,那么会主动拉起 bbbb。
这里稍微解释一下:
- bbbb 绑定 aaaa 的原因在于 bbbb 的配置是 aaaa 设置的,如果先于 aaaa 运行,那么会出现配置不对的情况
- aaaa 监控 bbbb 的健康是一个常规操作了。
其实,这是一个简单的 sidecar 模式,只不过加了一个限制。
2. 问题解答
在 systemd 中,为每个 unit 都维护着内部的一个任务队列,当执行一个操作(可能是一个事务)的时候,如果有一个对于同类资源进行操作,那么当前操作就会被取消,然后被新的操作所替代。
3. 测试验证
[[email protected]]# cat /usr/lib/systemd/system/liqiang.io.service
[Unit]
After=network.target
[Service]
ExecStartPre=/bin/sh /root/test.sh
ExecStart=/bin/sh -c '/root/prometheus --config.file /etc/prometheus/prometheus.yml --web.listen-address="0.0.0.0:9091"'
ExecStopPre=/bin/sh /root/test.sh
ExecReload=/bin/kill -HUP $MAINPID
[[email protected]]# cat /root/test.sh
sleep 10
然后打开一个窗口执行:
[[email protected]]# systemctl start prometheus
[[email protected]]# systemctl stop prometheus
在另外一个窗口执行:
[[email protected]]# systemctl start prometheus
可以发现,第一个窗口的 prometheus 的关闭操作被第二个窗口的 start canceld 掉了,并且不会回滚,也就是说此时 prometheus 的状态是关闭的。直到第二个任务执行完毕,prometheus 才被重新拉起,和前面提到的说明是一致的。