Jul 13

看门狗

作者: Lennart Pottering

翻译 : 微蔡

我们systemd是给这么三类人用的: 嵌入式佬、桌面用户和服务器佬。嵌入式系统总是资源有限,桌面计算机要强大的多——但仍没有服务器那么强悍。  然而有一些特性中端系统(桌面计算机)不感冒,低端和高端系统(嵌入式和大型服务器)却都很需要。其中一个这样的特性就是看门狗——硬件的和软件的。

看门狗被广泛应用于嵌入式系统。一旦软件出了失去响应(准确的说,是没有在限定的时间内给看门狗发出信号表明它还在运行),看门狗总是能自动重启硬件。 为了提高可靠性这是必须的,它保证最后总是能通过重启让系统恢复工作。这种功能似乎在桌面电脑上没什么用\footnote{尽管如今多数桌面电脑都包含了看门狗硬件,因为这种逻辑实现起来也没什么成本,多数芯片都内置了}。但是到了高端领域,如高可靠性服务器, 看门狗又要被广泛应用了。

从 183 版本开始,systemd 提供了对硬件看门狗(内核通过 /dev/watchdog 设备文件提供给程序使用 )和软件看门狗(提供给每一个服务程序)的全面支持。基本思路是这样的: 如果启用了硬件看门狗支持, systemd 会经常性的向看门狗硬件发送信号;如果systemd或是系统本身挂起,这种信号就不会再有,看门狗就会导致自动重启;这样从硬件上保护了systemd和系统内核不会无限死机;为了让这套保护系统更完善,systemd 又为其监控的系统服务提供软件看门狗,这样死锁的服务也能被重启(或者别的处理方式);这种软件看门狗可以为每个服务独立配置;
两种看门狗(硬件看门狗保护内核和 systemd, systemd 的看门狗保护后台服务程序)放到一起我们就有了一套监控系统所有部件的看门狗系统。

要使用硬件看门狗,只要简单在在配置里 (/etc/systemd/system.conf ) 为 RuntimeWatchdogSec= 选项设置一个时间。默认是0,也就是禁用。 比如设置为 20s 就能启用。如果 systemd 20s 内不能及时通告看门狗,系统就会重启。这里注意一下, systemd 是在设置的时间过了一半的时候就会去通告看门狗,也就是10s一次。就这样一行简单的配置你就能让硬件发挥看门狗作用了。1

需要提醒的是,硬件看门狗是单路的。要么让 systemd 用,要么让第三方程序(有这么个程序,它的名字就是 watchdog)使用。

ShutdownWatchdogSec=是另一个你在  /etc/systemd/system.conf 里能配置的选项。它给出了系统重启的时候使用的看门狗作用时间。
默认是  10 分钟,它给系统重启逻辑上了更牢靠的锁: 如果重启过程被什么原因卡住了,我们还能靠看门狗直接强制重启。

好了,硬件看门狗逻辑就到这里了,我们有2个选项可以配置,这也已经是能利用看门狗硬件的全部能力了。现在我们看看如果为单独的服务添加看门狗支持。

首先,要让软件看门狗工作,我们需要修改一下服务程序来周期性的提供 “我还活着”信号给 systemd。
其实改起来也很简单。第一,读取 WATCHDOG_USEC= 环境变量,如果有,它会以ascii格式提供
看门狗的间隔时间,就像你在 .service 文件里写的那样。 然后服务程序每隔配置的间隔时间的一半调用
一次 sd_notify("WATCHDOG=1") 。 这样修改后的服务程序就能透明的支持 systemd 提供的看门狗了。

要为服务(当然是已经按照上面提供的方法修改过的)启用看门狗, 只要在 .service 文件
里设置 WatchdogSec= 为你想要的间隔。2


这将导致  WATCHDOG_USEC 环境变量被设置, 并在服务程序没能按时报道的时候让服务器进入失效状态。

如果 systemd 的看门狗逻辑能检测到服务出现死锁并立即让服务进入失效状态,这就足够你搭建一个强健的系统了。
下一步就是配置systemd是否应该重启服务,如果是,那么应该以多快的速度重启,如果重启后服务持续失效又应该怎么做。
要自动重启服务,在配置文件中设置 Restart=on-failure。
要限制服务尝试重启的次数,需要联合使用 StartLimitBurst= 和 StartLimitInterval= 来设置给定的时间内最多能重启的次数,
一旦超过了限制就不再重启转而进行特殊的处理。该处理办法通过 StartLimitAction= 来配置。
默认是none, 也就是什么也做,服务就待在失效状态了。 其他可配置的行为是 重启(reboot)、强制重启(reboot-force),立即重启(reboot-immediate).

重启(reboot) 是通常步骤的重启,通知关闭各个服务,卸载文件系统,最后关机重启。
强制重启(reboot-force) 要快的多,它直接杀死所有运行的程序,但是正常的卸载文件系统后关机重启,所以重开机后文件系统还是一致的。
立即重启(reboot-immediate) 则跳过了所有的步骤,甚至不卸载文件系统就进行关机重启,类似直接按主机上的重启按钮或者是硬件看门狗引起的重启,因此重开机后文件系统需要做检查。
所有的这些设置都在 man 手册 systemd.service(5) 里有仔细介绍。

把这些逻辑全放到一起,我们就有了非常灵活的方法去看门狗式监督一个服务程序。并在服务卡死的时候重启它或者不奏效的话做别的事情。
下面是一个 unit 文件例子:

 

[Unit]
Description=My Little Daemon
Documentation=man:mylittled(8)

[Service]
ExecStart=/usr/bin/mylittled
WatchdogSec=30s
Restart=on-failure
StartLimitInterval=5min
StartLimitBurst=4
StartLimitAction=reboot-force
 

 

该服务如果 30s 内没有向 systemd 报到,或者其他的原因失败会被自动重启。如果5分钟内重启超过4次,特殊行为就要执行,也就是强制重启系统——先卸载文件系统后重启,下次启动的时候文件系统还是干净的。

好了,这就是要向你们说的全部内容了! 有了 PID 1 硬件看门狗支持,又有了每个独立服务能使用的软件看门狗,
我们应该已经提供了你所需要的一切功能得以进行你的“看门狗”式用途。
不管你要捣鼓一个嵌入式系统还是一个手机,或者是组建高可靠服务器,都给试一试 systemd 提供的看门狗吧!


(哦,要是你觉得为何  /dev/watchdog 干嘛要给 PID 1 处理,干嘛不弄一个独立的程序,那请麻烦你仔细的再读一遍,并理解这就是我们要构建的 链式看门狗。并且,我们相信一个没有响应的服务应该和其他错误一样对待。最后,ping /dev/watchdog 也是操作系统最重要的工作之一,虽然不过是一个 ioctl 调用外加几百行代码。而如果改用和外置 watchdog 程序的复杂 IPC 调用,那就不值得维护了。)

systemd 内置的硬件看门狗功能并不和别的硬件看门狗程序冲突,只要不同时使用就可以了,并且 systemd 默认也不启用。也欢迎你使用别的程序来配合
systemd, 只要这样做是最适合你的。

最后一件事: 如果你不知道你的硬件有没有看门狗,你通常回答应该是“是” —— 只要是近几年的电脑都有。当然,用最新的 util-linux 带的 wdctl 工具来证实一下最好不过了,它能告诉你想知道的关于你电脑上看门狗硬件的一切。

I'd like to thank the great folks from Pengutronix for contributing most of the watchdog logic. Thank you!

脚注:

1 那啥,这里有个忠告:当你在折腾核心系统的时候不要启用,否则你调试 PID 1 的时候系统就会突然重启了,因为 systemd 被 gdb 停住了......

2 更详细的配置请查看 man 手册 systemd.service(5)。