2021-02-22

高性能 Nginx HTTPS 调优

为什么要优化 Ngin HTTPS 延迟

 
Nginx 常作为最常见的服务器,常被用作负载均衡 (Load Balancer)、反向代理 (Reverse Proxy),以及网关 (Gateway) 等等。一个配置得当的 Nginx 服务器单机应该可以期望承受住 50K 到 80K 左右每秒的请求,同时将 CPU 负载在可控范围内。

但在很多时候,负载并不是需要首要优化的重点。比如对于卡拉搜索来说,我们希望用户在每次击键的时候,可以体验即时搜索的感觉,也就是说,每个搜索请求必须在 100ms - 200ms 的时间内端对端地返回给用户,才能让用户搜索时没有"卡顿"和"加载"。因此,对于我们来说,优化请求延迟才是最重要的优化方向。2021Java面试宝典

这篇文章中,我们先介绍 Nginx 中的 TLS 设置有哪些与请求延迟可能相关,如何调整才能最大化加速。然后我们用优化卡拉搜索 Nginx 服务器的实例来分享如何调整 Nginx TLS/SSL 设置,为首次搜索的用户提速 30% 左右。我们会详细讨论每一步我们做了一些什么优化,优化的动机和效果。希望可以对其它遇到类似问题的同学提供帮助。

照例,本文的 Nginx 设置文件放置于 github,欢迎直接使用: 高性能 Nginx HTTPS 调优(https://github.com/Kalasearch/high-performance-nginx-tls-tuning)

TLS 握手和延迟

 
很多时候开发者会认为:如果不是绝对在意性能,那么了解底层和更细节的优化没有必要。这句话在很多时候是恰当的,因为很多时候复杂的底层逻辑必须包起来,才能让更高层的应用开发复杂度可控。比如说,如果你就只需要开发一个 APP 或者网站,可能并没有必要关注汇编细节,关注编译器如何优化你的代码——毕竟在苹果或者安卓上很多优化在底层就做好了。

那么,了解底层的 TLS 和应用层的 Nginx 延迟优化有什么关系呢?

答案是多数情况下,优化网络延迟其实是在尝试减少用户和服务器之间的数据传输次数,也就是所谓的 roundtrip。由于物理限制,北京到云南的光速传播差不多就是要跑 20 来毫秒,如果你不小心让数据必须多次往返于北京和云南之间,那么必然延迟就上去了。

因此如果你需要优化请求延迟,那么了解一点底层网络的上下文则会大有裨益,很多时候甚至是你是否可以轻松理解一个优化的关键。本文中我们不深入讨论太多 TCP 或者 TLS 机制的细节,如果有兴趣的话请参考 High Performance Browser Networking 一书。

举个例子,下图中展示了如果你的服务启用了 HTTPS,在开始传输任何数据之前的数据传输情况。

在 Nginx 中开启 HTTP 2.0 非常简单,只需要增加一个 http2 标志即可

listen 443 ssl;# 改为listen 443 ssl http2;

如果你担心你的用户用的是旧的客户端,比如 Python 的 requests,暂时还不支持 HTTP 2 的话,那么其实不用担心。如果用户的客户端不支持 HTTP 2,那么连接会自动降级为 HTTP 1.1,保持了后向兼容。因此,所有使用旧 Client 的用户,仍然不受影响,而新的客户端则可以享受 HTTP/2 的新特性。

如何确认你的网站或者 API 开启了 HTTP 2

在 Chrome 中打开开发者工具,点开 Protocol 之后在所有的请求中都可以看到请求用的协议了。如果 protocol 这列的值是 h2 的话,那么用的就是 HTTP 2 了


来测试。如果结果为

OCSP response:OCSP Response Data: OCSP Response Status: successful (0x0) Response Type: Basic OCSP Response

则表明已经开启。参考 HTTPS 在 iPhone 上慢的问题 一文

调整 ssl_buffer_size

sslbuffersize 控制在发送数据时的 buffer 大小,默认设置是 16k。这个值越小,则延迟越小,而添加的报头之类会使 overhead 会变大,反之则延迟越大,overhead 越小。

因此如果你的服务是 REST API或者网站的话,将这个值调小可以减小延迟和 TTFB,但如果你的服务器是用来传输大文件的,那么可以维持 16k。关于这个值的讨论和更通用的 TLS Record Size 的讨论,可以参考:Best value for nginx's sslbuffersize option

如果是网站或者 REST API,建议值为 4k,但是这个值的最佳取值显然会因为数据的不同而不一样,因此请尝试 2 - 16k 间不同的值。在 Nginx 中调整这个值也非常容易

ssl_buffer_size 4k;

启用 SSL Session 缓存

启用 SSL Session 缓存可以大大减少 TLS 的反复验证,减少 TLS 握手的 roundtrip。虽然 session 缓存会占用一定内存,但是用 1M 的内存就可以缓存 4000 个连接,可以说是非常非常划算的。同时,对于绝大多数网站和服务,要达到 4000 个同时连接本身就需要非常非常大的用户基数,因此可以放心开启。

这里 ssl_session_cache 设置为使用 50M 内存,以及 4 小时的连接超时关闭时间 ssl_session_timeout

# Enable SSL cache to speed up for return visitorsssl_session_cache shared:SSL:50m; # speed up first time. 1m ~= 4000 connectionsssl_session_timeout 4h;

卡拉搜索如何减少 30% 的请求延迟

 
卡拉搜索是国内的 Algolia,致力于帮助开发者快速搭建即时搜索功能(instant search),做国内最快最易用的搜索即服务。

开发者接入后,所有搜索请求通过卡拉 API 即可直接返回给终端用户。为了让用户有即时搜索的体验,我们需要在用户每次击键后极短的时间内(通常是 100ms 到 200ms)将结果返回给用户。因此每次搜索需要可以达到 50 毫秒以内的引擎处理时间和 200 毫秒以内的端对端时间。

我们用豆瓣电影的数据做了一个电影搜索的 Demo,如果感兴趣的话欢迎体验一下即时搜索,尝试一下搜索"无间道"或者"大话西游"体验一下速度和相关度:https://movies-demo.kalasearch.cn/
对于每个请求只有 100 到 200 毫秒的延迟预算,我们必须把每一步的延迟都考虑在内。

简化一下,每个搜索请求需要经历的延迟有

而在阿里云监控中,我们设置了从全国各地向卡拉服务器发送搜索请求。我们终于发现 SSL 处理时间时常会超过 300 毫秒,也就是说在 T2 这一步,光处理 TLS 握手之类的事情,Nginx 已经用掉了我们所有的请求时间预算。

同时检查之后我们发现,在苹果设备上搜索速度格外慢,特别是第一次访问的设备。因此我们大致判断应该是因为我们使用的 Let's Encrypt 证书的问题。

我们按照上文中的步骤对 Nginx 设置进行了调整,并将步骤总结出来写了这篇文章。在调整了 Nginx TLS 的设置后,SSL 时间从平均的 140ms 降低到了 110ms 左右(全国所有省份联通和移动测试点),同时苹果设备上首次访问慢的问题也消失了。

https://www.ikjzd.com/home/96964
浔兴股份前董事长被捕!资本掮客投案曝光内幕交易细节!:https://www.ikjzd.com/home/104147

No comments:

Post a Comment