这是一道看起来无解的题。

新一代 AMD 处理器提供了两倍的核心数,但每个核心能用到的 L3 缓存只剩原来的六分之一。对于高度依赖缓存局部性的网络服务来说,这几乎是一个不可接受的退步。

Cloudflare 在评估第 13 代服务器时,就遇到了这个困境。这篇文章记录了他们是怎么走出来的——答案不是换一块更保守的 CPU,而是重写了整个软件栈。

原文链接:https://blog.cloudflare.com/gen13-launch/


Gen 13 的硬件底牌

Cloudflare 为第 13 代服务器选择了 AMD EPYC 第五代 Turin 系列处理器,其中最终落地的型号是 Turin 9965。

光看核心数,这是一个毫无悬念的升级:

代次处理器核心/线程每核 L3 缓存
Gen 12AMD Genoa-X 9684X96C/192T12MB(3D V-Cache)
Gen 13 候选一AMD Turin 9755128C/256T4MB
Gen 13 候选二AMD Turin 9845160C/320T2MB
Gen 13 候选三AMD Turin 9965192C/384T2MB

核心数翻倍,Zen 5 架构带来更高的 IPC(每时钟周期指令数),每核功耗还降了 32%,DDR5-6400 提供更高的内存带宽。在纸面上,这是一次全面的代际飞跃。

但有一个数字藏在参数表的角落:每核 L3 缓存,从 Gen 12 的 12MB 骤降到 2MB,缩小了六倍。

这不是一个可以忽略的细节。


先量化,再下结论

Cloudflare 没有凭直觉判断缓存减少会不会成为问题,而是用性能计数器直接测量。他们借助 AMD uProf 工具,收集了 CPU 在实际负载下的详细指标。

数据说明了一切:

  • L3 缓存未命中率相比 Gen 12 的 3D V-Cache 机器大幅上升
  • 内存访问延迟开始主导请求处理时间——原本命中 L3 就能拿到的数据,现在需要去 DRAM 里取
  • 随着 CPU 利用率升高,缓存争用加剧,延迟惩罚随之放大

这里有一个关键的硬件常识:L3 缓存命中大约需要 50 个 CPU 周期,而 L3 未命中需要去访问 DRAM,代价是 350 个周期以上,相差整整一个数量级。

每核缓存减少六倍,意味着同样的工作负载会产生更多的 DRAM 访问,每次访问都要多付出 300 个周期的代价。这个惩罚在高并发下会被迅速放大。


第一轮测试:吞吐涨了,延迟炸了

带着测量数据,Cloudflare 在 Gen 13 上跑了完整的基准测试,当时使用的是原有的 FL1 请求处理层(基于 NGINX 和 LuaJIT 实现,已有超过 15 年历史)。

结果如下:

指标Gen 12 FL1Gen 13 9755 FL1Gen 13 9845 FL1Gen 13 9965 FL1
核心数变化基准+33%+67%+100%
吞吐提升基准+10%+31%+62%
低负载延迟基准+10%+30%+30%
高负载延迟基准>20%>50%>50%

最高密度的 Turin 9965 确实带来了 62% 的吞吐提升,但代价是高负载下延迟上涨超过 50%。

这个代价无法接受。请求处理延迟直接影响用户体验,50% 的延迟劣化不是一个可以用"总吞吐更高"来平衡的指标。


硬件层面能调出多少?

Cloudflare 与 AMD 合作,系统性地测试了各种硬件调优方案:

硬件预取器和 DF Probe Filter 调整:效果微乎其微。

增加 FL1 Worker 数量:能提升吞吐,但会挤占同机上其他生产服务的资源,不可持续。

CPU 绑核与隔离:收益有限。

AMD PQOS(平台服务质量扩展):这是测试结果最接近有用的方案。PQOS 允许以细粒度方式分配 L3 缓存给特定工作负载。

Turin 处理器内部由一个 I/O 裸片和最多 12 个核心复合体(CCD)构成,每个 CCD 有 16 个核心共享一块 L3 缓存。测试结果显示:

  • 在单个 CCD 内给 FL1 划拨专属缓存份额:增益不足 5%
  • 把整个 CCD 专门留给 FL1(即 NUMA 感知绑核):获得超过 15% 的增量吞吐提升

15% 已经是硬件调优的天花板了。距离让 Gen 13 真正发挥价值,还差得很远。


FL2:恰好已经在做的那次重写

硬件调优触顶之后,唯一的出路是从软件层面解决问题。

幸运的是,这件事 Cloudflare 已经在做了。

在 2025 年的生日周期间,Cloudflare 宣布了 FL2 项目——对核心请求处理层的完整 Rust 重写,基于自研的 Pingora 和 Oxy 框架,替换掉有 15 年历史的 NGINX + LuaJIT 代码。

FL2 的立项动机并不是为了解决缓存问题,而是出于三个独立的工程需求:更好的安全性(Rust 的内存安全)、更快的开发迭代速度(严格的模块化系统)、以及整体性能改善(更低的 CPU 和内存消耗)。

但 FL2 的架构特点——更清晰的内存访问模式、更少的动态内存分配——恰好指向了一个假设:它对大 L3 缓存的依赖可能远小于 FL1。

这个假设后来被生产数据证实了。


FL2 + Gen 13 的实测结果

随着 FL2 逐步推向生产,Gen 13 服务器上的实际运行数据开始验证团队的判断:

指标Gen 13 9965 + FL1Gen 13 9965 + FL2
每 CPU% 处理请求数基准高 50%
延迟 vs Gen 12劣化 >50%优于 Gen 12 70%
吞吐 vs Gen 12+62%+100%

几个数字值得单独拎出来看:

FL2 几乎彻底消除了延迟劣化。FL1 在 Gen 13 上高负载时延迟会上涨超过 50%,FL2 不仅没有劣化,还比 Gen 12 更好。这意味着 Gen 13 可以被推到更高的 CPU 利用率,同时严格满足延迟 SLA。

吞吐从 +62% 变成了 +100%。FL1 因为缓存瓶颈,无法将核心数的增加线性转化为吞吐。FL2 消除了这个瓶颈,让性能真正随核心数线性扩展,192 个核心终于能被充分利用。


Gen 13 的三项业务数字

最终确定量产的 Gen 13 选用 AMD Turin 9965,综合性能对比 Gen 12 如下:

最高 2 倍吞吐,且延迟保持在 SLA 范围内——流量峰值吸收能力翻倍,用户体验不受影响。

每瓦性能提升 50%——同等功耗下能处理更多请求,数据中心扩张成本降低,单请求碳排放显著下降。

机架吞吐提升 60%——在机架功耗预算不变的前提下,更高密度的计算能力可以在全球任意 PoP 节点部署,无需单独规划电力扩容。


这件事说明了什么

Cloudflare Gen 13 的故事,表面上是一次服务器换代,深层是一个关于硬件与软件协同设计的典型案例。

AMD Turin 是一款为高吞吐密度优化的处理器,它主动牺牲了每核缓存来换取更多核心。这个选择在硬件设计层面是合理的——但它只有在软件能适配的前提下,才能兑现承诺。

FL1(NGINX + LuaJIT)的代码和执行模式,高度依赖大量 L3 缓存来维持性能。这不是设计缺陷,而是过去十五年里特定硬件环境下自然演化的结果。

FL2 的 Rust 重写,带来的不只是内存安全和代码可维护性的提升,还有对内存访问模式的根本性改善——更少的动态分配,更可预测的数据局部性,更低的缓存压力。这些特性让 FL2 能够充分利用 Turin 的核心数优势,而不被缓存不足拖累。

最值得记住的教训是:硬件提供了可能性,软件决定了能不能用上它。选择新一代硬件之前,先搞清楚自己的软件对硬件资源的假设,才能真正做到物尽其用。


标签: none

添加新评论