主頁 > 後端開發 > 高性能 Nginx HTTPS 調優 - 如何為 HTTPS 提速 30%

高性能 Nginx HTTPS 調優 - 如何為 HTTPS 提速 30%

2021-02-23 06:15:32 後端開發

為什么要優化 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,在開始傳輸任何資料之前的資料傳輸情況,
    可以看到,在你的用戶拿到他需要的資料前,底層的資料包就已經在用戶和你的服務器之間跑了 3 個來回, 假設每次來回需要 28 毫秒的話,用戶已經等了 224 毫秒之后才開始接收資料, 同時這個 28 毫秒其實是非常樂觀的假設,在國內電信、聯通和移動以及各種復雜的網路狀況下,用戶與服務器之間的延遲更不可控,另一方面,通常一個網頁需要數十個請求,這些請求不一定可以全部并行,因此幾十乘以 224 毫秒,頁面打開可能就是數秒之后了, 所以,原則上如果可能的話,我們需要盡量減少用戶和服務器之間的往返程 (roundtrip),在下文的設定中,對于每個設定我們會討論為什么這個設定有可能幫助減少往返程,

Nginx 中的 TLS 設定

  那么在 Nginx 設定中,怎樣調整引數會減少延遲呢?

開啟 HTTP/2

HTTP/2 標準是從 Google 的 SPDY 上進行的改進,比起 HTTP 1.1 提升了不少性能,尤其是需要并行多個請求的時候可以顯著減少延遲,在現在的網路上,一個網頁平均需要請求幾十次,而在 HTTP 1.1 時代瀏覽器能做的就是多開幾個連接(通常是 6 個)進行并行請求,而 HTTP 2 中可以在一個連接中進行并行請求,HTTP 2 原生支持多個并行請求,因此大大減少了順序執行的請求的往返程,可以首要考慮開啟, 如果你想自己看一下 HTTP 1.1 和 HTTP 2.0 的速度差異,可以試一下:https://www.httpvshttps.com/,我的網路測驗下來 HTTP/2 比 HTTP 1.1 快了 66%, 在 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 了 當然另一個辦法是直接用 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

調整 Cipher 優先級

盡量挑選更新更快的 Cipher,有助于減少延遲:
# 手動啟用 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 證書的服務或網站影響最大的延遲優化了,如果不啟用 OCSP Stapling 的話,在用戶連接你的服務器的時候,有時候需要去驗證證書,而因為一些不可知的原因(這個就不說穿了)Let's Encrypt 的驗證服務器并不是非常通暢,因此可以造成有時候數秒甚至十幾秒延遲的問題,這個問題在 iOS 設備上特別嚴重 解決這個問題的方法有兩個:
  1. 不使用 Let's Encrypt,可以嘗試替換為阿里云提供的免費 DV 證書
  2. 開啟 OCSP Stapling
開啟了 OCSP Stapling 的話,跑到證書驗證這一步可以省略掉,省掉一個 roundtrip,特別是網路狀況不可控的 roundtrip,可能可以將你的延遲大大減少, 在 Nginx 中啟用 OCSP Stapling 也非常簡單,只需要設定:
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/full_chain.pem;

如何檢測 OCSP Stapling 是否已經開啟?

可以通過以下命令
openssl s_client -connect test.kalasearch.cn:443 -servername kalasearch.cn -status -tlsextdebug < /dev/null 2>&1 | grep -i "OCSP response"
來測驗,如果結果為
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 visitors
ssl_session_cache   shared:SSL:50m; # speed up first time. 1m ~= 4000 connections
ssl_session_timeout 4h;

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

  卡拉搜索是國內的 Algolia,致力于幫助開發者快速搭建即時搜索功能(instant search),做國內最快最易用的搜索即服務, 開發者接入后,所有搜索請求通過卡拉 API 即可直接回傳給終端用戶,為了讓用戶有即時搜索的體驗,我們需要在用戶每次擊鍵后極短的時間內(通常是 100ms 到 200ms)將結果回傳給用戶,因此每次搜索需要可以達到 50 毫秒以內的引擎處理時間和 200 毫秒以內的端對端時間,
我們用豆瓣電影的資料做了一個電影搜索的 Demo,如果感興趣的話歡迎體驗一下即時搜索,嘗試一下搜索“無間道”或者“大話西游”體驗一下速度和相關度:https://movies-demo.kalasearch.cn/
對于每個請求只有 100 到 200 毫秒的延遲預算,我們必須把每一步的延遲都考慮在內, 簡化一下,每個搜索請求需要經歷的延遲有 總延遲 = 用戶請求到達服務器(T1) + 反代處理(Nginx T2) + 資料中心延遲(T3) + 服務器處理 (卡拉引擎 T4) + 用戶請求回傳(T3+T1) 在上述延遲中,T1 只與用戶與服務器的物理距離相關,而 T3 非常小(參考Jeff Dean Numbe)可以忽略不計, 所以我們能控制的大致只有 T2 和 T4,即 Nginx 服務器的處理時間和卡拉的引擎處理時間, Nginx 在這里作為反向代理,處理一些安全、流量控制和 TLS 的邏輯,而卡拉的引擎則是一個在 Lucene 基礎上的倒排引擎, 我們首先考慮的第一個可能性是:延遲是不是來自卡拉引擎呢? 在下圖展示的 Grafana 儀表盤中,我們看到除了幾個時不時的慢查詢,搜索的 95% 服務器處理延遲小于 20 毫秒,對比同樣的資料集上 benchmark 的 Elastic Search 引擎的 P95 搜索延遲則在 200 毫秒左右,所以排除了引擎速度慢的可能, 而在阿里云監控中,我們設定了從全國各地向卡拉服務器發送搜索請求,我們終于發現 SSL 處理時間時常會超過 300 毫秒,也就是說在 T2 這一步,光處理 TLS 握手之類的事情,Nginx 已經用掉了我們所有的請求時間預算, 同時檢查之后我們發現,在蘋果設備上搜索速度格外慢,特別是第一次訪問的設備,因此我們大致判斷應該是因為我們使用的 Let's Encrypt 證書的問題, 我們按照上文中的步驟對 Nginx 設定進行了調整,并將步驟總結出來寫了這篇文章,在調整了 Nginx TLS 的設定后,SSL 時間從平均的 140ms 降低到了 110ms 左右(全國所有省份聯通和移動測驗點),同時蘋果設備上首次訪問慢的問題也消失了,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/262357.html

標籤:Java

上一篇:學習筆記

下一篇:G1 與 CMS 兩個垃圾收集器的對比

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more