MsgTrans 2.0 Beta 1 的重点,不是给 1.x 再添加几个协议适配器,而是重新审视生产级实时网络库最难维护的部分:事件如何传递、请求何时结束、写入是否真正完成、连接断开后旧请求如何处理,以及系统在关闭和资源耗尽时能否保持可预测行为。
MsgTrans 仍然通过统一 API 支持 TCP、WebSocket 和 QUIC,但 2.0 把“高性能”扩展成了一组可以验证的工程约束:请求生命周期必须清楚,写入结果必须可确认,连接必须区分代际,资源必须有边界,关闭过程必须能收敛。
这不是一次普通的版本升级
网络库在实验环境中跑得快,并不意味着它适合生产。真实服务通常同时面对以下情况:
- 连接在请求完成前突然断开;
- 自动重连后,新连接继续使用了旧连接的状态;
- 写入接口返回成功,但数据仍停留在队列中;
- 事件处理速度跟不上网络输入,内存持续增长;
- 服务收到退出信号后,既没有丢弃新请求,也没有等待旧请求完成;
- TCP、WebSocket 和 QUIC 的差异泄漏到业务代码中,导致协议切换成本越来越高。
因此,统一 API 的价值不只是让三种协议拥有相似的方法名,更重要的是让业务层能够依赖一致的语义。2.0 的重构方向,正是把这些隐含行为变成明确的公共 API 和生命周期规则。
需要重点关注的八个契约
事件传递
事件传递决定了网络线程、协议解析器和业务处理器之间如何协作。高吞吐场景下,事件不能只追求“尽快投递”,还要回答几个问题:队列是否有上限?消费者变慢时如何施加背压?事件是否可能重复或乱序?关闭时未处理事件如何结束?
升级到 2.0 时,应重点检查事件回调是否仍然假设“永远有消费者”,以及业务代码是否把回调执行时间误当成网络 IO 时间。一个更可靠的设计通常会把事件接收、处理和确认拆开,让调用方能够观察积压并设置资源策略。
请求生命周期
请求从创建到完成,至少要区分成功、失败、取消、超时和连接关闭几种结果。仅返回一个布尔值,无法让调用方正确处理重试和补偿。
业务层可以采用类似下面的状态模型:
Created -> Sent -> Acked -> Completed
| | |
Cancelled Failed TimedOut
任何状态都可能因为连接关闭而结束,但已经完成的请求不能再次被旧连接回调覆盖。
这里的关键不是状态名称,而是状态迁移必须单向、可观测,并且只允许一个终态。否则,重连、超时和异步回调同时发生时,就可能出现一次请求被完成两次的问题。
写入确认
“写入成功”至少有三种含义:数据被应用层接受、数据进入本地发送队列、对端协议确认收到。库的 API 必须明确当前确认点,否则业务代码很容易把队列接收误认为可靠交付。
使用 MsgTrans 2.0 时,可以把写入确认当作一个需要显式选择的策略,而不是默认假设。实时状态同步可能只需要本地排队成功;订单、控制指令等场景则需要更严格的确认、超时和重试规则。
连接代际
连接代际是处理重连竞态的实用手段。假设连接 A 断开后建立了连接 B,A 的延迟回调此时才返回。如果回调没有携带代际信息,它就可能修改 B 的状态。
可以这样实践:每次建立物理连接时递增 generation,所有请求、事件和回调都记录创建时的代际。回调执行前先验证代际,不匹配就丢弃或转入明确的失败路径。
资源限制
没有上限的发送队列、请求表和事件队列,最终都会把短时流量峰值转化为进程内存问题。资源限制不应只存在于配置文件中,还需要在 API 结果和监控指标中体现出来。
至少需要为以下对象设置边界:
- 单连接待发送字节数;
- 全局未完成请求数;
- 单请求超时时间;
- 事件队列长度;
- 优雅关闭的最大等待时间。
当限制触发时,调用方应该得到明确的拒绝、阻塞、丢弃或降级结果,而不是等待一个永远不会完成的 Future。
优雅关闭
优雅关闭不是简单地调用 close()。一个生产级关闭流程通常需要停止接收新请求,保留正在处理的请求,等待可确认的写入完成,在截止时间到达后取消剩余工作,最后释放连接和底层资源。
关闭顺序尤其重要:如果先释放事件循环,再处理请求完成回调,业务层可能永远收不到结果;如果无限等待网络确认,进程又可能无法退出。
协议扩展
TCP、WebSocket 和 QUIC 的统一入口可以降低业务复杂度,但协议扩展仍然需要保留边界。业务代码不应依赖某一种协议独有的内部状态,协议差异应通过扩展点、能力查询或明确的选项暴露。
这能让同一套请求处理逻辑在不同传输协议之间迁移,同时避免为了追求统一而抹平必要的能力差异。
公共 API
重构最终会落到公共 API:类型是否表达了失败原因,异步操作是否可以取消,配置是否具有默认上限,错误是否可以稳定匹配,关闭是否可以重复调用。
Beta 版本尤其值得做一次 API 走查。不要只验证“代码能不能编译”,还要验证异常路径是否足够清晰,因为生产问题大多发生在连接抖动、超时和关闭阶段。
一个可运行的可靠发送器示例
下面的 Python 示例不是 MsgTrans 的官方 API,而是一个可运行的最小模型,用来说明应用层应该如何围绕“连接代际、写入确认、超时和优雅关闭”组织代码。接入实际 SDK 时,将 send_to_transport 替换为 MsgTrans 2.0 的发送调用,并保留这些边界检查。
from __future__ import annotations
import asyncio
from dataclasses import dataclass
@dataclass
class SendResult:
request_id: int
generation: int
acknowledged: bool
class ReliableSender:
def __init__(self, max_pending: int = 100):
self._generation = 0
self._next_id = 0
self._pending: set[int] = set()
self._max_pending = max_pending
self._closing = False
def connected(self) -> int:
self._generation += 1
return self._generation
async def send(self, payload: bytes, generation: int) -> SendResult:
if self._closing:
raise RuntimeError("sender is closing")
if generation != self._generation:
raise RuntimeError("stale connection generation")
if len(self._pending) >= self._max_pending:
raise RuntimeError("pending request limit reached")
self._next_id += 1
request_id = self._next_id
self._pending.add(request_id)
try:
# Replace this sleep with the MsgTrans write operation.
await asyncio.sleep(0.01)
if generation != self._generation:
raise ConnectionError("connection replaced before acknowledgement")
return SendResult(request_id, generation, acknowledged=True)
finally:
self._pending.discard(request_id)
async def close(self, timeout: float = 1.0) -> None:
self._closing = True
deadline = asyncio.get_running_loop().time() + timeout
while self._pending and asyncio.get_running_loop().time() < deadline:
await asyncio.sleep(0.01)
if self._pending:
raise TimeoutError(f"{len(self._pending)} requests did not finish")
async def main() -> None:
sender = ReliableSender(max_pending=2)
generation = sender.connected()
result = await sender.send(b"event=ready", generation)
print(result)
await sender.close()
if __name__ == "__main__":
asyncio.run(main())
这个模型展示了几条值得保留在真实服务中的规则:旧连接的回调不能影响新连接;未完成请求数量必须受限;关闭之后不能接受新请求;关闭需要截止时间;发送结果必须说明是否获得了确认。
升级 Beta 版本前的检查清单
可以把升级工作拆成四组测试:
- 正常路径:验证 TCP、WebSocket 和 QUIC 下的连接、发送、接收和请求完成。
- 竞态路径:在发送、超时、断连和重连同时发生时,确认请求只进入一个终态。
- 资源路径:人为降低队列和未完成请求上限,确认调用方能观察到明确的拒绝或背压结果。
- 关闭路径:发送退出信号,确认新请求被拒绝,旧请求按策略完成或超时,事件循环和连接最终释放。
Beta 版本适合先接入可回滚的实时业务,并为请求状态、写入确认延迟、队列长度、连接代际切换和关闭耗时建立指标。不要只用吞吐量作为验收标准:吞吐量说明系统能跑多快,而生命周期和确认语义决定系统出问题时能否解释、恢复和止损。
MsgTrans 2.0 Beta 1 的真正价值,需要在这些边界条件中被验证。对于生产接入,建议先固定协议能力和错误语义,再逐步提高并发与消息速率;对于对可靠交付有要求的业务,还应在库的确认机制之上设计幂等键、重试上限和持久化补偿。