操bb国片四区三区,亚洲一片内射无码,91短视频福利导航,蜜桃臀成人免费在线视频观看

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

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

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

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

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

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

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

TLS 握手和延遲

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

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

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

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

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

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

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

假設(shè)每次來回需要 28 毫秒的話,用戶已經(jīng)等了 224 毫秒之后才開始接收數(shù)據(jù)。

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

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

Nginx 中的 TLS 設(shè)置

那么在 Nginx 設(shè)置中,怎樣調(diào)整參數(shù)會減少延遲呢?

開啟 HTTP/2

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

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

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

在 Nginx 中開啟 HTTP 2.0 非常簡單,只需要增加一個 http2 標志即可

listen 443 ssl;

# 改為
listen 443 ssl http2;

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

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

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

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

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

?  ~ 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

調(diào)整 Cipher 優(yōu)先級

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

# 手動啟用 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

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

解決這個問題的方法有兩個:

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

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

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

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

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

可以通過以下命令

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

來測試。如果結(jié)果為

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

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

調(diào)整 ssl_buffer_size

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

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

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

ssl_buffer_size 4k;

啟用 SSL Session 緩存

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

這里 ssl_session_cache 設(shè)置為使用 50M 內(nèi)存,以及 4 小時的連接超時關(guān)閉時間 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% 的請求延遲

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

開發(fā)者接入后,所有搜索請求通過卡拉 API 即可直接返回給終端用戶。為了讓用戶有即時搜索的體驗,我們需要在用戶每次擊鍵后極短的時間內(nèi)(通常是 100ms 到 200ms)將結(jié)果返回給用戶。因此每次搜索需要可以達到 50 毫秒以內(nèi)的引擎處理時間和 200 毫秒以內(nèi)的端對端時間。

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

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

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

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

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

在上述延遲中,T1 只與用戶與服務(wù)器的物理距離相關(guān),而 T3 非常小(參考Jeff Dean Number[12])可以忽略不計。

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

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

我們首先考慮的第一個可能性是:延遲是不是來自卡拉引擎呢?

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

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

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

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

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

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

在調(diào)整過后,全國范圍內(nèi)測試的搜索延遲降低到了 150 毫秒左右。

總結(jié)

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


我要咨詢