隧道可能出三种不同的问题,而 它们需要三种不同的应对。对端不再应答,守护进程死亡,或者隧道背后的应用停止服务。对其中任何一种都重启服务的配置并不是细致的监控;那是把同一个粗暴动作套用到互不相关的故障上。比较每种机制实际能观察到什么,分工就一清二楚了。

三种看似同一种的故障

对端沉默意味着另一端停止发送,而 OpenVPN 因为掌握心跳,自己就能发现这一点。进程死亡意味着守护进程退出,服务管理器会注意到,而 OpenVPN 无法察觉。应用故障意味着隧道正常而它背后的东西不正常,另外两种机制都无从得知。每一种都需要不同的反应,而任何一种都不等于发现隧道是通的。

这些是来自不同层次的不同信号,每一种都有能在不猜测的情况下采取行动的所有者。把它们混为一谈,就会得到一个对无法解释的症状重启的系统。

在改动任何定时器之前,先把三种情况写下来。这份清单本身通常就显示出:某个机制被要求覆盖全部三种情况。

keepalive 实际展开成什么

keepalive 指令是简写,展开方式因模式而异。在服务器上,keepalive 10 60 会变成每十秒一次的本地 ping、120 秒的本地重启超时,以及推送给客户端的 10 和 60。服务器超时被故意加倍,好让客户端在服务器放弃之前有机会重启。要读运行配置里的展开形式,而不是配置文件里的简写。

正是这种加倍,使得任何声称两端都会在六十秒后重启的描述都是错的。它也解释了为什么当路径劣化时,两端不会同步抖动。

心跳是 OpenVPN 的对端流量,不是对某个公网主机的 ICMP 探测。应答只能证明隧道的远端还活着。它对用户真正需要的数据库或 Web 服务只字未提。

Restart=on-failure 不监视什么

添加覆盖之前,先读已安装的单元文件。Restart=on-failure 响应的是有文档记载的进程失败条件,这与监视连接状态并不是一回事。它不会因为内部重连开始而触发,而干净退出与崩溃的语义也不同。

这个区别很重要,因为内部重启会让同一个进程继续存活。单元什么也看不到,隧道自行恢复,这才是正确的结果。

要有意设置 RestartSec 和启动次数限制,否则崩溃循环会反复冲击网关,把真正的错误埋在重启消息下面。触发重启限制会让单元进入失败状态,这是可见的;而无限循环则不可见。

ping-restart 与 ping-exit 不能互换

ping-restart 触发 OpenVPN 的内部重启并保留进程。ping-exit 在同样的超时条件下结束进程,把决定交给服务管理器。两者互斥,选择后者会改变恢复的归属。区别在于由谁决定再次尝试,以及这次尝试能保留多少状态。

如果选择超时退出,单元就需要相匹配的重启策略和退出状态处理,否则一次存活失败看起来就像永久停止。持久化选项也能在内部重启期间保留接口和路由,但在进程退出期间不能。

每次部署只选一种生命周期,并写下理由。同时携带两条指令的配置,就是还没有做出决定的配置。

把每种故障当作独立情况来测试

在获批的时间窗口内模拟安静的对端、被杀的守护进程和不可用的应用,然后检查哪种恢复被触发。安静的对端应产生内部重连,被杀进程应产生单元重启,应用中断则两者都不应发生。当两种情况产生同一个动作时,说明归属仍然是混的。

反复恢复也不是修复。被拒绝的凭据或两个客户端共用同一个有效名称,会不断互相取代,而更快的定时器只会让这种抖动更快。

相关文章