【Rust日报】2026-10-06 mold 3.0.0:高速链接器改用 Rust

💡 原文中文,约3200字,阅读约需8分钟。
📝

内容提要

mold 3.0.0 发布,链接器由 C++ 改写为 Rust,兼容 GNU ld,性能持平,改用 Cargo 构建。rustc 1.95 存在 overflowing_add 误编译问题,已修复。基准测试显示,读多写少场景下 crossbeam 原子指针吞吐远高于逐项 RwLock。ruxen 使用 nginx 测试套件校验,63/105 通过,性能接近 nginx。

🔎

延伸解读

mold 3.0 迁移到 Rust 的兼容性策略

mold 3.0 从 C++ 改写为 Rust,但发布说明强调其按 2.42.1 的替代品来设计:命令行选项、目标架构和输出(除列出的修复外)均保持一致,链接性能持平。兼容验证覆盖各目标测试套件、真实工作负载和选项组合的输出对比,以及构建全部 Gentoo 包,未发现回退。这表明迁移优先保证行为一致,而非引入新特性。

rustc 1.95 误编译问题的触发条件与修复

该误编译从 rustc 1.95.0 开始出现,编号 #163779,被标记为 stable 到 stable 的正确性回退。问题在 SsaRangePropagation 中,当优化开启且溢出检查关闭时(默认 release 或 -O),特定代码会被编成直接返回 false。触发需要调用 std::ops::Add::add 方法后再调用 overflowing_add,用 + 运算符则无法复现。修复 PR #163780 已合入,issue 已关闭。

读多写少场景下 RwLock 与原子指针的性能差异

基准测试显示,在 50 个读任务、1 个写任务每秒 500 次写、Block 长度 16,384 的读多写少负载下,crossbeam epoch 原子指针的读吞吐为 229.07k 次/秒,远高于 parking_lot::RwLock 的 15.93k 次/秒。原因在于每次 Block 遍历需进行 16,384 次读锁获取和释放,而原子指针方案对整次遍历只 pin 一次 epoch,每项仅做一次原子加载。

ruxen 的验证方式与当前局限

ruxen 是实验性的 nginx 行为重实现,它读取 nginx 配置并用 nginx 上游测试套件校验自身。目前 opt-in 的 105 个测试文件中 63 个端到端通过。性能目标为同配置下至少达到 nginx 1.24 吞吐的 95%,但 8 KiB 静态文件(sendfile 打开)场景低 11.6%,未达目标。作者明确它还不能上生产,且不支持 HTTP/2、缓存和模块。

❓

Q&A

mold 3.0.0 相比之前的 C++ 版本有哪些主要变化?

mold 3.0.0 是从 C++ 改写到 Rust 后的第一个大版本,2.42.1 是最后一个 C++ 版本。3.x 旨在补上与 GNU ld 的兼容缺口,重点是链接脚本,并为 Linux 发行版将 mold 设为默认链接器做准备。命令行选项、目标架构和输出与 2.42.1 相同(除修复外),链接性能持平。构建系统从 CMake 换成 Cargo,需要 Rust 1.95 或更新版本以及一个 C 编译器。去掉了 oneTBB 依赖,仍静态链接 mimalloc 3.5.3,可用 --features system-allocator 改用系统 malloc。启动时不再预留 8 GiB 虚拟地址空间,因此可以在 ulimit -v 下运行。

rustc 1.95 中 overflowing_add 误编译问题是什么?如何修复?

这是 rustc 的误编译问题(编号 #163779),从 1.95.0 开始出现。在优化开启、溢出检查关闭时(默认 release 或 -O),调用 std::ops::Add::add 后再调用 a.overflowing_add(b).1 的函数会被错误地编译为直接返回 false。问题源于 SsaRangePropagation 从可选 assert 传播范围信息,将 AddWithOverflow 后的 assert 视为一定成功。修复在 #163780,标题为 Skip optional asserts in SsaRangePropagation,该 PR 已合入,issue 已关闭。

在读多写少场景下,crossbeam 原子指针相比逐项 RwLock 的性能优势有多大?

基准测试显示,在 50 个并发读任务、1 个写任务每秒 500 次写、Block 长度 16,384 的读多写少负载下,RwLock 读吞吐为 15.93k 次/秒,p50 441.42µs,p95 910.18µs,p99 1.81ms;而 crossbeam epoch 原子指针读吞吐为 229.07k 次/秒,p50 22.44µs,p95 49.84µs,p99 241.97µs。原子指针吞吐远高于 RwLock,因为 RwLock 每次遍历需进行 16,384 次读锁获取和释放,而 crossbeam 的 pin() 对整次遍历只钉一次 epoch,每项只做一次原子指针加载。

ruxen 是什么?它目前支持哪些功能?

ruxen 是实验性的 nginx 行为重实现,读取 nginx 配置,并用 nginx 上游测试套件校验自己的二进制。它只支持 Linux 和 HTTP/1.1,每核一个线程,运行时是 monoio(io_uring),TLS 用 rustls。已实现静态文件、proxy_pass、keepalive 和故障转移、rewrite / return / if / map、error_page、auth_basic、带变量的访问日志,以及带 SNI 的 TLS 1.2/1.3。还没有 HTTP/2、缓存和模块。作者写明它还不能上生产,也不是逐行翻译 nginx 的 C 代码。

ruxen 的性能与 nginx 1.24 相比如何?

性能目标是同一配置下至少达到 nginx 1.24 吞吐的 95%。测试机是 i9-13900HX,wrk -t16 -c512。相对 nginx 1.24:return 200 低 1.0%,反向代理低 1.9%,TLS hello 高 8.0%,8 KiB 静态文件(sendfile 打开)低 11.6%,最后一项低于 95% 目标。

ruxen 通过 nginx 测试套件的情况如何?

ruxen 用 nginx 上游测试套件校验自己的二进制。目前 opt-in 的 105 个测试文件里,63 个端到端通过。还不能执行的访问限制指令,例如 limit_except、ssl_verify_client on、disable_symlinks,会让进程以 [emerg] 拒绝启动。

🏷️

标签

➡️

继续阅读