Rustls服务端性能分析
 Support this Work
Rustls Server-Side Performance
Dirkjan Ochtman,2025年5月13日
过去几年,Rustls 项目很高兴收到来自 ISRG 的大量投资。我们的目标之一是在不牺牲安全性的前提下提高性能。我们上次发布关于性能改进的文章是在2024年10月,现在我们又回来讨论新一轮的改进。
什么是 Rustls?
Rustls 是一个内存安全的 TLS 实现,专注于性能。它已准备好用于生产环境,并被广泛应用于各种应用中。您可以在 Wikipedia 上阅读更多关于其历史的信息。
它附带一个 C API 和 FIPS 支持,以便我们可以将内存安全和性能带给广泛的现有程序。这很重要,因为 OpenSSL 及其衍生产品在互联网上被广泛使用,但存在很长的内存安全漏洞历史,今年也发现了更多漏洞。现在是互联网摆脱基于 C 的 TLS 的时候了。
服务端表现
在我们之前的文章中,我们研究了客户端和服务器上连接的握手延迟和流量吞吐量。虽然客户端通常在任何时候都只有少量的活动连接,但 TLS 服务器通常希望优化高利用率,同时支持尽可能多的连接。TLS 服务器连接通常共享对后备存储的引用,该后备存储可用于跨连接恢复会话,从而显着提高连接设置中的延迟。我们的目标是最大限度地减少共享恢复存储对单个连接造成的性能下降。
我们首先验证了关闭恢复功能将允许线性扩展的假设:
正如我们的测试所表明的那样,在这种情况下,Rustls 设法避免了任何来自扩展的影响,直到本次测试中使用的 Ampere ARM 硬件提供的 80 个内核。这与 BoringSSL 类似,后者也没有显示出影响——尽管它每次握手花费的时间更多。OpenSSL 握手延迟随着规模的扩大而恶化,但比较 OpenSSL 版本表明,其开发团队也已努力改进这一点。
恢复机制
TLS 支持两种不同的恢复策略:
-
有状态恢复 将恢复状态存储在服务器上的某种映射(或数据库)中。该映射的键通过网络发送。因为该键相对紧凑,所以它使用的带宽更少,因此略微降低了延迟。另一方面,当多个服务器为同一潜在恢复客户端提供服务时,很难有效地扩展。
-
无状态恢复 将加密的恢复状态发送到客户端。这很容易水平扩展,因为没有服务器端状态,但是恢复状态要大得多,从而导致带宽使用的增加(以及相关的延迟影响)。
发送给客户端的恢复状态通常称为“票证”。票证加密密钥必须定期轮换,因为密钥泄露会破坏所有过去和未来票证的安全性。为了在支持多个并发会话的同时启用密钥轮换,Rustls 0.23.16 及更早版本将加密密钥包装在互斥锁中,这导致随着并发服务器连接握手次数的增加而产生大量争用。在 Rustls 0.23.17 中,我们开始使用 RwLock 来代替,这会将争用限制在密钥轮换发生的短时间内(默认情况下,每 6 小时)。
最后,我们在 Rustls 0.23.17 中进行了另一项更改,以减少默认情况下在启用无状态恢复时发送的票证数量,从 4 个减少到 2 个,以与 OpenSSL/BoringSSL 的默认值保持一致。这导致在 CPU 时间(加密)和使用的带宽方面都减少了工作量。
握手延迟分布
除了特定的恢复问题之外,我们还在服务器上体验到的延迟分布方面将 Rustls 与其他 TLS 实现进行了比较:不仅要查看平均延迟,还要查看最坏情况(在本例中为 P90 和 P99)延迟。Rustls 在这方面做得很好:
虽然此图特别显示了完整的 TLS 1.3 握手,但在其他情况下也观察到了类似的结果。
结论
当前版本的 Rustls 在服务器上同时处理多个连接时显示出具有竞争力的性能。Rustls 服务器几乎随着可用内核数量线性扩展,并且我们的基准测试中,核心 TLS 握手处理的服务器延迟大约比 OpenSSL 低 2 倍。