systemd管理进程自动重启
可以使用 systemd 管理 go 进程
systemd 实践: 依据情况自动重启服务,参考:https://mp.weixin.qq.com/s/W6_Z1zPn3MeDgfGDP263vg
systemd 服务异常自动重启很好用,但有的时候希望某些服务只在特定情况下进行重启,其他时候不要自动重启(比如 OOM,需要人工介入)。 本文抛砖引玉,旨在能够让读者对 systemd 的重启机制有一定了解。
最简单的自动重启范例
1 | [Unit] |
重点参数详解
- Restart=always: 只要不是通过 systemctl stop 来停止服务,任何情况下都必须要重启服务,默认值为 no
- RestartSec=5: 重启间隔,比如某次异常后,等待 5(s)再进行启动,默认值 0.1(s)
- StartLimitInterval: 无限次重启,默认是 10 秒内如果重启超过 5 次则不再重启,设置为 0 表示不限次数重启
案例需求
需求:有个业务,当程序因受到 OOM 而退出的时候,不希望自动重启(此时需要人工介入排查),其他情况下可以自动重启
分析:OOM 就是通过 kill -9 来杀进程,因此只要找到方法,告诉 systemd 当该服务遇到 kill -9 时候不自动重启即可
RestartPreventExitStatus 参数
查询 man systemd.service 发现,systemd 的[Service]段落里支持一个参数,叫做 RestartPreventExitStatus
该参数从字面上看,意思是当符合某些退出状态时不要进行重启。
该参数的值支持 exit code 和信号名 2 种,可写多个,以空格分隔,例如:
1 | RestartPreventExitStatus=143 137 SIGTERM SIGKILL |
表示,当退出情况只要符合以下 4 种情况中任意一种时候,则不再进行重启
- exit code 为 143
- exit code 为 137
- 信号为 TERM
- 信号为 KILL
但具体如何使用,请继续往下看
测试方法
/usr/lib/systemd/system/mytest.service
1 | [Unit] |
/root/mem.c(不断消耗内存直至发生 OOM)
1 | #include <stdio.h> |
编译及执行
1 | gcc -o /root/mem /root/mem.c |
测试结果
1 | [root@fzxiaomange ~]# systemctl status mytest |
重点看上面第 6 行 MainPID:10555(code=killed,signal=KILL)
,这行表示主进程的状态,常见有 2 种情况
- code=exited, status=143:表示 systemd 认为主进程自行退出的,exit code 为 143
- code=killed, signal=KILL:表示 systemd 认为主进程是被 kill 的,接收到的信号是 SIGKILL
等待 5 秒后,并没有自动重启,符合预期
此时将 RestartPreventExitStatus=SIGKILL 改为 RestartPreventExitStatus=SIGTERM
执行 systemctl restart mytest,再进行一次观察,等待 5 秒后,服务自动重启,符合预期
注意事项
RestartPreventExitStatus 与 Restart 的关系
配置 RestartPreventExitStatus=后,并没有完全忽略 Restart=,而是指当退出情况与 RestartPreventExitStatus=匹配的时候,才忽略 Restart=,若没有匹配,根据 Restart=该怎么样还怎么样(具体详见后面的详细测试数据)
kill 子进程会是什么情况
若 systemd 启动的不是一个简单进程,而是会派生子进程的情况(比如执行 shell 脚本,shell 脚本里启动多个程序),那么当另外开一个窗口通过 kill-信号
测试时,会是什么情况呢,先贴出测试方法
ExecStart=/root/mem 改为 ExecStart=/root/mytest.sh
/root/mytest.sh 内容为
1 |
|
测试结果
- 若 kill 主进程 PID(kill 不带参数),则主进程状态为
code=killed,signal=TERM
- 若 kill -9 主进程 PID,则主进程状态为
code=killed,signal=KILL
- 若 kill 最后一个子进程 PID(kill 不带参数),则 systemd 不认为是接收到信号,而是根据最后一个进程的 exit code 进行处理,此时主进程状态为
code=exited,status=143
- 若 kill -9 最后一个子进程 PID,此时主进程状态为
code=exited,status=137
详细测试数据
上面有提到 RestartPreventExitStatus 和 Restart 的关系,但没有数据说明
另外,kill 和 kill -9 的区别,也需要有一份数据说明
因此做了一个详细对比,这里附上详细数据