N.04 / SYSTEMS

Sodama 数据面工程笔记

一次生产级数据面 Rust 重写的完整工程记录:内核边界、map 契约、性能修复、长期稳定性与证据范围。

阅读时间 13 分钟 · 2026-10-25

一次生产级数据面 Rust 重写的工程笔记:内核边界、map 契约、可复现证据,以及让一个系统长期保持健康所需的、并不光鲜的工作。

工程笔记 001阅读时间 · 13 分钟

01 / 问题在边界,不在语言。

只有改变系统被理解、被验证的方式,重写才有意义。Sodama 从三个约束开始:数据面必须端到端使用 Rust;规则编译必须能与 Go 参考实现逐字节对拍;任何性能或稳定性结论都必须有可以复现的实验。

最终成果既是一套经过生产环境验证的网络系统,也是一份关于 Linux 内核路径、eBPF 生命周期、协议行为与资源治理的研究档案。

02 / 一条数据面,8 个程序,14 张 map。

内核侧包含 7 个 TC classifier 与 1 个 sk_skb offload verdict 程序,由 14 张 BTF map 携带共享状态。Rust / aya-ebpf 定义程序,Rust + aya 在用户态加载并协调它们。

数据包决策留在内核附近,配置、协议实现与运维则进入可测试的控制面。map 布局与单写者纪律被当作架构契约,而不是可以随时改动的实现细节。

配置→规则编译→BTF MAPS→TC + SK_SKB
图 01 — 控制与状态最终落在明确的内核契约上。

03 / 复杂性由控制面承担。

用户态解析完整 .dae 配置并编译规则,实现 DNS 缓存、TCP、regex 与 EDNS 行为,以及 TCP relay、UDP NAT、TCP offload、健康探测、组策略、失败切换、状态面与指标导出。

协议工作覆盖 Shadowsocks、Trojan、VLESS、VMess、TUIC、Hysteria2 与 AnyTLS,包括 UDP 和会话行为。TLS SNI / HTTP Host 嗅探保留域名信息,交由远端解析。每个功能都放在完整数据路径中验收,而不是孤立地勾选清单。

04 / 性能,先把等待时间测出来。

一次重载不应继承慢速订阅拉取的延迟。将拉取与重载解耦后,面板回执从观测到的 19–34 秒降至 0.74 秒,验证、落盘与回执契约保持不变。

实验室仍由 netns 拓扑、故障注入、跨实现客户端、长稳压测与逐字节对拍构成。路径变快,只有在相同契约继续通过时才有意义。

FIG. 02 / 性能热重载回执 · 秒
等待更短,运维契约不变。 修复前后观测区间 · 线性秒轴 061218243036 s 修复前 / 19–34 秒 修复后 / 0.74 秒 ÷ 25.7–45.9等待时间 将订阅拉取与重载解耦;保留验证、落盘与回执。
数据来源:生产实战 §10–§11。区间为修复前观测;0.74 秒为解耦后的重载回执。
表 01 — 核心回归基线
单元测试268 / 2687 ignored
标准 / 单臂拓扑9 / 9 · 9 / 9netns 验证
DNS / 转发面 / 运维6 / 6 · 6 / 6 · 5 / 5专项测试
协议梯17 / 1715 个会话
Go 规则编译器对拍5 / 5逐字节一致
内核矩阵9 / 9 · 9 / 9宿主 + QEMU

05 / 稳定,看长窗口里有没有漂移。

真实负载暴露了功能测试无法覆盖的问题:健康探测阻塞、握手线程失控、粘滞 IP 只作废却不重解析,以及热重载被慢速网络读取拖住。

加入硬超时、探测并发上限、拨号看门狗、拨号时解析与按源隔离失败后,3 个月长期运行测试中 RSS 常驻 68 MB,未观察到内存增长或内存跳变。

FIG. 03 / 稳定性3 个月 · 长期运行
稳定是一段长期行为,不是一个瞬时读数。 3 个月生产窗口内 RSS 常驻 68 MB RSS / MB 020406080100 68 MB 3 months观测窗口 0观察到的内存跳变 0.74 s重载回执
数据来源:3 个月长期生产测试。RSS 常驻 68 MB。该窗口不外推为“内存有界”;硬件、内核版本、提交与流量画像未在此公开。
表 02 — 观测到的故障 → 工程动作 → 测量结果
553 个阻塞接收线程Socket 超时 + 探测上限 96 + 拨号看门狗长期窗口内未观察到复发
Relay 线程 36组拨号回归 ReactorRelay 线程 0;斜率 +2.39 → −0.11
粘滞地址漂移拨号时解析,按源保留健康成员自愈且不丢来源
表 03 — 证据范围
重载回执19–34 秒 → 0.74 秒经过验证、落盘与重载后的面板回执;不等于完整请求延迟。
RSS68 MB3 个月长期运行测试、单一生产负载。
单元测试268 / 268 · 7 ignored对应特定修订;测试通过不等于覆盖所有路径。
尚未公开硬件 · 内核版本 · 提交 SHA · 流量画像 · 完整采样日志在把这些数字当作通用基准之前,需要补齐。

03′ / 不改引擎的控制台。

控制台使用 Axum 后端与 Leptos → WASM 前端,交付为单文件 musl 二进制。它读取既有 Unix socket 状态与指标契约;配置修改统一经过验证、落盘与热重载回执。

二进制约 2.6 MB,静态资源约 940 KB;无浏览器访问时约 3 MB RSS、3 个线程。运行时卡片展示 RSS、线程、FD、CPU 与连接,数据新鲜度指示则区分“面板卡住”与“引擎本来就稳定”。

06 / 决策必须带修订条件。

63 条已采纳 ADR 记录背景、选项、理由、后果,以及最重要的——什么测量结果会触发修订。档案从语言迁移、map 布局延伸到 M4 reactor 与零线程握手。

剩余 backlog 同样明确:工程化打包与发行 CI、fuzz、更多 eBPF 挂载模式、工具链供应链固定,以及协议覆盖。稳定不代表完成,而代表系统行为仍在被持续测量。

内存安全只是起跑线。运维安全,是知道每一个线程、描述符、截止时间与失败路径。
相关项目: Sodama→ ← 返回笔记列表→