在linux中,可能会存在如下的场景:我们时刻监测某个重要服务是否在线,如果程序报错退出则自动重启服务(应用开机自启不在此次讨论范围内),以此来保持服务常在线。
调研
经过调研我们关注了linux的看门狗机制。看门狗有硬件看门狗(“硬狗”)和软件看门狗(“软狗”)的区别。硬件看门狗指的是设备主板上某块区域的定时器电路,软件看门狗指的是在linux下有个watchdog的守护进程,它会监测/dev/watchdog文件的读写情况。无论软狗硬狗,只要不咬人都是好狗!
原理
看门狗可以理解为一个定时器,在指定的周期完成前需要“喂狗”,否则狗饿了会咬人(程序重启)。喂狗在硬件看门狗里可能是电路信号,在上述所说的linux“软狗”下指的是往/dev/watchdog文件内写入内容。“喂狗”在各种编程语言中方法又不一样。下面讨论在golang应用中如何借助systemd,使用看门狗机制保持应用常在线。
步骤
- 注册应用为系统服务
将应用注册成系统服务,文件路径:/usr/lib/systemd/system/test.service
,这里给出我们应用的service文件:
[Unit]
# 服务描述
Description=watchdog test
[Service]
# 服务类型,默认的simple
Type=simple
# 程序启动命令
ExecStart=/opt/watchdog-test/watchdog-test
# 程序工作目录
WorkingDirectory=/opt/watchdog-test/
# 看门狗周期30s
WatchdogSec=30
# 程序失败重启
Restart=on-failure
# 启动周期限制为3s,未设置会报启动过快的错
StartLimitInterval=3
StartLimitBurst=100
[Install]
# 多用户生效
WantedBy=multi-user.target
注册成服务后我们就可以使用systemctl来管理我们的应用了。
- 程序喂狗
在配置服务由看门狗看管后,我们需要在设置周期内喂狗(上述配置的30s)。那么在golang应用中我们如何改造程序,让程序按照指定周期内“喂狗”呢?
"github.com/coreos/go-systemd/v22/daemon"
go func() {
interval, err := daemon.SdWatchdogEnabled(false)
if err != nil || interval == 0 {
return
}
for {
daemon.SdNotify(false, daemon.SdNotifyWatchdog)
time.Sleep(interval / 3)
}
}()
以上便是golang下“喂狗”需要引入的包和函数。大家可以根据自己具体的业务逻辑进行改造!比如判断err==nil且喂狗周期到了才喂狗。另外注意函数执行周期,一般取看门狗周期的1/3。在上面代码中,看门狗周期的1/3时间后就会喂一次狗。
详细教程大家可以去看Vincent Bernat
大佬的博客,这里给出链接:
https://vincent.bernat.ch/en/blog/2017-systemd-golang
。