- 為什么要優(yōu)化 Nginx HTTPS 延遲
- TLS 握手和延遲
- Nginx 中的 TLS 設置
- 卡拉搜索如何減少 30% 的請求延遲
- 總結(jié)
為什么要優(yōu)化 Nginx HTTPS 延遲
Nginx 常作為最常見的服務器,常被用作負載均衡 (Load Balancer)、反向代理 (Reverse Proxy),以及網(wǎng)關 (Gateway) 等等。一個配置得當?shù)?Nginx 服務器單機應該可以期望承受住 50K 到 80K 左右 [1]每秒的請求,同時將 CPU 負載在可控范圍內(nèi)。
但在很多時候,負載并不是需要首要優(yōu)化的重點。比如對于卡拉搜索來說,我們希望用戶在每次擊鍵的時候,可以體驗即時搜索的感覺,也就是說,每個搜索請求必須在 100ms - 200ms 的時間 內(nèi)端對端地返回給用戶,才能讓用戶搜索時沒有“卡頓”和“加載”。因此,對于我們來說,優(yōu)化請求延遲才是最重要的優(yōu)化方向。
這篇文章中,我們先介紹 Nginx 中的 TLS 設置有哪些與請求延遲可能相關,如何調(diào)整才能最大化加速。然后我們用優(yōu)化卡拉搜索 [2] Nginx 服務器的實例來分享如何調(diào)整 Nginx TLS/SSL 設置,為首次搜索的用戶提速 30% 左右。我們會詳細討論每一步我們做了一些什么優(yōu)化,優(yōu)化的動機和效果。希望可以對其它遇到類似問題的同學提供幫助。
照例,本文的 Nginx 設置文件放置于 github,歡迎直接使用: 高性能 Nginx HTTPS 調(diào)優(yōu) [3]
基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能
TLS 握手和延遲
很多時候開發(fā)者會認為:如果不是絕對在意性能,那么了解底層和更細節(jié)的優(yōu)化沒有必要。這句話在很多時候是恰當?shù)模驗楹芏鄷r候復雜的底層邏輯必須包起來,才能讓更高層的應用開發(fā)復雜度可控。比如說,如果你就只需要開發(fā)一個 APP 或者網(wǎng)站,可能并沒有必要關注匯編細節(jié),關注編譯器如何優(yōu)化你的代碼——畢竟在蘋果或者安卓上很多優(yōu)化在底層就做好了。
那么,了解底層的 TLS 和應用層的 Nginx 延遲優(yōu)化有什么關系呢?
答案是多數(shù)情況下,優(yōu)化網(wǎng)絡延遲其實是在嘗試減少用戶和服務器之間的數(shù)據(jù)傳輸次數(shù),也就是所謂的 roundtrip。由于物理限制,北京到云南的光速傳播差不多就是要跑 20 來毫秒,如果你不小心讓數(shù)據(jù)必須多次往返于北京和云南之間,那么必然延遲就上去了。
因此如果你需要優(yōu)化請求延遲,那么了解一點底層網(wǎng)絡的上下文則會大有裨益,很多時候甚至是你是否可以輕松理解一個優(yōu)化的關鍵。本文中我們不深入討論太多 TCP 或者 TLS 機制的細節(jié),如果有興趣的話請參考 High Performance Browser Networking [4] 一書,可以免費閱讀。
舉個例子,下圖中展示了如果你的服務啟用了 HTTPS,在開始傳輸任何數(shù)據(jù)之前的數(shù)據(jù)傳輸情況。
在傳輸數(shù)據(jù)前數(shù)據(jù)已經(jīng)跑了好幾個來回 roundtrip
可以看到,在你的用戶拿到他需要的數(shù)據(jù)前,底層的數(shù)據(jù)包就已經(jīng)在用戶和你的服務器之間跑了 3 個來回。
假設每次來回需要 28 毫秒的話,用戶已經(jīng)等了 224 毫秒之后才開始接收數(shù)據(jù)。
同時這個 28 毫秒其實是非常樂觀的假設,在國內(nèi)電信、聯(lián)通和移動以及各種復雜的網(wǎng)絡狀況下,用戶與服務器之間的延遲更不可控。另一方面,通常一個網(wǎng)頁需要數(shù)十個請求,這些請求不一定可以全部并行,因此幾十乘以 224 毫秒,頁面打開可能就是數(shù)秒之后了。
所以,原則上如果可能的話,我們需要盡量減少用戶和服務器之間的往返程 (roundtrip),在下文的設置中,對于每個設置我們會討論為什么這個設置有可能幫助減少往返程。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能
Nginx 中的 TLS 設置
那么在 Nginx 設置中,怎樣調(diào)整參數(shù)會減少延遲呢?
開啟 HTTP/2
HTTP/2 標準是從 Google 的 SPDY 上進行的改進,比起 HTTP 1.1 提升了不少性能,尤其是需要并行多個請求的時候可以顯著減少延遲。在現(xiàn)在的網(wǎng)絡上,一個網(wǎng)頁平均需要請求幾十次,而在 HTTP 1.1 時代瀏覽器能做的就是多開幾個連接(通常是 6 個)進行并行請求,而 HTTP 2 中可以在一個連接中進行并行請求。HTTP 2 原生支持多個并行請求,因此大大減少了順序執(zhí)行的請求的往返程,可以首要考慮開啟。
如果你想自己看一下 HTTP 1.1 和 HTTP 2.0 的速度差異,可以試一下:https://www.httpvshttps.com/。我的網(wǎng)絡測試下來 HTTP/2 比 HTTP 1.1 快了 66%。
HTTP 1.1 與 HTTP 2.0 速度對比
在 Nginx 中開啟 HTTP 2.0 非常簡單,只需要增加一個 http2 標志即可
listen443ssl;
#改為
listen443sslhttp2;
如果你擔心你的用戶用的是舊的客戶端,比如 Python 的 requests,暫時還不支持 HTTP 2 的話,那么其實不用擔心。如果用戶的客戶端不支持 HTTP 2,那么連接會自動降級為 HTTP 1.1,保持了后向兼容。因此,所有使用舊 Client 的用戶,仍然不受影響,而新的客戶端則可以享受 HTTP/2 的新特性。
如何確認你的網(wǎng)站或者 API 開啟了 HTTP 2
在 Chrome 中打開開發(fā)者工具,點開 Protocol
之后在所有的請求中都可以看到請求用的協(xié)議了。如果 protocol
這列的值是 h2
的話,那么用的就是 HTTP 2 了
用 Chrome 確認 HTTP/2 已經(jīng)打開
當然另一個辦法是直接用 curl
如果返回的 status 前有 HTTP/2
的話自然也就是 HTTP/2 開啟了。
?~curl--http2-Ihttps://kalasearch.cn
HTTP/2403
server:Tengine
content-type:application/xml
content-length:264
date:Tue,22Dec202018:38:46GMT
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_cipherson;#preferalistofcipherstopreventoldandslowciphers
ssl_ciphers'EECDH+AESGCMAES256+EECDH:AES256+EDH';
啟用 OCSP Stapling
在國內(nèi)這可能是對使用 Let's Encrypt 證書的服務或網(wǎng)站影響最大的延遲優(yōu)化了。如果不啟用 OCSP Stapling 的話,在用戶連接你的服務器的時候,有時候需要去驗證證書。而因為一些不可知的原因(這個就不說穿了)Let's Encrypt 的驗證服務器并不是非常通暢 [6],因此可以造成有時候數(shù)秒甚至十幾秒延遲的問題 [7],這個問題在 iOS 設備上特別嚴重
解決這個問題的方法有兩個:
- 不使用 Let's Encrypt,可以嘗試替換為阿里云提供的免費 DV 證書
- 開啟 OCSP Stapling
開啟了 OCSP Stapling 的話,跑到證書驗證這一步可以省略掉。省掉一個 roundtrip,特別是網(wǎng)絡狀況不可控的 roundtrip,可能可以將你的延遲大大減少。
在 Nginx 中啟用 OCSP Stapling 也非常簡單,只需要設置:
ssl_staplingon;
ssl_stapling_verifyon;
ssl_trusted_certificate/path/to/full_chain.pem;
如何檢測 OCSP Stapling 是否已經(jīng)開啟?
可以通過以下命令
openssls_client-connecttest.kalasearch.cn:443-servernamekalasearch.cn-status-tlsextdebug/dev/null2>&1|grep-i"OCSPresponse"
來測試。如果結(jié)果為
OCSPresponse:
OCSPResponseData:
OCSPResponseStatus:successful(0x0)
ResponseType:BasicOCSPResponse
則表明已經(jīng)開啟。參考 HTTPS 在 iPhone 上慢的問題 [8] 一文。
調(diào)整 ssl_buffer_size
ssl_buffer_size
控制在發(fā)送數(shù)據(jù)時的 buffer 大小,默認設置是 16k。這個值越小,則延遲越小,而添加的報頭之類會使 overhead 會變大,反之則延遲越大,overhead 越小。
因此如果你的服務是 REST API [9] 或者網(wǎng)站的話,將這個值調(diào)小可以減小延遲和 TTFB,但如果你的服務器是用來傳輸大文件的,那么可以維持 16k。關于這個值的討論和更通用的 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_size4k;
啟用 SSL Session 緩存
啟用 SSL Session 緩存可以大大減少 TLS 的反復驗證,減少 TLS 握手的 roundtrip。雖然 session 緩存會占用一定內(nèi)存,但是用 1M 的內(nèi)存就可以緩存 4000 個連接,可以說是非常非常劃算的。同時,對于絕大多數(shù)網(wǎng)站和服務,要達到 4000 個同時連接本身就需要非常非常大的用戶基數(shù),因此可以放心開啟。
這里 ssl_session_cache
設置為使用 50M 內(nèi)存,以及 4 小時的連接超時關閉時間 ssl_session_timeout
#EnableSSLcachetospeedupforreturnvisitors
ssl_session_cacheshared50m;#speedupfirsttime.1m~=4000connections
ssl_session_timeout4h;
卡拉搜索如何減少 30% 的請求延遲
卡拉搜索是國內(nèi)的 Algolia [11],致力于幫助開發(fā)者快速搭建即時搜索功能(instant search),做國內(nèi)最快最易用的搜索即服務。
開發(fā)者接入后,所有搜索請求通過卡拉 API 即可直接返回給終端用戶。為了讓用戶有即時搜索的體驗,我們需要在用戶每次擊鍵后極短的時間內(nèi)(通常是 100ms 到 200ms)將結(jié)果返回給用戶。因此每次搜索需要可以達到 50 毫秒以內(nèi)的引擎處理時間和 200 毫秒以內(nèi)的端對端時間。
我們用豆瓣電影的數(shù)據(jù)做了一個電影搜索的 Demo,如果感興趣的話歡迎體驗一下即時搜索,嘗試一下搜索“無間道”或者“大話西游”體驗一下速度和相關度:https://movies-demo.kalasearch.cn/
對于每個請求只有 100 到 200 毫秒的延遲預算,我們必須把每一步的延遲都考慮在內(nèi)。
簡化一下,每個搜索請求需要經(jīng)歷的延遲有
卡拉搜索的端對端延遲圖示
總延遲 = 用戶請求到達服務器(T1) + 反代處理(Nginx T2) + 數(shù)據(jù)中心延遲(T3) + 服務器處理 (卡拉引擎 T4) + 用戶請求返回(T3+T1)
在上述延遲中,T1 只與用戶與服務器的物理距離相關,而 T3 非常?。▍⒖?strong style="color:#0e88eb;">Jeff Dean Number [12])可以忽略不計。
所以我們能控制的大致只有 T2 和 T4,即 Nginx 服務器的處理時間和卡拉的引擎處理時間。
Nginx 在這里作為反向代理,處理一些安全、流量控制和 TLS 的邏輯,而卡拉的引擎則是一個在 Lucene 基礎上的倒排引擎。
我們首先考慮的第一個可能性是:延遲是不是來自卡拉引擎呢?
在下圖展示的 Grafana 儀表盤 [13]中,我們看到除了幾個時不時的慢查詢,搜索的 95% 服務器處理延遲小于 20 毫秒。對比同樣的數(shù)據(jù)集上 benchmark 的 Elastic Search 引擎的 P95 搜索延遲則在 200 毫秒左右,所以排除了引擎速度慢的可能。
Search Grafana
而在阿里云監(jiān)控中,我們設置了從全國各地向卡拉服務器發(fā)送搜索請求。我們終于發(fā)現(xiàn) SSL 處理時間時常會超過 300 毫秒,也就是說在 T2 這一步,光處理 TLS 握手之類的事情,Nginx 已經(jīng)用掉了我們所有的請求時間預算。
同時檢查之后我們發(fā)現(xiàn),在蘋果設備上搜索速度格外慢,特別是第一次訪問的設備。因此我們大致判斷應該是因為我們使用的 Let's Encrypt 證書的問題。
我們按照上文中的步驟對 Nginx 設置進行了調(diào)整,并將步驟總結(jié)出來寫了這篇文章。在調(diào)整了 Nginx TLS 的設置后,SSL 時間從平均的 140ms 降低到了 110ms 左右(全國所有省份聯(lián)通和移動測試點),同時蘋果設備上首次訪問慢的問題也消失了。
調(diào)整后延遲
在調(diào)整過后,全國范圍內(nèi)測試的搜索延遲降低到了 150 毫秒左右。
總結(jié)
調(diào)整 Nginx 中的 TLS 設置對于使用 HTTPS 的服務和網(wǎng)站延遲有非常大的影響。本文中總結(jié)了 Nginx 中與 TLS 相關的設置,詳細討論各個設置可能對延遲的影響,并給出了調(diào)整建議。之后我們會繼續(xù)討論 HTTP/2 對比 HTTP 1.x 有哪些具體改進,以及在 REST API 使用 HTTP/2 有哪些優(yōu)缺點,請繼續(xù)關注。
審核編輯 :李倩
-
cpu
+關注
關注
68文章
10807瀏覽量
210852 -
服務器
+關注
關注
12文章
8964瀏覽量
85087 -
nginx
+關注
關注
0文章
142瀏覽量
12154
原文標題:優(yōu)化 Nginx HTTPS 延遲 - 如何讓Nginx提速 30%的?
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論