如何用 Nginx 實現百萬併發連線?| 極客時間

語言: CN / TW / HK

大家好,我是 《Nginx 核心知識 100 講》 課程講師–陶輝,有幸能借這個文章的機會,和大家分享 Nginx 的重難點: Nginx 究竟是如何支援百萬併發連線的?

其實,大家學習 Nginx,最大的動力是想讓自己的產品在支援高併發請求的同時保持高效的服務。那除了掌握 Nginx,可能沒有其他更好的選擇。

在學習 Nginx 路上,你可能會遇到很多阻礙,比如:

  • 當你在做擴充套件功能時發現新增的指令 Nginx 不支援,不知道如何增加 Nginx 模組,如何分析 access 日誌
  • Nginx 裡的 Master 程序和 Worker 程序到底是怎樣的?
  • Nginx 是如何在高併發下使使用者無感知的熱部署?
  • cache 的快取問題
  • 不清楚 OpenResty 的 Lua 模組如何與 Nginx 結合使用,以及這個對 Nginx 效能的影響
  • ……

其實,這些問題我在課程裡都有做系統性的講解,有些是用 3-4 個影片來完整地講解一個知識點,有些疑惑你單看目錄就能找到答案。不過我還是希望大家能從 0 開始,跟著我係統性地把這套影片學完,那麼百萬併發下的 Nginx 效能優化之道,你基本就掌握了。

今天,我們就直達要點,來看看 Nginx 究竟是如何支援百萬併發連線的?

1、搞清楚 TCP 連線的併發

首先是對於 TCP 連線併發的掌握。不少同學認為,由於埠最大範圍是 65535,所以 Nginx 的最大併發連線數就是 65535。實際上,Nginx 的併發連線可以達到百萬或者千萬級,原因是 TCP 連線是個四元組,它包括(源 IP、源埠、目的 IP、目的埠)。

我們以 32 位的 IPv4 地址為例,如果不考慮資源限制,理論上它的最大併發連線數是 2^(32+16+32+16) 個(因為 IP 為 32 位,埠號為 16 位),遠遠大於 65535。

顯然,在如此巨大的併發連線數下,再細小的問題都可能會被放大很多倍。所以,我們要精細化配置 Linux 中的 TCP 選項(TCP 層由作業系統核心實現),優化建立連線的速度,防禦針對建立連線過程的種種惡意攻擊。

2、掌握磁碟 IO 優化

眾所周知,磁碟是計算機體系中最慢的裝置,它遠遠慢於 CPU 計算速度、記憶體的存取、網路的傳輸等。正如我們所熟悉的短板理論,最慢的磁碟,很容易成為伺服器效能的瓶頸。

因此,雖然在很多場景下,Nginx 最主要的工作是協議解析與網路傳輸(如反向代理),但少量的磁碟操作,卻也可能大幅度降低 Nginx 效能。

所以,我們要在瞭解磁碟特點及作業系統 API 的基礎上,嘗試減少磁碟操作,或者優化磁碟操作。比如,在每次工作前,你可以先問一下自己:

  • access.log 是不是可以批量寫入磁碟?
  • 是不是可以壓縮後再寫入,以減少傳輸位元組數?
  • 或者是,乾脆使用 syslog 協議,走網路寫入其他伺服器?

當 Nginx 用於 CDN 或者靜態資源伺服器時,大量的讀操作下,我們需要考慮,對大檔案採用 DirectIO 以減少無謂的快取記憶體操作;而在 AIO 失效時,還要考慮基於執行緒池來應對阻塞等問題。

3、弄懂優化記憶體分配

Nginx 會確保每一個連線消耗的記憶體最小化,這也是 Nginx 支援高併發的關鍵。由於記憶體資源有限,併發數卻數以百萬計,這就要求在 Nginx 使用者態下,每個連線所用的記憶體都應遵循以下幾個原則:

  • 夠用就好;
  • 延遲分配;
  • 減少記憶體碎片等等。

所以,弄清楚優化記憶體分配,首先你就得明白記憶體工作原理。在「第二章:Nginx 架構基礎」的「 第 36 講 | 記憶體池對效能的影響 」中我介紹過記憶體池的意義,在「第三章:詳解 HTTP 模組」的「 第 45 講 | 處理 HTTP 請求頭部的流程 」中提及過處理請求過程中基於記憶體池分配的記憶體大小。

不過,TCP 是由作業系統核心實現的,所以 TCP 協議處理相關的記憶體,需要通過配置核心引數來控制,「第五章:Nginx 的系統層效能優化」對此有深入介紹。

推薦你看看以下的內容,看你是否已掌握 Nginx 效能優化中的重要部分:TCP 協議。

第 120 講 | 效能優化方法論

第 128 講 | TCP 協議的 keepalive 功能

當然,分配記憶體的速度也非常重要。googleperftool 提供的 tcmalloc,就是為了替代預設的 glibc 庫,用來分配記憶體的工具。它在多執行緒分配小塊記憶體的速度上有很大優勢。

4、高效使用 CPU 的負載均衡

提升效能工作中,最重要的一環,就是提升 CPU 的計算速度。不過,在如今動則 32 核、64 核等的多核 CPU 架構下,提升 CPU 效率便複雜了很多。比如下面這幾個方面的問題:

  • 由於 CPU 有 1 級、2 級、3 級快取之分,並且每級快取的存取速度相差很大。所以,我們需要提升 CPU 快取的利用率,例如需要繫結程序與 CPU。
  • 新版本的核心通過 reuseport,高效地解決了“驚群”問題。但這一選項,卻需要我們顯式配置。
  • NUMA 架構解決了匯流排頻寬的束縛問題,但又引入了訪問部分主存過慢的問題。
  • 多佇列網絡卡可以提升 CPU 處理網路 packet 的效率,但它並不是萬能的,只在其適用場景下發揮作用。

總的來說,多核確實意味著更強大的計算力,但真正的銀彈並不存在。若想基於增加 CPU 核數獲得接近線性提升的計算力,我們還有許多工作要做。

完結寄語

《Nginx 核心知識 100 講》 已經完結,從預計 100 講的內容擴充到了 155 講,歷經 3 個月的課程錄製,才把我想交付給大家的知識點盡數講完。

雖然網上關於 Nginx 的使用介紹非常多,但存在著“僅從使用層面介紹,未深入原理未”、“未體系化的效能優化知識”等問題。 抱著想解決以上兩個問題,及讓大家系統化掌握 Nginx 的心,我從 HTTP 應用層、分散式叢集到硬體及作業系統核心優化等等層面,把 Nginx 的知識點體系化地解讀給大家。

大家若能跟著這一整套影片完整地學下來,必然能從 Nginx 的初級使用者成長為高階使用者,搭建起自己的 Nginx 知識全景圖。

學完課程後,你將獲得:

  1. 基礎知識詳解及核心架構剖析

  2. 搭建支援百萬高併發的 Nginx 服務

  3. 從核心優化到原始碼解讀的全方位拆解

  4. OpenResty + Nginx 開發實戰

戳此訂閱 / 試看

分享到: