按顺序关闭 Linux 上的 VPN 与代理服务
趁路径还在时停用消费者,再停代理,最后通过其所有者停用隧道。要有意使用 ExecStop 与 TimeoutStopSec,而不是大范围 kill。
代理运行时关机卡住,很少是 VPN 的缺陷,即使屏幕上最后看到的是 VPN 也一样。代理后面的应用仍在等待一条即将消失的路径,而拥有隧道的单元还没有被要求关闭它。看起来像服务很慢,通常其实是顺序问题。把顺序理清,比任何超时改动都能解决更多这类情况。
按相反方向由外向内推进:先消费者,再代理,最后隧道——每一层都由启动它的组件来停用。
在停任何东西之前先列出单元
写下正常运行时涉及的应用程序单元、代理单元和 VPN 所有者。把带自身关闭动作的解析器或辅助组件也加进去,因为凌晨两点被忘掉的正是它们。没有这份清单,你敲下的第一条停止命令会随机挑一个受害对象。
名字是弱证据。用户代理、系统代理和另一个账户的隧道可以共用一个名字,生命周期却毫无关系。
先让工作结束,再停消费者
有计划地停止从应用开始:让它完成或取消请求,然后通过其服务单元停用代理。如果应用在隧道消失后仍应继续运行,要有意安排,而不是把它挂到一条即将消失的路由上。
停止过程中仍在途的请求属于记录的一部分,因为下一次启动时的重试风暴正是从那里来的。
ExecStop 与 ExecStopPost 是不同的工具
ExecStop= — 这是同步的停止操作; ExecStopPost= — 这是即使启动失败也会运行的清理。仅仅向进程发信号然后返回的停止命令,会让 systemd 在消费者仍在冲刷数据时继续往下走。无论如何都必须发生的事属于 post 变体,必须阻塞停止的事属于同步变体。应当检查生效的单元及其 drop-in 文件,而不是直接就地修改软件包文件。
依赖图只是给停止任务排序。它不会把异步脚本变成同步的,也不会让远程应用提交自己的数据。
给停止设上限,并知道这个上限的代价
TimeoutStopSec= 同时限制停止命令和服务自身的终止,超时后 systemd 会升级为强制 kill。要依据应用真实的冲刷行为来选值,并写下触到上限时可能丢失什么。因为机器应该关得更快而挑的数字,其实是一个换了名字的数据丢失设置。
停止仍然很慢时,要记录单元、它的子进程、日志区间和超时结果。把所有超时都改短,或者直接上大范围 kill,正是干净关机在下次启动时变成损坏状态的原因。
通过所有者断开连接,然后测三种情况
消费者停掉之后,请拥有隧道的管理器断开连接:systemd 实例、NetworkManager 的活动连接,或厂商服务。杀掉无关的 OpenVPN 进程未必会移除提供路由的会话,而带重启策略的代理可能在你拆路径时重新创建请求。开始之前先把这个策略与计划中的停止协调好。
测试正常停止、带活动请求的停止,以及隧道先失败的停止。有期限的、可重复的流程,胜过只能奏效一次的快速关机。