原副标题:NGINX不足之处太多,Cloudflare最后舍弃它他用Rust暗鞘了崭新代替品
项目组里关于自建全权的声浪涌现,大家愈来愈觉得这种方式尽管投资较大,但最后投资回报是值得称赞的。
译者|Yuchen Wu、Andrew Hauck
校对|原子武器果汁
撰稿|燕珊
长久以来,NGINX 可以说是中文网站安全和代销服务供应商 Cloudflare 的核心理念,是其所采用的基础应用软件的一部分。
“Cloudflare 将 NGINX 用于其提供更多的所有 Web 服务,并在全世界的多台计算机电脑上采用它作为逆向全权服务器。”“她们选择 NGINX 主要原因在于它的操控性。”Cloudflare CTO John Graham-Cumming 曾如此阐释 NGINX 对 Cloudflare 的必要性性。
不过, 如今 Cloudflare 决定舍弃 NGINX ,急于采用外部合作开发的 Pingora。理据也和操控性有关。
按照非官方的讲法,随着 Cloudflare 的壮大,NGINX 已经难以满足用户她们的现实生活销售业务需求。“尽管 NGINX 多年来一直表现较好,但推移下。其不足之处性也在她们的持续插值、体量收缩下Murviel。她们既难以获得理想的操控性,NGINX 也根本无法为度繁杂的环境提供更多必要性的功能支持。”Cloudflare 于 9 月 14 日发布的昌明中写到。
Pingora 是 Cloudflare 技师用 Rust 撰写的崭新 HTTP 全权控制系统,专门针对 Cloudflare 用Lagor销售业务体量设计。据悉,它每晚处理超过 1 万亿元条允诺,提高控制系统操控性尔后,也为 Cloudflrae 顾客带来不少新功能。更重要的是,它运转所挤占的 CPU 和缓存资源只相等于旧有全权基础建设的一半。
目前 Pingora 仍未开放源码,非官方称将找个最合适的最佳时机再对内撷取。
附注源于 Cloudflare,其详尽讲诉了拿掉旧全权的原因,以及她们是如何合作开发出 Pingora 的。
1为什么要构筑新全权
多年以来,NGINX 的种种不足之处性已经严重影响到她们的销售业务运营。尽管先后优化或缓解了部分限制,但仍有一部分问题始终得不到完美解决。
架构限制开始拖累性能
NGINX worker(进程)架构在她们的用例中存在缺陷,而且已经损害了 Cloudflare 的操控性和效率。
首先,在 NGINX 当中,每条允诺只能由单个 worker 处理。这会导致各 CPU 核心理念的负载不均衡,进而拖慢处理速度。
由于这种允诺进程锁定效应,一旦出现高强度 CPU 操作或阻塞 IO 任务的允诺,那么其他允诺的处理速度也会受到影响。她们已经投入了不少精力尝试解决,但收效不佳。
对她们的用例来说,NGINX 中最大的麻烦还在于糟糕的连接重用机制。她们的设备与原始服务器间通过 TCP 连接来全权 HTTP 允诺。连接重用会重复采用连接池中包含的旧有连接,由此跳过建立新连接所需要的 TCP 和 TLS 握手,从而缩短 TTFB(第一字节时间)。
然而,NGINX 连接池是按 worker 划分的。当允诺到达特定 worker 时,其只能重用该 worker 之内的连接。因此当她们添加更多 NGINX worker 进行扩容时,连接重用率就会变得愈来愈差,导致大量连接分散在所有进程的多个隔离池内。于是 TTFB 延长了、需要维护的连接数量增加了,她们自己乃至顾客的资源(成本)也被白白浪费掉了。
可以看到,NGINX 中的 worker/ 进程模型才是罪魁祸首,所以合作开发新全权就成了从根源上解决问题的最佳途径。
难以添加某些功能类型
NGINX 其实是款非常出色的 Web 服务器、负载均衡器和简单网关。问题是 Cloudflare 的需求远不止于此。以往,她们常常围绕 NGINX 构筑自己需要的各项功能,但同时还要避免同 NGINX 的上游代码库发生严重分歧,这相等于是戴着脚镣跳舞、非常痛苦。
例如,当允诺重试 / 失败时,她们往往希望能将允诺发送到具有不同允诺标头集的其他服务器处。但 NGINX 并不允许这样的操作,所以她们就得投入时间和精力想办法突破 NGINX 的限制。
除了设计上的限制之外,NGINX 的编程语言要求也让她们颇为头痛。NGINX 是纯用 C 语言撰写的,因此在设计上不具备缓存安全性。在采用第三方代码库时经常会出错,即使对经验丰富的技师来说,也很容易闹出缓存安全问题。她们当然希望能尽量回避掉这些问题。
她们用过的另一种补充性语言是 Lua,它的风险更低,但操控性也比较差。另外,在处理繁杂的 Lua 代码和销售业务逻辑时,经常会出现静态类型缺失的问题。
最后,NGINX 社区不太活跃,合作开发项目组往往像在“闭门造车”。
2决定自己开辟一条道路
过去几年以来,随着她们不断扩大顾客群体和功能集,Cloudflare 也一直在认真评估以下三种选项:
继续投资 NGINX,并尝试通过 fork 让它能 100% 满足用户她们的需求。她们已经拥有必要性的专业知识,但考虑到设计之初的架构限制,恐怕要投入大量资源才能根据自身需求完成全面重建。 迁移至其他第三方全权选项。市面上并不缺乏好的项目,比如 envoy 等。但她们担心再过几年,同样的问题也许会在那些项目身上重演。 从零开始构筑外部平台与框架。这个选项的效果肯定是最好的,问题就是挤占的工程资源和产生的前期投入也最多。过去几年来,她们每个季度都会对这些选项开展评估,但始终没找到最有说服力的答案。于是她们继续走阻力最小的道路,不断增强 NGINX。但项目组中关于自建全权的声浪开始涌现,大家愈来愈觉得这种方式虽然投资较大,但最后投资回报是值得称赞的。于是她们开始从零入手构筑全权,希望能设计出完美匹配自身需求的全权方案。
Pingora 项目
设计决策
为了让全权快速、高效且安全地处理每秒数百万条允诺,她们先得做出一系列重要的设计决策。
首先,她们选择用 Rust 撰写这个项目。因为它能够在不影响操控性的前提下,以缓存安全的方式带来可与 C 语言比肩的极佳操控性。
尽管市面上已经有不少很棒的第三方 HTTP 库,例如 hyper,但她们还是决定自行构筑库。理据很简单,她们想要最大限度提升 HTTP 流量处理的灵活性,并确保按照自己的节奏推动创新。
在 Cloudflare,她们需要面对几乎是整个互联网的流量,必须支持种种稀奇古怪、不符合 RFC 的 HTTP 流量。这也是 HTTP 社区和 Web 领域的常见难题,即如何在严格遵循 HTTP 规范的同时,适应潜在遗留袖或服务器同广泛生态控制系统间的细微差别与紧张关系。
在 RFC 9110 中,HTTP 状态码被定义成一个三位整数,通常区间在 100 到 599 之间。Hyper 就是这样一种实现。但也有不少服务器支持采用 599 到 999 之间的状态码。这种冲突曾引发过激烈的争论,尽管 hyper 项目组最后接受了这一变更,但如果不接受其实也没有办法——毕竟双方都有自己的道理可讲。而这,还只是她们需要支持的种种不合规行为中的冰山一角。
为了满足用户 Cloudflare 在 HTTP 生态控制系统中主导性地位的要求,她们必须建立起一个健壮、宽松、可定制的 HTTP 库,适应互联网上的狂野法则、支持种种不合规用例。好在由于是外部原创,所以至少决定权把握在她们自己手中。
下一项设计决策则跟工作负载调度控制系统有关。她们选择了多线程、而非多进程,目的是为了轻松实现资源共享,特别是连接池共享。她们还决定用工作窃取机制来避免前文提到的某些操控性问题。事实证明,Tokio 异步运转时特别符合她们的需求。
最后,她们希望这个项目能直观些、对合作开发者们友好些。她们要合作开发的并不是最后产品,而是可以进一步扩展的平台,允许在其上构筑更多功能。于是,她们决定提供更多一个类似于 NGINX/OpenResty 的基于“允诺生命周期”事件的可编程接口。举例来说,可以后续撰写“允诺过滤器”帮助合作开发人员在收到允诺标头时,运转相应代码来修改或拒绝允诺。通过这样的设计,她们就能清晰地把销售业务逻辑和通用全权逻辑分离开来,同时保证之前接触 NGINX 的合作开发人员也能轻松转向 Pingora、迅速提高工作效率。
3Pingora 在生产中速度更快
让她们快进到现在,Pingora 已经在处理几乎一切需要与源服务器交互的 HTTP 允诺(例如缓存未命中的情况),她们在此期间也收集到了大量操控性数据。
首先,她们来看看 Pingora 如何推动顾客流量提速。Pingora 上的总体流量显示,TTFB 中位数降低了 5 毫秒,第 95 百分位 TTFB 降低了 80 毫秒。这当然不原因在于她们的代码运转更快了,毕竟原封不动的旧服务现在也可以将允诺响应控制在亚毫秒范围内。
这样的节约源于新架构,特别是它跨所有线程实现连接共享的能力。凭借着更好的连接重用率,她们在 TCP 和 TLS 握手上耗费的时间大为缩短。
与旧服务相比,Pingora 将全体顾客的每秒新连接采用量降低至一半。对其中一家主要顾客,其连接征用率从之前的 87.1% 提升到了 99.92%,意味着新连接数量降低至原本的一百六十分之一。为了更直观地感受这种变化,大家不妨看看这个数字:自从采用 Pingora 以来,她们每晚能够为顾客和用户节约下长达 434 年的握手时间。
更多功能
有了技师们熟悉的合作开发者友好接口,又消除了以往令人头痛的限制,她们自然可以快速合作开发出更多新功能。凭借新的协议等核心理念功能,她们现在能够为顾客提供更多更多产品构筑块。
例如,她们能够以相对简单的方式为 Pingora 添加 HTTP/2 上游支持,由此加快了向顾客提供更多 gRPC 的速度。很明显,要想将这项功能添加进 NGINX,不只是涉及的工程量更大、甚至有可能压根难以实现。
最近,我们又公布了 Cache Reserve,Pingora 在其中采用 R2 存储作为缓存层。随着她们向 Pingora 添加更多功能,相信未来将提供更多更多开创性的新产品。
更高效率
在生产环境中, 面对同等流量负载的情况下,Pingora 所消耗的 CPU 和缓存资源量与旧有服务相比,分别降低了约 70% 和 67%。这样可观的资源节约源于以下几大要素。
与旧的 Lua 代码相比,她们的 Rust 新代码运行效率更高。更重要的是,二者在架构上也存在显著的效率差异。以 NGINX/OpenResty 为例,当 Lua 代码想要访问 HTTP 标头时,必从 NGINX C 结构中进行读取、分配一个 Lua 字符串,然后将该标头复制到 Lua 字符串内。最后,Lua 还得对这个新字符串进行垃圾回收。而 Pingora 不同,它能直接执行字符串访问,就这么简单。
多线程模型也让跨允诺数据共享变得更加高效。NGINX 尽管也提供更多共享缓存,但由于实现限制,每次共享缓存访问都需要采用互斥锁,而且只能将字符串和数字放入共享缓存。在 Pingora 中,大多数共享条目都能通过原子引用计数器后的共享引用进行直接访问。
至于 CPU 的节约,主要体现在前文提到的新连接创建量显著降低之上。不同于会造成高昂 TLS 握手成本的旧方案,Pingora 可以更多通过已建立的连接实现数据发送和接收。
更安全
快速安全地发布功能绝非易事,在 Cloudflare 这样庞大的运营体量下更是困难重重。她们几乎难以预测每秒要处理几百万条允诺的分布式环境中可能发生哪些极端状况,毕竟模糊测试和静态分析根本就覆盖不到这样的场景。这时候,Rust 的缓存安全语义保护挺身而出,在保护她们免受未定义行为困扰的同时,也让她们坚定相信自己的服务能够正确运转。
有了这些保障,她们就能更多关注自己的服务变更如何与其他服务或顾客源进行交互。她们能以更快的节奏合作开发出新功能,不再受到缓存安全和种种未知崩溃的拖累。
而一旦真的发生了崩溃,技师们当然要花时间来诊断崩溃如何发生、背后又有怎样的原因。自 Pingora 运转以来,她们已经先后处理过数百万亿元条允诺,还没遇到过任何一次源于服务代码的崩溃问题。
事实上,Pingora 的崩溃可以说非常罕见,每次出现的问题都跟 Pingora 自身没什么关系。最近,她们在一次服务崩溃中发现了一个内核 bug,还在某些设备上发现了硬件问题。这种感觉简直神奇,长久以来最不稳定的应用软件元素现在却成了最可靠的部分,甚至足以支持她们发现硬件层面的缓存 bug……之前无数次重大调试都找不到这些问题,原因自然是当时不等硬件崩溃,应用软件早已经坚持不住了。
4总结
总而言之,她们建立起一套更快、更高效、更通用的外部全权,并把它当成现有及未来产品的运转平台。
借此机会,她们重新将视线集中到 Cloudflare 面临的问题、值得称赞探索的优化空间,以及 Pingora 合作开发过程中积累下的重要经验教训与技术细节身上。她们也将回归开放源码精神,找个适合的机会与大家撷取更多后续成果。
总之,Pingora 是她们重构控制系统的一次最新尝试,但绝不会是最后一次。期待 Pingora 能成为她们全面控制系统重构的重要基石。
原文链接:
https://blog.cloudflare.com/how-we-built-pingora-the-proxy-that-connects-cloudflare-to-the-internet/
CEO 们突然介入到 IT 建设, 企业纷纷迁出 VM 虚拟机基础建设
“羊了个羊”一天宕机 3 次,马化腾辟谣日赚 468 万元;60 岁史玉柱“重返一线”改游戏;旷工为由辞退员工,脉脉被判赔 24 万|Q 资讯
Adobe 豪掷 200 亿美元收购 Figma,合作开发者却将其骂上了“热搜”
历时三年替拿掉二十年老控制系统,这个项目组选择“一次性到位” | 卓越技术项目组访谈录
活动推荐
企业数据库如何满足用户高弹性、易伸缩等销售业务需求?
9 月 26 日 19:00,作业帮、微盟技术专家直播间为你解答!
预约本期 DB Talk 技术公开课,聚焦【暗鞘数据库技术破局与最佳实践】,Get 敏态场景下的数据库落地实践经验!