每月流量额度应该落在 OpenVPN 账号的哪一层
每次重连就重置的额度不是限制。按账号跟踪用量,每个字节差值只计一次,并让耗尽真正拦截准入。
只要隧道重连就把额度清零,那它就不是限制;把字节计数器直接挂在 VPN 服务器上、却没有地方存放持久状态,结果正是如此。计数器属于会话,额度属于一个人或一份设备合约。这项功能的所有难点都来自这处错配,所以下面的检查关注的是状态存在哪里、哪一层有权做决定。
把额度钉在账号上,而不是隧道上
先给额度命名主体。一个人可能持有三张设备证书,它们各自独立认证,却不应因此各拿一份月度预算。一个能扛住重连、新隧道地址和迁移到第二台网关的稳定账号标识,才是额度唯一能用的锚点。证书通用名只有在签发策略保证一个名字对应一个账号时,才可作为这个键。
分配到的隧道地址永远不是答案。地址会被回收,地址池是共享的,同一个账号可能在同一分钟出现在两台网关上。如果台账以地址为键,断开再重连就足以把油箱重新加满。
每个会话要记录足够的信息,使算术可审计:账号、账期、网关实例、会话标识、最后观测到的计数器,以及已提交的总量。会话标识里要带上守护进程的启动代次,因为重启后的服务器会复用客户端 ID,朴素匹配会继承上一条基线。
确定单位、方向和重置边界
开始采集前,必须把四个定义写成文字。额度统计的是客户端发出的字节、收到的字节,还是两者之和?一个 GB 是 10^9 字节还是 2^30?周期在哪个本地小时、哪个时区翻转?以及计数器究竟测的是什么——隧道开销和重传被计入,而应用文件大小和服务商账单不计入。
这些选择本身没有错,但实现与客户看到的数字必须一致。同一系统的两半若对 GiB 各执一词,或对在 UTC 午夜而非本地时间翻转各执一词,产生的正是那种侵蚀用户对整份额度信任的工单。
把字节总量变成一个计费差值
管理接口会周期性上报 BYTECOUNT_CLI 行,携带客户端 ID 以及每个方向的累计字节总量,bytecount 命令决定这些行的到达频率。从服务器视角看,接收数字统计客户端发出的字节,发送数字统计送达客户端的字节。把间隔设成台账能承受的值;过短的间隔买到的精度其实并不存在。
一个约束塑造了整个设计:管理套接字只接受一条控制连接。监控导出器、图形界面和你的控制器不能各开一条。要决定哪个进程拥有这条通道,让其余进程从它读取状态,因为这个接口会授予管理动作,本就不该暴露在主机之外。
rx_delta = sample.rx_now - session.prev_rx
tx_delta = sample.tx_now - session.prev_tx
charge = rx_delta + tx_delta
# same transaction:
ledger.total += charge
session.prev_rx, session.prev_tx = sample.rx_now, sample.tx_now
把新基线和用量增量一起提交,这样重放样本不会重复计费,而是一分不计。计数器倒退是信号而非欠账:它意味着会话被替换或守护进程重启,正确做法是核对会话标识,而不是记入负数。
断开路径同样需要小心。如果最终事件带着会话结束总量,只计它与最后一次已提交样本的差值。在周期性采样已经计费之后再加总量,是自研额度系统里最常见的重复计费。跨周期边界的会话也需要规则,因为单个结束总量并不携带字节何时越过午夜的信息。
让耗尽拒绝准入,而不只是切断隧道
当账号到达上限,必须发生两件事:现有会话结束,新会话被拒绝。管理协议提供按客户端 ID 的 client-kill,只要枚举该账号的所有活动会话,前半部分就能处理,而不是杀掉你恰好注意到的那一个地址。
后半部分才是额度设计失败的地方。只杀不拒,是在与客户端的重连循环赛跑,它几秒钟后就会欣然回来。准入必须查询共享台账,而在多网关部署中,这项检查不能是每台机器上的一个文件。每个能接受登录的实例都必须看到同样的耗尽状态。
基于令牌的重连值得单独测试。OpenVPN 2.6 可以用 auth-gen-token 在内部校验会话令牌,跳过你控制器用来执行上限的外部认证调用。因此仍然有效的令牌只能证明身份,不能证明剩余额度,每个新的客户端实例仍须查询台账。若改用 management-client-auth,控制器就成了认证方,并继承自行解析会话状态、拒绝过期或无效令牌的义务。
接受采样带来的超支
周期性观测加上断开,得到的是带已知容差的采样额度。客户端可能超出一个上报间隔加上控制器采取动作所需的时间,而同一账号上的并发会话会让这个窗口成倍放大。要在界面上说明这一点,而不是宣传一个你交付不了的精确到最后一字节的截断。
真正的硬顶是另一个工程问题:在转发路径内部执行,并跨会话绑定同一账号。更快地读取计数器不是一回事,也扛不住一个只是多开隧道的客户端。
上线前,跑那些会击穿朴素实现的验收用例:反复重连、两台设备同时在线、控制器与网关重启、丢失断开事件、会话中途翻转周期,以及刚耗尽就尝试令牌重连。然后确定计费中断时的失败模式。持久台账保护你记录下的用量;它无法复活从未到达的观测,而客户有权知道自己处在哪一种情形。