systemd-journald的SIGPIPE信号BUG

在重启systemd-journald后, 意外的发现, 本台服务器上的其他由 systemd 托管的部分服务, 却意外被 stop 掉了, 由于大部分服务的 unit 文件中都配置了 Restart 规则为 on-failure. 所以如果是异常的退出, 这些服务应该会重启才对. 很明显, 这些服务是被”正常”关闭的.

在查看被 stop 的应用状态时, 发现了以下线索

1
2
3
4
5
$ sudo systemctl status kube-apiserver
......
Active: inactive (dead) since Thu 2018-11-22 13:53:46 CST; 25min ago
Main PID: 90457 (code=killed, signal=PIPE)
......

code=killed, signal=PIPE 这些信息告诉我们, 这个进程是被SIGPIPE信号关闭的. 在网上查阅资料时, 发现 github 中大量的项目 issue 下都有相关的问题. 而问题的矛头都指向了systemd-journald这个服务的重启事件!

问题的原因在于: systemd-journald这个服务重启的时候, 会给所有的进程发送SIGPIPE信号, 而在默认的 systemd 定义中, SIGPIPE 信号属于正常退出的范围. 所以即使 unit 文件配置了Restart on-failure也不会被重启

该问题是 systemd 的已知 BUG 之一. 规避该问题的方式有很多种, 其中以下这种方式并没有生效

1
2
$ systemctl show kube-apiserver | grep PIPE
IgnoreSIGPIPE=yes

默认情况下, IgnoreSIGPIPE=yes是配置好的, 理论上会忽略掉接收到的SIGPIPE信号, 但实际情况表明, 并没有被忽略

解决方案:

  • 在 systemd 的 unit 文件中的 Restart 策略设置为 Always, 这样即使是正常的关闭, 也会重启服务
  • 在 systemd 的 unit 文件中配置 RestartForceExitStatus=SIGPIPE 指定收到这个信号时, 强制重启服务

坏消息:

RestartForceExitStatus 的配置在 systemd 215中才被加入, 对于使用之前版本的情况来说, 并没有什么帮助, 可能Always是唯一的选择


病友:

参考文档: