Justine Tunney 最近写了一篇很硬的系统编程文章,主角是 Linux 4.18 起支持的 restartable sequences,简称 rseq。\n\n这个机制 2018 年就进了 Linux,不算新。但它现在刺眼,是因为 96 核、128 核机器开始离开发者更近了。四核机器上只是“锁慢一点”,到了上百核心,可能就是性能悬崖。\n\n这篇文章真正要看的,也不是 rseq 多炫。它暴露的是另一件事:多核时代,性能瓶颈正在从算法表面沉到调度器、缓存线和语言边界里。\n\n## rseq 补的是锁和 CPU 分片之间的缝\n\nrseq 的核心很小:用户态线程声明一段极短的汇编临界区。如果这段代码执行时被内核迁移到别的 CPU,内核就把它跳到 abort handler,让它重试。\n\n它靠 TLS 和内核共享状态。线程通过 rseq() 系统调用给内核一块 TLS 内存。内核在调度时写入当前 CPU 编号。线程再告诉内核:这几条指令不能被迁核破坏。\n\n正常情况,几条指令就跑完。中途被抢占或迁移,就放弃这次结果,重新来。\n\n这有点像用户态的微型事务。不是数据库事务。它只服务于很短、可重启、和 CPU 本地数据强相关的临界区。\n\n它解决的是一个窄缝,但这个缝很疼:\n\n| 做法 | 痛点 | rseq 补的位置 |\n|---|---|---|\n| mutex | 多核心争同一把锁,排队明显 | 避免热锁 |\n| atomic | 不进锁,但仍争同一条缓存线 | 减少缓存线乒乓 |\n| CPU 分片 | 读完 CPU 号后线程可能被迁移 | 让短临界区失败后重试 |\n| affinity 绑核 | 基准可能快,但库很难安全使用 | 保留调度器自由度 |\n\n所以 rseq 适合 malloc/free 热路径、计数器、运行时内部队列、每 CPU freelist。临界区要短,最好短到十来条汇编指令能讲完。\n\n它不适合复杂业务锁。也不替代原子操作。它更像 Linux 给系统库作者开的窄门:可以快,但只能在非常受控的地方快。\n\n## 数字很猛,但不要把基准当成通用承诺\n\nJustine 给出的数字很刺激。Cosmopolitan malloc 在 128 核 Ampere Altra 上,相比基于 sched_getcpu()%32 的 mutex 分片方案,约快 34 倍。在 96 核 Threadripper Pro 7995WX 上,约快 43 倍。\n\nhit counter 这种极简计数场景里,rseq 相比朴素 mutex 甚至能出现极端数量级差距。\n\n但这里不能乱拔高。不是所有工作负载都会快 34 倍、43 倍,更不是随便换上 rseq 就能跑出神话。\n\n这些数字至少说明一件事:当操作本身足够小,锁、原子、缓存线争用和调度成本会吞掉主体。你以为 CPU 在执行业务逻辑,其实它在抢缓存线、等锁、处理迁移带来的不确定性。\n\n| 场景 | rseq 价值 | 现实边界 |\n|---|---|---|\n| malloc/free 热路径 | 很高 | 需要分配器或系统库实现 |\n| hit counter | 很高 | 适合分片汇总,不适合强一致复杂状态 |\n| 通用业务锁 | 不稳定 | 临界区通常太长,状态也太复杂 |\n| 跨平台库 | 有成本 | 非 Linux 或旧内核必须 fallback |\n| 绑核优化 | 基准可快 | 通用库很难假设线程调度策略 |\n\naffinity 绑核在一些测试里更快,但它不是通用解。绑核等于你接过调度器方向盘。应用一复杂,容器、线程池、NUMA、部署策略都会进来添乱。\n\n对库作者尤其麻烦。库不知道自己会被放进什么进程,也不知道上层怎么调度线程。一个局部最优,很容易变成全局事故。\n\nrseq 的好处正在这里:它不要求库夺走调度权。它只是告诉内核,某几条用户态指令如果被迁核破坏,就请让我重来。\n\n## 真正受影响的是库作者和高性能团队\n\n普通业务开发者不该今天下午就去手写 rseq。它目前主要是现代 Linux 能力,实际使用还高度依赖手写汇编。非 Linux、旧内核、不同架构,都要准备 fallback。\n\n已知更适合碰它的人,是 tcmalloc、jemalloc、glibc、Cosmopolitan 这类系统库和运行时作者。还有一类,是跑在几十到上百核心机器上的高性能服务端团队。\n\n更具体一点:\n\n| 读者 | 该怎么做 | 不该怎么做 |\n|---|---|---|\n| 系统库、运行时、分配器作者 | 评估 rseq 热路径,补 Linux 快路径和可移植 fallback | 把 rseq 当跨平台默认能力 |\n| 多核后端、基础设施团队 | 关注 malloc、计数器、运行时库是否已启用类似优化 | 在业务代码里到处手写汇编 |\n| 普通业务开发者 | 通过升级分配器、运行时、系统库间接受益 | 指望 rseq 直接提升接口 QPS |\n| 硬件/平台团队 | 用 64 核、96 核、128 核环境暴露锁争用 | 只在小机器上判断并发设计好坏 |\n\n我更在意的是第二类人。很多后端团队不会自己写 rseq,但会被它影响。比如要不要换 malloc,要不要升级运行时,要不要重新压测计数器、对象池、日志队列这类热路径。\n\n动作不复杂:先看火焰图和 perf 里有没有锁竞争、atomic 热点、malloc/free 热点。再看底层库有没有 Linux rseq 路径。没有证据,就别为了“先进”动基础设施。\n\n这也是 rseq 最现实的门槛。它不是思想门槛,是条件门槛。你要有足够大的机器,才看得见问题;你要懂 ABI、汇编和缓存一致性,才敢动刀。\n\nC11 当年把 atomic 放进语言层,开发者才不用天天和特定 CPU 指令搏斗。rseq 现在还没有走到那一步。刀很快,刀柄还没完全做好。\n\n“工欲善其事,必先利其器。”这里的器,不只是 CPU。还包括语言、库、运行时,以及开发者能不能表达这种“短到不能再短”的并发意图。\n\n可以拿铁路做个小对照,不完全一样,但结构相似。马车时代拼的是马和车夫。铁路时代,真正拉开差距的是轨距、信号、调度和站场。多核服务器也在发生类似迁移:算法还重要,但调度、缓存线、运行时热路径开始决定上限。\n\n接下来最该观察的,不是又有哪个 benchmark 跑出几百倍。那很容易变成性能烟花。\n\n更该看三件事:主流 malloc 和语言运行时会不会更普遍启用 rseq;发行版和容器环境里的兼容路径是否稳定;开发者工具能不能把这类“每 CPU 短临界区”从手写汇编里解放出来。\n\n如果这些没跟上,rseq 仍然只是少数库作者的利器。如果跟上了,它会悄悄改变很多服务端程序的底层成本结构。\n\n这就是这件事的分水岭:模型、框架、业务代码都在上层热闹,真正的性能账单却可能藏在一条缓存线和一次迁核里。谁还把并发理解成 mutex 和 atomic 两件套,谁就会先被上百核心机器教育。
rseq 不新,但上百核心机器让锁优化开始露怯
其他
2026年6月1日
作者:林川
版权所有:ic.work

核心摘要
Summary
- Justine Tunney 详解 Linux 4.18 起支持的 restartable sequences:它让用户态线程在极短临界区里绕开 mutex 和 atomic,尤其适合每 CPU 分片的数据结构。
- \n真正该看的不是某个基准跑出几十倍,而是多核机器把瓶颈推到了调度、缓存线和语言表达能力上。
- \n系统库、运行时、内存分配器和高性能服务端团队会先受影响;普通业务代码不该贸然手写 rseq,更现实的动作是观察底层库是否已经替你吃到收益。
内容导图
Mind Map
锐评
Commentary
rseq 是小门,不是大道。但上百核心时代,能把这扇门用好的人,会先拿走最便宜的性能。
restartable sequencesrseqLinux系统编程锁优化每 CPU 数据结构用户态多核性能调度Justine Tunney