11月25日 23:40 至26日 00:10,blog 服务器宕机半小时。受影响的服务包括 blog,freeshell 控制端和 http proxy,public DNS,VPN server,邮件服务器,邮件列表 archive。

问题发生在 11:40 左右,blog 服务突然中断。此时除了与 blog 同一局域网的机器都无法 ping 通 blog。从同一子网的 mirrors 上 ssh 进去,发现 ip route 和 ip rule 都挺正常的,但 ping 自己的 IP 都不通。执行了 ip rule flush,重新添加了 local, main, default 三个 ip rule,重新执行了设置 ip route/rule 的启动脚本,问题如故。当时,高一凡在邮件列表里反映有路由环路,发往 202.141.160.99 的包弹回了上级路由 218.22.21.30。

于是决定重启,23:48 发出 sudo reboot 命令,几秒后连接还没断,就 sudo init 6,大约10秒后 ssh 连接才中断。事后发现,23:49 syslog 里记下了最后一条日志。直到 00:02,新的 syslog 才出来,这时候应该是 kernel 启动 322 秒的事了。可见从发出重启命令到真正关电源需要的时间超过了 5 分钟,kernel 初始化也超过了 5 分钟。dmesg 里从 5.60s 到 290.48s 完全是空的,也没有看到 fsck 之类的字眼。

更坑爹的问题是 nginx 没有启动起来,导致 blog 和 freeshell 的恢复又拖了10分钟。nginx 没起来的原因是形如 s1.freeshell.ustc.edu.cn 这样的域名解析失败。而域名解析失败的原因是本地 bind9 nameserver 没有启动。bind9 启动失败的原因是 named.conf.local 配置文件里少加了一个分号。由于最近几次对 bind9 配置文件做的修改都忘了 git commit,不知道是什么时候配置文件开始出现语法错误了。这就奇怪了,如果配置文件改错了,service bind9 reload 会失败,肯定一眼就发现了。

同样是由于 bind9 没有启动,OpenVPN 无法解析域名,因此几个 tunnel 没能启动,不过这不是大问题。

这次故障中奇怪的地方:

  1. 为什么会出现路由环路?之前出现过一次,定性为内核 bug,之后就没管了。
  2. 为什么从 kernel init 到服务进程(rsyslogd)启动需要近 300 秒的时间,中间内核都在做什么?
  3. bind9 配置文件少了一个分号,为什么改的时候没发现?

应当吸取的教训:

  1. Nginx resolver 不要使用默认的本地 nameserver,以防 nameserver 挂掉连累 nginx。目前已改成4个学校官方 nameserver。
  2. 配置文件修改后应及时 git commit,便于追踪历史。已经将之前 bind9 的几处修改 commit & push。

Blog 服务器上服务太多,路由配置过于复杂,一旦发生故障,受影响的服务太多。计划做的修改:

  1. 向 jameszhang 再申请两台虚拟机(称为A、B)和移动、电信线路 IP 地址,将 OpenVPN server 转移到A,策略路由和国外 tunnel 转移到B,DNS nameserver 转移到B。这样就能避免规则间错综复杂的相互作用,也顺便解决了 tee 不经过 POSTROUTING nat 的遗留问题。
  2. 把 HTTP 服务监控脚本转移到 lug 服务器上,在 freeshell 上反过来监控 lug。
  3. 邮件列表 archive 转移到 freeshell 上,blog 上做反向代理。
  4. 由于少院机房网络偶尔抽风的问题尚未解决,blog,freeshell 控制端,freeshell http proxy,邮件服务器仍然在 blog 上不变,暂不移到 freeshell 上。