Nginx 核心架構(gòu)設(shè)計,揭秘其為何能支持高并發(fā)爆存?

作者:JeffreyC
https://segmentfault.com/a/1190000018261096

Nginx 作為業(yè)界知名的高性能服務(wù)器,被廣泛的應(yīng)用蝗砾。它的高性能正是由于其優(yōu)秀的架構(gòu)設(shè)計先较,其架構(gòu)主要包括這幾點:模塊化設(shè)計、事件驅(qū)動架構(gòu)悼粮、請求的多階段異步處理闲勺、管理進程與多工作進程設(shè)計、內(nèi)存池的設(shè)計扣猫,以下內(nèi)容依次進行說明菜循。

模塊化設(shè)計

高度模塊化的設(shè)計是 Nginx 的架構(gòu)基礎(chǔ)。在 Nginx 中申尤,除了少量的核心代碼癌幕,其他一切皆為模塊。

所有模塊間是分層次昧穿、分類別的勺远,Nginx 官方共有五大類型的模塊:核心模塊、配置模塊时鸵、事件模塊胶逢、HTTP 模塊、mail 模塊。它們之間的關(guān)系如下:

image

在這 5 種模塊中初坠,配置模塊和核心模塊是與 Nginx 框架密切相關(guān)的和簸。而事件模塊則是 HTTP 模塊和 mail 模塊的基礎(chǔ)。HTTP 模塊和 mail 模塊的“地位”類似碟刺,它們都是更關(guān)注于應(yīng)用層面比搭。

事件驅(qū)動架構(gòu)

事件驅(qū)動架構(gòu),簡單的說就是由一些事件發(fā)生源來產(chǎn)生事件南誊,由事件收集器來收集身诺、分發(fā)事件,然后由事件處理器來處理這些事件(事件處理器需要先在事件收集器里注冊自己想處理的事件)抄囚。

對于 Nginx 服務(wù)器而言霉赡,一般由網(wǎng)卡、磁盤產(chǎn)生事件幔托,Nginx 中的事件模塊將負(fù)責(zé)事件的收集穴亏、分發(fā)操作;而所有的模塊都可能是事件消費者重挑,它們首先需要向事件模塊注冊感興趣的事件類型嗓化,這樣,在有事件產(chǎn)生時谬哀,事件模塊會把事件分發(fā)到相應(yīng)的模塊中進行處理刺覆。

對于傳統(tǒng) web 服務(wù)器(如 Apache)而言,采用的所謂事件驅(qū)動往往局限在 TCP 連接建立史煎、關(guān)閉事件上谦屑,一個連接建立以后,在其關(guān)閉之前的所有操作都不再是事件驅(qū)動篇梭,這時會退化成按順序執(zhí)行每個操作的批處理模式氢橙,這樣每個請求在連接建立后都將始終占用著系統(tǒng)資源,直到關(guān)閉才會釋放資源恬偷。這種請求占用著服務(wù)器資源等待處理的模式會造成服務(wù)器資源極大的浪費悍手。如下圖所示,傳統(tǒng) web 服務(wù)器往往把一個進程或線程作為時間消費者袍患,當(dāng)一個請求產(chǎn)生的事件被該進程處理時坦康,直到這個請求處理結(jié)束時,進程資源都將被這一請求所占用协怒。比較典型的例子如 Apache 同步阻塞的多進程模式就是這樣的涝焙。

傳統(tǒng) web 服務(wù)器處理事件的簡單模型(矩形代表進程):

image

Nginx 采用事件驅(qū)動架構(gòu)處理業(yè)務(wù)的方式與傳統(tǒng)的 web 服務(wù)器是不同的。它不使用進程或者線程來作為事件消費者孕暇,所謂的事件消費者只能是某個模塊仑撞。只有事件收集赤兴、分發(fā)器才有資格占用進程資源,它們會在分發(fā)某個事件時調(diào)用事件消費模塊使用當(dāng)前占用的進程資源隧哮,如下圖所示桶良,該圖中列出了 5 個不同的事件,在事件收集沮翔、分發(fā)者進程的一次處理過程中陨帆,這 5 個事件按照順序被收集后,將開始使用當(dāng)前進程分發(fā)事件采蚀,從而調(diào)用相應(yīng)的事件消費者來處理事件疲牵。當(dāng)然,這種分發(fā)榆鼠、調(diào)用也是有序的纲爸。

Nginx 處理事件的簡單模型:

image

由上圖可以看出,處理請求事件時妆够,Nginx 的事件消費者只是被事件分發(fā)者進程短期調(diào)用而已识啦,這種設(shè)計使得網(wǎng)絡(luò)性能、用戶感知的請求時延都得到了提升神妹,每個用戶的請求所產(chǎn)生的事件會及時響應(yīng)颓哮,整個服務(wù)器的網(wǎng)絡(luò)吞吐量都會由于事件的及時響應(yīng)而增大。當(dāng)然鸵荠,這也帶來一定的要求冕茅,即每個事件消費者都不能有阻塞行為,否則將會由于長時間占用事件分發(fā)者進程而導(dǎo)致其他事件得不到及時響應(yīng)腰鬼,Nginx 的非阻塞特性就是由于它的模塊都是滿足這個要求的嵌赠。

請求的多階段異步處理

多階段異步處理請求與事件驅(qū)動架構(gòu)是密切相關(guān)的,也就是說熄赡,請求的多階段異步處理只能基于事件驅(qū)動架構(gòu)實現(xiàn)。多階段異步處理就是把一個請求的處理過程按照事件的觸發(fā)方式劃分為多個階段齿税,每個階段都可以由事件收集彼硫、分發(fā)器來觸發(fā)。

處理獲取靜態(tài)文件的 HTTP 請求時切分的階段及各階段的觸發(fā)事件如下所示:

image

這個例子中凌箕,該請求大致分為 7 個階段拧篮,這些階段是可以重復(fù)發(fā)生的,因此牵舱,一個下載靜態(tài)資源請求可能會由于請求數(shù)據(jù)過大串绩,網(wǎng)速不穩(wěn)定等因素而被分解為成百上千個上圖所列出的階段。

異步處理和多階段是相輔相成的芜壁,只有把請求分為多個階段礁凡,才有所謂的異步處理高氮。當(dāng)一個時間被分發(fā)到事件消費者中進行處理時,事件消費者處理完這個事件只相當(dāng)于處理完 1 個請求的階段顷牌。什么時候可以處理下一個階段呢剪芍?這只能等待內(nèi)核的通知,即當(dāng)下一次事件出現(xiàn)時窟蓝,epoll 等事件分發(fā)器將會獲取到通知罪裹,然后去調(diào)用事件消費者進行處理。

管理進程运挫、多工作進程設(shè)計

Nginx 在啟動后状共,會有一個 master 進程和多個 worker 進程。master 進程主要用來管理worker 進程谁帕,包括接收來自外界的信號峡继,向各 worker 進程發(fā)送信號,監(jiān)控 worker 進程的運行狀態(tài)以及啟動 worker 進程雇卷。worker 進程是用來處理來自客戶端的請求事件鬓椭。多個 worker 進程之間是對等的,它們同等競爭來自客戶端的請求关划,各進程互相獨立小染,一個請求只能在一個 worker 進程中處理。worker 進程的個數(shù)是可以設(shè)置的贮折,一般會設(shè)置與機器 CPU 核數(shù)一致裤翩,這里面的原因與事件處理模型有關(guān)。Nginx 的進程模型调榄,可由下圖來表示:

image

在服務(wù)器上查看 Nginx 進程:

image

這種設(shè)計帶來以下優(yōu)點:

利用多核系統(tǒng)的并發(fā)處理能力

現(xiàn)代操作系統(tǒng)已經(jīng)支持多核 CPU 架構(gòu)踊赠,這使得多個進程可以分別占用不同的 CPU 核心來工作。Nginx 中所有的 worker 工作進程都是完全平等的每庆。這提高了網(wǎng)絡(luò)性能筐带、降低了請求的時延。

負(fù)載均衡

多個 worker 工作進程通過進程間通信來實現(xiàn)負(fù)載均衡缤灵,即一個請求到來時更容易被分配到負(fù)載較輕的 worker 工作進程中處理伦籍。這也在一定程度上提高了網(wǎng)絡(luò)性能、降低了請求的時延腮出。

管理進程會負(fù)責(zé)監(jiān)控工作進程的狀態(tài)帖鸦,并負(fù)責(zé)管理其行為

管理進程不會占用多少系統(tǒng)資源,它只是用來啟動胚嘲、停止作儿、監(jiān)控或使用其他行為來控制工作進程。首先馋劈,這提高了系統(tǒng)的可靠性攻锰,當(dāng) worker 進程出現(xiàn)問題時晾嘶,管理進程可以啟動新的工作進程來避免系統(tǒng)性能的下降。其次口注,管理進程支持 Nginx 服務(wù)運行中的程序升級变擒、配置項修改等操作,這種設(shè)計使得動態(tài)可擴展性寝志、動態(tài)定制性較容易實現(xiàn)娇斑。

內(nèi)存池的設(shè)計

為了避免出現(xiàn)內(nèi)存碎片,減少向操作系統(tǒng)申請內(nèi)存的次數(shù)材部、降低各個模塊的開發(fā)復(fù)雜度毫缆,Nginx 設(shè)計了簡單的內(nèi)存池,它的作用主要是把多次向系統(tǒng)申請內(nèi)存的操作整合成一次乐导,這大大減少了 CPU 資源的消耗苦丁,同時減少了內(nèi)存碎片。

因此物臂,通常每一個請求都有一個簡易的獨立內(nèi)存池(如每個 TCP 連接都分配了一個內(nèi)存池)旺拉,而在請求結(jié)束時則會銷毀整個內(nèi)存池,把曾經(jīng)分配的內(nèi)存一次性歸還給操作系統(tǒng)棵磷。這種設(shè)計大大提高了模塊開發(fā)的簡單些蛾狗,因為在模塊申請內(nèi)存后不用關(guān)心它的釋放問題;而且因為分配內(nèi)存次數(shù)的減少使得請求執(zhí)行的時延得到了降低仪媒。同時沉桌,通過減少內(nèi)存碎片,提高了內(nèi)存的有效利用率和系統(tǒng)可處理的并發(fā)連接數(shù)算吩,從而增強了網(wǎng)絡(luò)性能留凭。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市偎巢,隨后出現(xiàn)的幾起案子蔼夜,更是在濱河造成了極大的恐慌,老刑警劉巖压昼,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挎扰,死亡現(xiàn)場離奇詭異,居然都是意外死亡巢音,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門尽超,熙熙樓的掌柜王于貴愁眉苦臉地迎上來官撼,“玉大人,你說我怎么就攤上這事似谁“列澹” “怎么了掠哥?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秃诵。 經(jīng)常有香客問我续搀,道長,這世上最難降的妖魔是什么菠净? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任禁舷,我火速辦了婚禮,結(jié)果婚禮上毅往,老公的妹妹穿的比我還像新娘牵咙。我一直安慰自己,他們只是感情好攀唯,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布洁桌。 她就那樣靜靜地躺著,像睡著了一般侯嘀。 火紅的嫁衣襯著肌膚如雪另凌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天戒幔,我揣著相機與錄音吠谢,去河邊找鬼。 笑死溪食,一個胖子當(dāng)著我的面吹牛囊卜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播错沃,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼栅组,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枢析?” 一聲冷哼從身側(cè)響起玉掸,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎醒叁,沒想到半個月后司浪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡把沼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年啊易,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饮睬。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡租谈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捆愁,到底是詐尸還是另有隱情割去,我是刑警寧澤窟却,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站呻逆,受9級特大地震影響夸赫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咖城,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一茬腿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酒繁,春花似錦滓彰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至郎哭,卻和暖如春他匪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背夸研。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工邦蜜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人亥至。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓悼沈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親姐扮。 傳聞我的和親對象是個殘疾皇子絮供,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容