MsgTrans 是多协议高性能网络库,现在 MsgTrans 2.0 Beta 1 已经发布。
这是一次面向生产级实时网络的系统性重构,而不是在 1.x 上继续堆叠功能。
MsgTrans 继续通过统一 API 支持 TCP、WebSocket 和 QUIC,但 2.0 重新设计了事件传递、请求生命周期、写入确认、连接代际、资源限制、优雅关闭、协议扩展和公共 API。
我们的目标非常明确:
网络库不应只在正常环境里工作,还必须在弱网、拥塞、重连、超时、慢消费者和异常关闭下给出确定、可验证的结果。
一套业务代码,覆盖三种网络环境
MsgTrans 2.0 让业务层不再绑定具体协议。同一套消息、请求响应和会话处理逻辑,可以部署在三种传输之上。
| 协议 | 推荐场景 | 核心价值 |
|---|---|---|
| QUIC | 移动网络、弱网、高延迟、丢包环境 | 更适合互联网与低延迟传输 |
| TCP | 稳定内网、服务间通信、长连接网关 | 成熟、稳定、行为可预测 |
| WebSocket | 浏览器、HTTP 代理、防火墙限制、只放行普通 Web 流量的环境 | HTTP 基础设施兼容性更强 |
| 自定义协议 | 专用硬件、私有链路、定制传输 | 通过 msgtrans::spi 接入统一传输层 |
业务无需为不同协议维护三套请求状态机、会话生命周期和错误处理逻辑。
2.0 的核心变化:可靠性成为架构属性
1. 有界事件主干,不再静默丢消息
MsgTrans 2.0 删除了核心数据路径中的广播事件总线,改为每连接独立的有界事件管道和 Session Actor:
Connection → bounded channel → SessionActor → SessionHandler
慢消费者只会对自己的连接形成背压,不再影响其他连接。
数据、诊断和控制事件被拆分为不同平面:
旧广播主干在内部饱和测试中曾复现约 91% 的消息丢失。2.0 直接移除了这条结构性风险。
2. 请求生命周期只有一个真相源
2.0 使用统一的 Request Registry 管理请求状态:
Pending → Responding → Responded
→ SendFailed
→ TimedOut
→ SessionClosed
→ Dropped
状态迁移使用原子操作,保证:
Responder 携带不可伪造的 RequestToken,业务方无法手动构造消息 ID 或绕过请求注册表。
3. 彻底关闭重连 ABA 与旧连接污染
每次连接都会获得独立、单调递增的 Session ID。
连接和代际信息存储在同一个原子生命周期槽中。旧连接迟到的 Response、ConnectionClosed 或异步发送,只能影响旧代会话,无法触碰重连后的新连接。
请求 ID 由传输层按会话分配,并且拒绝回绕。宁可明确返回资源耗尽,也不会复用仍可能存在迟到响应的 ID 空间。
4. Ok 终于代表真实成功
2.0 不再把“进入发送队列”包装成“发送成功”。
所有正式 send 路径都是 write-confirmed:
let receipt = client.send(b"hello").await?;
只有底层写循环确认字节已经写入传输层,调用才返回成功。
如果只需要排队、不等待写入,可以显式使用:
client.send_detached(b"hello").await?;
两种语义通过命名直接区分,不再出现真假难辨的 Ok(())。
请求超时现在返回真正的 Err,不再伪装成“成功但没有数据”。广播则返回 BroadcastReport,明确报告成功数量和每个会话的失败原因。
5. 可等待、可证明的确定性关闭
shutdown() 不再只是设置一个停止标记。
2.0 使用受控任务所有权和生命周期监督器,等待:
-
listener 停止
-
scanner 退出
-
actor 与事件泵结束
-
会话资源释放
-
连接许可全部归还
-
监听端口真正释放
关闭结果通过 ShutdownReport 返回:
let report = server.shutdown().await?;
assert!(report.infra_stopped);
assert!(report.permits_restored);
assert!(report.clean);
这解决了 Ctrl+C 后 QUIC 或其他监听端口长时间不能重新绑定、幽灵会话占用连接配额、后台任务脱离服务器生命周期等问题。
严格、安全、统一的协议边界
Strict 成为默认策略
FramePolicy::Strict 现在是默认值。
以下输入都会被视为协议错误并关闭连接:
-
未知 Packet Type
-
未知 Compression Type
-
WebSocket 文本帧
-
尾随多余字节
-
非法固定头
-
超过限制的扩展头或 Payload
-
无法解压的数据
-
声明长度与实际帧不一致
需要兼容 1.x 宽松行为时,仍可显式选择 FramePolicy::Lenient。
三协议共享同一套尺寸限制
TCP、WebSocket、QUIC 不再各自维护不同的隐藏上限。
ServerLimits 和 ClientLimits 统一控制:
-
最大 Payload
-
最大扩展头
-
最大帧尺寸
-
写入截止时间
-
事件管道容量
-
出站队列容量
-
Actor 邮箱容量
同一个包不会再出现“WebSocket 可以发,TCP 却突然断开”的协议差异。
压缩不再可能制造损坏帧
压缩通过 SendOptions 和 RequestOptions 指定,由传输层在 Payload 完成后统一处理:
let options = SendOptions::new()
.biz_type(7)
.compression(CompressionType::Zstd);
如果构建时没有启用对应 codec,发送会明确失败,而不是把原始数据挂上“已压缩”标志继续发出。
入站解压只在共享事件边界执行一次。TCP、WebSocket、QUIC、客户端、服务端和自定义协议的上层消费者看到的始终是明文 Payload 与自洽的包头。
性能优化不是用可靠性换吞吐
MsgTrans 2.0 的性能方向不是盲目追求微基准数字,而是在稳定语义下减少热路径成本:
-
Bytes 驱动的 Payload 与零拷贝切片解码
-
编码路径消除重复 Vec 和 freeze 拷贝
-
QUIC 读取缓冲减少无意义清零
-
每连接独立 Actor,降低跨连接共享竞争
-
ConnectionWriter 将写路径从连接状态锁中分离
-
等待队列和写入回执时不持有连接锁
-
压缩和解压只执行一次
-
广播选项在扇出前只准备一次
-
有界队列防止慢连接无限吞噬内存
-
TCP、WebSocket、QUIC Cargo feature 真正裁剪协议依赖
当前三协议压力测试均保持零传输错误,架构重构前后未观察到显著吞吐回退。
更小、更诚实的公共 API
2.0 删除了大量“看起来能用、实际上未接线”或暴露内部实现的接口。
公共面现在只有两部分:
内部 Transport、Request Registry、Session Actor、协议适配器和状态机不再泄漏到公共命名空间。
公共 API 由快照纳入 CI。一旦接口发生变化,构建会直接失败,避免文档和实现静默漂移。
1.x 用户必须关注的升级点
MsgTrans 2.0 保持 wire format 不变,规范的 1.x 与 2.0 节点可以互通。但 Rust 公共 API 是有意进行的 breaking change。
SessionHandler 拆分
单向消息和请求不再混在同一个入口:
async fn on_message(
&self,
session_id: SessionId,
packet: Packet,
sender: SessionSender,
);
async fn on_request(
&self,
session_id: SessionId,
packet: Packet,
responder: Responder,
);
请求只能通过消费式 Responder 回应。
Packet 字段私有化
packet.message_id();
packet.biz_type();
packet.payload();
packet.into_payload();
packet.try_encode()?;
编码成为可失败操作,超限数据不会再被静默截断。
发送参数拆分
let send = SendOptions::new()
.biz_type(7)
.compression(CompressionType::Zstd);
let request = RequestOptions::new()
.biz_type(7)
.timeout(Duration::from_millis(500));
Raw Packet 发送入口已经删除,调用方无法再伪造 Request 类型和消息 ID。
WebSocket TLS 类型化
旧的 verify_tls: bool 被替换为:
ClientTls::SystemRoots
ClientTls::CustomCa(pem)
ClientTls::Insecure
每个选项都有真实实现,Insecure 只适合开发环境。
深层 import 迁移
应用类型统一从 crate root 导入:
use msgtrans::{Packet, ClientEvent, Responder};
协议实现者使用:
use msgtrans::spi::{Connection, ConnectionWriter, EventSink};
完整迁移说明:
适用场景
MsgTrans 2.0 尤其适合:
如果项目只是普通 REST API,或者只需要短连接 HTTP 请求,MsgTrans 并不是 HTTP 框架的替代品。它面向的是持续连接、双向实时传输和可控生命周期。
如何开始
Beta 1 发布后可使用:
[dependencies]
msgtrans = {
version = "2.0.0-beta.1",
features = ["tcp", "websocket", "quic"]
}
启用压缩:
msgtrans = {
version = "2.0.0-beta.1",
features = ["tcp", "websocket", "quic", "zstd"]
}
对于现有 1.x 项目,建议采用滚动升级:
-
先迁移公共 API并保持原协议部署。
-
在测试环境启用 Strict 策略。
-
验证超时、重连、慢消费者与服务关闭场景。
-
对移动网络优先试运行 QUIC。
-
生产环境先灰度单协议,再扩展到多协议入口。
结语
MsgTrans 1.x 证明了统一 TCP、WebSocket 和 QUIC 是可行的。
MsgTrans 2.0 要证明的是另一件事:
在弱网、拥塞、异常输入、频繁重连和服务退出时,网络库仍然可以给出精确、确定、可观察的行为。
这不是一次简单升级,而是 MsgTrans 从多协议网络库迈向生产级实时传输基础设施的重要一步。