Cloudflare公司宣布弃用Nginx,转用自研的新一代反向代理服务Pingora,并声称其比Nginx更快、更高效、更安全。本文基于Cloudflare官方文章,解析Pingora的技术优势。
今天,我们很高兴介绍Pingora。这是我们使用Rust在内部构建的新HTTP代理,它每天处理超过1万亿个请求,在提升性能的同时,为Cloudflare客户带来诸多新功能,而所需CPU和内存资源仅为旧代理基础架构的三分之一。
随着Cloudflare规模的持续扩大,我们已经超越了Nginx的处理能力。多年来它运作良好,但随着时间推移,其在我们规模下暴露的局限性意味着有必要构建全新的解决方案。我们无法再获得所需的性能,同时Nginx也缺乏我们在复杂环境中需要的功能。
Cloudflare网络作为HTTP客户端(如浏览器、应用、IoT设备)与服务器之间的代理。过去,我们关注于优化用户连接到我们网络的这段链路(如QUIC和HTTP/2优化)。今天,我们关注等式的另一部分:代理我们网络与互联网服务器之间流量的服务。该服务为我们的CDN、Workers、Tunnel、Stream、R2等众多产品提供动力。
让我们探讨为何要替换旧服务,以及专为Cloudflare用例和规模设计的Pingora的开发过程。
为何要重建一个代理?
多年来,我们对Nginx的使用遇到了瓶颈。部分限制我们已通过优化或绕过方式解决,但另一些则难以克服。
架构限制损害性能
Nginx的worker(进程)架构对我们的用例存在操作缺陷,损害了性能和效率。
- 负载不均与阻塞:在Nginx中,每个请求仅由单个worker处理,导致CPU内核间负载不平衡,进而引发性能下降。CPU密集型或阻塞IO的请求会拖慢同一worker内的其他请求。
- 糟糕的连接重用:这是最关键的问题。我们的机器与源服务器建立TCP连接以代理HTTP请求。连接重用能跳过TCP和TLS握手,显著降低TTFB(首字节时间)。然而,Nginx的连接池是worker粒度的。请求到达某个worker后,只能复用该worker内的连接。当我们增加Nginx worker数以扩展时,连接会分散在更多孤立的池中,导致连接重用率下降、TTFB变慢,并需要维护更多连接,消耗更多资源。

我们曾为部分问题提供了变通方案,但要根治所有问题,必须解决其根本:worker/进程模型。
功能扩展困难
Nginx是优秀的Web服务器、负载均衡器或简单网关。但Cloudflare的功能远不止于此。我们常在Nginx外围构建所需功能,并尽量避免与其上游代码库产生过大分歧,这并不容易。
例如,当需要重试失败请求时,我们有时希望将请求发送至另一台带有不同请求头的源服务器。Nginx并不原生支持此操作,迫使我们需要花费额外精力来解决其限制。
同时,所采用的编程语言也加剧了这些困难。Nginx使用C语言编写,其设计本身不具备内存安全性。使用此类第三方代码库极易出错,即使经验丰富的工程师也可能陷入内存安全问题。我们用来补充的Lua语言虽风险较低,但性能较差,且在处理复杂业务逻辑时缺乏静态类型支持。此外,Nginx社区活跃度有限,开发往往较为封闭。
最终抉择:自研之路
过去几年,随着客户群和功能集的增长,我们持续评估三个选项:
- 继续深度投资并定制Nginx。
- 迁移至另一个第三方代理(如Envoy)。
- 从头开始构建内部平台和框架。
经过长期评估,尽管自研需要最大的前期工程投入,但其投资回报率在特定场景下显得更为可观。最终,我们决定打造一个符合梦想的代理应用程序。
Pingora项目
核心设计决策
为了构建一个每秒处理数百万请求、快速、高效且安全的代理,我们做出以下关键决策:
- 编程语言选择Rust:它能在保持C语言级别性能的同时,提供内存安全性。
- 自研HTTP库:尽管有hyper等优秀的第三方HTTP库,我们选择自建以实现最大的HTTP流量处理灵活性,并确保能按自身节奏创新。互联网上存在大量不符合RFC的HTTP流量,我们需要一个稳健、宽容且高度可定制的库来支持各种边缘案例。
- 采用多线程与工作窃取:我们选择多线程而非多进程,以便轻松共享资源(尤其是全局连接池),并集成工作窃取(Work Stealing)来避免前述性能问题。Tokio异步运行时完美契合了我们的需求。
- 开发者友好的可编程接口:我们实施了一个基于“请求生命周期”事件的接口(类似Nginx/OpenResty)。例如,“请求过滤器”阶段允许开发者在收到请求头时运行代码来修改或拒绝请求。这种设计清晰分离了业务逻辑与通用代理逻辑,使之前从事Nginx的开发者能快速上手Pingora。
生产环境表现:更快
Pingora现已处理几乎所有需要与源服务器交互的HTTP请求(如缓存未命中),我们积累了丰富的性能数据。
得益于新的多线程共享连接架构,连接重用率大幅提升。总体流量数据显示,TTFB中位数减少了5毫秒,第95百分位数减少了80毫秒。节省的时间主要来自于更少的TCP和TLS握手。

在所有客户中,Pingora每秒新建连接数仅为旧服务的三分之一。对于某主要客户,连接重用率从87.1%提升至99.92%,新建连接数减少160倍。直观来说,通过切换到Pingora,我们每天为客户和用户节省了434年的握手时间。
生产环境表现:更高效
在相同流量负载下,Pingora消耗的CPU和内存比旧服务分别减少约70%和67%。节省来源于:
- Rust代码相比旧Lua代码运行效率更高。
- 架构效率差异:在Nginx中,Lua代码访问HTTP头需多次复制与内存分配;而在Pingora中,这几乎是直接访问。
- 多线程模型使跨请求共享数据(如缓存)更高效,无需复杂的共享内存与锁机制。
- 新建连接的减少大幅降低了昂贵的TLS握手开销,这对高并发场景下的CPU节省尤为显著。
生产环境表现:更安全
在我们这样的规模下,安全、快速地发布功能充满挑战。Rust的内存安全特性保护我们免受未定义行为的影响,让我们能更专注于功能交互逻辑,而非内存错误或难以诊断的崩溃。
自Pingora上线以来,我们已处理了数百万亿请求,其服务代码自身尚未导致过崩溃。偶尔发生的崩溃通常源于内核错误或硬件问题。这种稳定性极大提升了开发效率与系统可靠性。
总结
我们已经构建了一个更快、更高效、功能更强大的内部代理平台,为当前及未来的产品提供坚实基础。
未来,我们将分享构建Pingora、将其部署以支撑互联网重要部分的过程中,所遇到的具体问题、优化细节以及经验教训,并介绍相关的开源计划。