国产在线观看精品免费,亚洲日本VA久久一区二区,香蕉久久99综合一区二区三区,久久精品99国产精品蜜桃小说

高性能 Nginx HTTPS 調優(yōu) - 如何為 HTTPS 提速 30%

2021-11-03 15:54:11 shuai.chang

睿智創(chuàng  )新RAIZ,一體化IT服務(wù)提供商
為什么要優(yōu)化 Ngin HTTPS 延遲

Nginx 常作為最常見(jiàn)的服務(wù)器,常被用作負載均衡 (Load Balancer)、反向代理 (Reverse Proxy),以及網(wǎng)關(guān) (Gateway) 等等。一個(gè)配置得當的 Nginx 服務(wù)器單機應該可以期望承受住 50K 到 80K 左右[1]每秒的請求,同時(shí)將 CPU 負載在可控范圍內。

但在很多時(shí)候,負載并不是需要首要優(yōu)化的重點(diǎn)。比如對于卡拉搜索來(lái)說(shuō),我們希望用戶(hù)在每次擊鍵的時(shí)候,可以體驗即時(shí)搜索的感覺(jué),也就是說(shuō),每個(gè)搜索請求必須在 100ms - 200ms 的時(shí)間內端對端地返回給用戶(hù),才能讓用戶(hù)搜索時(shí)沒(méi)有“卡頓”和“加載”。因此,對于我們來(lái)說(shuō),優(yōu)化請求延遲才是最重要的優(yōu)化方向。

這篇文章中,我們先介紹 Nginx 中的 TLS 設置有哪些與請求延遲可能相關(guān),如何調整才能最大化加速。然后我們用優(yōu)化卡拉搜索[2] Nginx 服務(wù)器的實(shí)例來(lái)分享如何調整 Nginx TLS/SSL 設置,為首次搜索的用戶(hù)提速 30% 左右。我們會(huì )詳細討論每一步我們做了一些什么優(yōu)化,優(yōu)化的動(dòng)機和效果。希望可以對其它遇到類(lèi)似問(wèn)題的同學(xué)提供幫助。

照例,本文的 Nginx 設置文件放置于 github,歡迎直接使用: 高性能 Nginx HTTPS 調優(yōu)[3]

TLS 握手和延遲

很多時(shí)候開(kāi)發(fā)者會(huì )認為:如果不是絕對在意性能,那么了解底層和更細節的優(yōu)化沒(méi)有必要。這句話(huà)在很多時(shí)候是恰當的,因為很多時(shí)候復雜的底層邏輯必須包起來(lái),才能讓更高層的應用開(kāi)發(fā)復雜度可控。比如說(shuō),如果你就只需要開(kāi)發(fā)一個(gè) APP 或者網(wǎng)站,可能并沒(méi)有必要關(guān)注匯編細節,關(guān)注編譯器如何優(yōu)化你的代碼——畢竟在蘋(píng)果或者安卓上很多優(yōu)化在底層就做好了。

那么,了解底層的 TLS 和應用層的 Nginx 延遲優(yōu)化有什么關(guān)系呢?

答案是多數情況下,優(yōu)化網(wǎng)絡(luò )延遲其實(shí)是在嘗試減少用戶(hù)和服務(wù)器之間的數據傳輸次數,也就是所謂的 roundtrip。由于物理限制,北京到云南的光速傳播差不多就是要跑 20 來(lái)毫秒,如果你不小心讓數據必須多次往返于北京和云南之間,那么必然延遲就上去了。

因此如果你需要優(yōu)化請求延遲,那么了解一點(diǎn)底層網(wǎng)絡(luò )的上下文則會(huì )大有裨益,很多時(shí)候甚至是你是否可以輕松理解一個(gè)優(yōu)化的關(guān)鍵。本文中我們不深入討論太多 TCP 或者 TLS 機制的細節,如果有興趣的話(huà)請參考 High Performance Browser Networking[4] 一書(shū),可以免費閱讀。

舉個(gè)例子,下圖中展示了如果你的服務(wù)啟用了 HTTPS,在開(kāi)始傳輸任何數據之前的數據傳輸情況。

睿智創(chuàng  )新RAIZ,一體化IT服務(wù)提供商
在傳輸數據前數據已經(jīng)跑了好幾個(gè)來(lái)回 roundtrip

可以看到,在你的用戶(hù)拿到他需要的數據前,底層的數據包就已經(jīng)在用戶(hù)和你的服務(wù)器之間跑了 3 個(gè)來(lái)回。

假設每次來(lái)回需要 28 毫秒的話(huà),用戶(hù)已經(jīng)等了 224 毫秒之后才開(kāi)始接收數據。

同時(shí)這個(gè) 28 毫秒其實(shí)是非常樂(lè )觀(guān)的假設,在國內電信、聯(lián)通和移動(dòng)以及各種復雜的網(wǎng)絡(luò )狀況下,用戶(hù)與服務(wù)器之間的延遲更不可控。另一方面,通常一個(gè)網(wǎng)頁(yè)需要數十個(gè)請求,這些請求不一定可以全部并行,因此幾十乘以 224 毫秒,頁(yè)面打開(kāi)可能就是數秒之后了。

所以,原則上如果可能的話(huà),我們需要盡量減少用戶(hù)和服務(wù)器之間的往返程 (roundtrip),在下文的設置中,對于每個(gè)設置我們會(huì )討論為什么這個(gè)設置有可能幫助減少往返程。

Nginx 中的 TLS 設置

那么在 Nginx 設置中,怎樣調整參數會(huì )減少延遲呢?

開(kāi)啟 HTTP/2

HTTP/2 標準是從 Google 的 SPDY 上進(jìn)行的改進(jìn),比起 HTTP 1.1 提升了不少性能,尤其是需要并行多個(gè)請求的時(shí)候可以顯著(zhù)減少延遲。在現在的網(wǎng)絡(luò )上,一個(gè)網(wǎng)頁(yè)平均需要請求幾十次,而在 HTTP 1.1 時(shí)代瀏覽器能做的就是多開(kāi)幾個(gè)連接(通常是 6 個(gè))進(jìn)行并行請求,而 HTTP 2 中可以在一個(gè)連接中進(jìn)行并行請求。HTTP 2 原生支持多個(gè)并行請求,因此大大減少了順序執行的請求的往返程,可以首要考慮開(kāi)啟。

如果你想自己看一下 HTTP 1.1 和 HTTP 2.0 的速度差異,可以試一下:https://www.httpvshttps.com/。我的網(wǎng)絡(luò )測試下來(lái) HTTP/2 比 HTTP 1.1 快了 66%。

睿智創(chuàng  )新RAIZ,一體化IT服務(wù)提供商
HTTP 1.1 與 HTTP 2.0 速度對比

在 Nginx 中開(kāi)啟 HTTP 2.0 非常簡(jiǎn)單,只需要增加一個(gè) http2 標志即可

listen 443 ssl;

# 改為
listen 443 ssl http2;

如果你擔心你的用戶(hù)用的是舊的客戶(hù)端,比如 Python 的 requests,暫時(shí)還不支持 HTTP 2 的話(huà),那么其實(shí)不用擔心。如果用戶(hù)的客戶(hù)端不支持 HTTP 2,那么連接會(huì )自動(dòng)降級為 HTTP 1.1,保持了后向兼容。因此,所有使用舊 Client 的用戶(hù),仍然不受影響,而新的客戶(hù)端則可以享受 HTTP/2 的新特性。

如何確認你的網(wǎng)站或者 API 開(kāi)啟了 HTTP 2

在 Chrome 中打開(kāi)開(kāi)發(fā)者工具,點(diǎn)開(kāi) Protocol 之后在所有的請求中都可以看到請求用的協(xié)議了。如果 protocol 這列的值是 h2 的話(huà),那么用的就是 HTTP 2 了

睿智創(chuàng  )新RAIZ,一體化IT服務(wù)提供商
用 Chrome 確認 HTTP/2 已經(jīng)打開(kāi)

當然另一個(gè)辦法是直接用 curl 如果返回的 status 前有 HTTP/2 的話(huà)自然也就是 HTTP/2 開(kāi)啟了。

?  ~ curl --http2 -I https://kalasearch.cn
HTTP/2 403
server: Tengine
content-type: application/xml
content-length: 264
date: Tue, 22 Dec 2020 18:38:46 GMT
x-oss-request-id: 5FE23D363ADDB93430197043
x-oss-cdn-auth: success
x-oss-server-time: 0
x-alicdn-da-ups-status: endOs,0,403
via: cache13.l2et2[148,0], cache10.l2ot7[291,0], cache4.us13[360,0]
timing-allow-origin: *
eagleid: 2ff6169816086623266688093e

調整 Cipher 優(yōu)先級

盡量挑選更新更快的 Cipher,有助于減少延遲[5]:

# 手動(dòng)啟用 cipher 列表
ssl_prefer_server_ciphers on;# prefer a list of ciphers to prevent old and slow ciphers
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'

啟用 OCSP Stapling

在國內這可能是對使用 Let's Encrypt 證書(shū)的服務(wù)或網(wǎng)站影響最大的延遲優(yōu)化了。如果不啟用 OCSP Stapling 的話(huà),在用戶(hù)連接你的服務(wù)器的時(shí)候,有時(shí)候需要去驗證證書(shū)。而因為一些不可知的原因(這個(gè)就不說(shuō)穿了)Let's Encrypt 的驗證服務(wù)器并不是非常通暢[6],因此可以造成有時(shí)候數秒甚至十幾秒延遲的問(wèn)題[7],這個(gè)問(wèn)題在 iOS 設備上特別嚴重

解決這個(gè)問(wèn)題的方法有兩個(gè):

  1. 不使用 Let's Encrypt,可以嘗試替換為阿里云提供的免費 DV 證書(shū)
  2. 開(kāi)啟 OCSP Stapling

開(kāi)啟了 OCSP Stapling 的話(huà),跑到證書(shū)驗證這一步可以省略掉。省掉一個(gè) roundtrip,特別是網(wǎng)絡(luò )狀況不可控的 roundtrip,可能可以將你的延遲大大減少。

在 Nginx 中啟用 OCSP Stapling 也非常簡(jiǎn)單,只需要設置:

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/full_chain.pem;

如何檢測 OCSP Stapling 是否已經(jīng)開(kāi)啟?

可以通過(guò)以下命令

openssl s_client -connect test.kalasearch.cn:443 -servername kalasearch.cn -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"

來(lái)測試。如果結果為

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

則表明已經(jīng)開(kāi)啟。參考 HTTPS 在 iPhone 上慢的問(wèn)題[8] 一文。

調整 ssl_buffer_size

ssl_buffer_size 控制在發(fā)送數據時(shí)的 buffer 大小,默認設置是 16k。這個(gè)值越小,則延遲越小,而添加的報頭之類(lèi)會(huì )使 overhead 會(huì )變大,反之則延遲越大,overhead 越小。

因此如果你的服務(wù)是 REST API[9] 或者網(wǎng)站的話(huà),將這個(gè)值調小可以減小延遲和 TTFB,但如果你的服務(wù)器是用來(lái)傳輸大文件的,那么可以維持 16k。關(guān)于這個(gè)值的討論和更通用的 TLS Record Size 的討論,可以參考:Best value for nginx's ssl*buffer*size option[10]

如果是網(wǎng)站或者 REST API,建議值為 4k,但是這個(gè)值的最佳取值顯然會(huì )因為數據的不同而不一樣,因此請嘗試 2 - 16k 間不同的值。在 Nginx 中調整這個(gè)值也非常容易

ssl_buffer_size 4k;

啟用 SSL Session 緩存

啟用 SSL Session 緩存可以大大減少 TLS 的反復驗證,減少 TLS 握手的 roundtrip。雖然 session 緩存會(huì )占用一定內存,但是用 1M 的內存就可以緩存 4000 個(gè)連接,可以說(shuō)是非常非常劃算的。同時(shí),對于絕大多數網(wǎng)站和服務(wù),要達到 4000 個(gè)同時(shí)連接本身就需要非常非常大的用戶(hù)基數,因此可以放心開(kāi)啟。

這里 ssl_session_cache 設置為使用 50M 內存,以及 4 小時(shí)的連接超時(shí)關(guān)閉時(shí)間 ssl_session_timeout

# Enable SSL cache to speed up for return visitors
ssl_session_cache shared:SSL:50m; # speed up first time. 1m ~= 4000 connections
ssl_session_timeout 4h;

卡拉搜索如何減少 30% 的請求延遲

卡拉搜索是國內的 Algolia[11],致力于幫助開(kāi)發(fā)者快速搭建即時(shí)搜索功能(instant search),做國內最快最易用的搜索即服務(wù)。

開(kāi)發(fā)者接入后,所有搜索請求通過(guò)卡拉 API 即可直接返回給終端用戶(hù)。為了讓用戶(hù)有即時(shí)搜索的體驗,我們需要在用戶(hù)每次擊鍵后極短的時(shí)間內(通常是 100ms 到 200ms)將結果返回給用戶(hù)。因此每次搜索需要可以達到 50 毫秒以?xún)鹊囊嫣幚頃r(shí)間和 200 毫秒以?xún)鹊亩藢Χ藭r(shí)間。

我們用豆瓣電影的數據做了一個(gè)電影搜索的 Demo,如果感興趣的話(huà)歡迎體驗一下即時(shí)搜索,嘗試一下搜索“無(wú)間道”或者“大話(huà)西游”體驗一下速度和相關(guān)度:https://movies-demo.kalasearch.cn/

對于每個(gè)請求只有 100 到 200 毫秒的延遲預算,我們必須把每一步的延遲都考慮在內。

簡(jiǎn)化一下,每個(gè)搜索請求需要經(jīng)歷的延遲有

睿智創(chuàng  )新RAIZ,一體化IT服務(wù)提供商
卡拉搜索的端對端延遲圖示

總延遲 = 用戶(hù)請求到達服務(wù)器(T1) + 反代處理(Nginx T2) + 數據中心延遲(T3) + 服務(wù)器處理 (卡拉引擎 T4) + 用戶(hù)請求返回(T3+T1)

在上述延遲中,T1 只與用戶(hù)與服務(wù)器的物理距離相關(guān),而 T3 非常?。▍⒖?span style="font-weight: bold; color: rgb(235, 97, 97);">Jeff Dean Number[12])可以忽略不計。

所以我們能控制的大致只有 T2 和 T4,即 Nginx 服務(wù)器的處理時(shí)間和卡拉的引擎處理時(shí)間。

Nginx 在這里作為反向代理,處理一些安全、流量控制和 TLS 的邏輯,而卡拉的引擎則是一個(gè)在 Lucene 基礎上的倒排引擎。

我們首先考慮的第一個(gè)可能性是:延遲是不是來(lái)自卡拉引擎呢?

在下圖展示的 Grafana 儀表盤(pán)[13]中,我們看到除了幾個(gè)時(shí)不時(shí)的慢查詢(xún),搜索的 95% 服務(wù)器處理延遲小于 20 毫秒。對比同樣的數據集上 benchmark 的 Elastic Search 引擎的 P95 搜索延遲則在 200 毫秒左右,所以排除了引擎速度慢的可能。

睿智創(chuàng  )新RAIZ,一體化IT服務(wù)提供商
Search Grafana

而在阿里云監控中,我們設置了從全國各地向卡拉服務(wù)器發(fā)送搜索請求。我們終于發(fā)現 SSL 處理時(shí)間時(shí)常會(huì )超過(guò) 300 毫秒,也就是說(shuō)在 T2 這一步,光處理 TLS 握手之類(lèi)的事情,Nginx 已經(jīng)用掉了我們所有的請求時(shí)間預算。

同時(shí)檢查之后我們發(fā)現,在蘋(píng)果設備上搜索速度格外慢,特別是第一次訪(fǎng)問(wèn)的設備。因此我們大致判斷應該是因為我們使用的 Let's Encrypt 證書(shū)的問(wèn)題。

我們按照上文中的步驟對 Nginx 設置進(jìn)行了調整,并將步驟總結出來(lái)寫(xiě)了這篇文章。在調整了 Nginx TLS 的設置后,SSL 時(shí)間從平均的 140ms 降低到了 110ms 左右(全國所有省份聯(lián)通和移動(dòng)測試點(diǎn)),同時(shí)蘋(píng)果設備上首次訪(fǎng)問(wèn)慢的問(wèn)題也消失了。

睿智創(chuàng  )新RAIZ,一體化IT服務(wù)提供商
調整后延遲

在調整過(guò)后,全國范圍內測試的搜索延遲降低到了 150 毫秒左右。

總結

調整 Nginx 中的 TLS 設置對于使用 HTTPS 的服務(wù)和網(wǎng)站延遲有非常大的影響。本文中總結了 Nginx 中與 TLS 相關(guān)的設置,詳細討論各個(gè)設置可能對延遲的影響,并給出了調整建議。之后我們會(huì )繼續討論 HTTP/2 對比 HTTP 1.x 有哪些具體改進(jìn),以及在 REST API 使用 HTTP/2 有哪些優(yōu)缺點(diǎn),請繼續關(guān)注。


我要咨詢(xún)