NGINX的模型

眾所周知仿贬,nginx性能高毁葱,而nginx的高性能與其架構(gòu)是分不開的专普。那么nginx究竟是怎么樣的呢卖鲤?這一節(jié)我們先來初識一下nginx框架吧蒂教。

NGINX進程模型

nginx在啟動后巍举,在unix系統(tǒng)中會以daemon的方式在后臺運行,后臺進程包含一個master進程和多個worker進程悴品。我們也可以手動地關(guān)掉后臺模式禀综,讓nginx在前臺運行,并且通過配置讓nginx取消master進程苔严,從而可以使nginx以單進程方式運行定枷。很顯然,生產(chǎn)環(huán)境下我們肯定不會這么做届氢,所以關(guān)閉后臺模式欠窒,一般是用來調(diào)試用的。所以退子,我們可以看到岖妄,nginx是以多進程的方式來工作的,當然nginx也是支持多線程的方式的寂祥,只是我們主流的方式還是多進程的方式荐虐,也是nginx的默認方式。

nginx在啟動后丸凭,會有一個master進程和多個worker進程福扬。master進程主要用來管理worker進程腕铸,包含:接收來自外界的信號,向各worker進程發(fā)送信號铛碑,監(jiān)控worker進程的運行狀態(tài)狠裹,當worker進程退出后(異常情況下),會自動重新啟動新的worker進程汽烦。而基本的網(wǎng)絡(luò)事件涛菠,則是放在worker進程中來處理了。多個worker進程之間是對等的撇吞,他們同等競爭來自客戶端的請求俗冻,各進程互相之間是獨立的。一個請求梢夯,只可能在一個worker進程中處理言疗,一個worker進程,不可能處理其它進程的請求颂砸。worker進程的個數(shù)是可以設(shè)置的噪奄,一般我們會設(shè)置與機器cpu核數(shù)一致,這里面的原因與nginx的進程模型以及事件處理模型是分不開的人乓。nginx的進程模型勤篮,可以由下圖來表示:



nginx啟動后,如果我們要操作nginx色罚,要怎么做呢碰缔?從上文中我們可以看到,master來管理worker進程戳护,所以我們只需要與master進程通信就行了金抡。master進程會接收來自外界發(fā)來的信號,再根據(jù)信號做不同的事情腌且。所以我們要控制nginx梗肝,只需要通過kill向master進程發(fā)送信號就行了。比如kill -HUP pid铺董,則是告訴nginx巫击,從容地重啟nginx,我們一般用這個信號來重啟nginx精续,或重新加載配置坝锰,因為是從容地重啟,因此服務(wù)是不中斷的重付。master進程在接收到HUP信號后是怎么做的呢顷级?首先master進程在接到信號后,會先重新加載配置文件确垫,然后再啟動新的worker進程弓颈,并向所有老的worker進程發(fā)送信號拣凹,告訴他們可以光榮退休了。新的worker在啟動后恨豁,就開始接收新的請求,而老的worker在收到來自master的信號后爬迟,就不再接收新的請求橘蜜,并且在當前進程中的所有未處理完的請求處理完成后,再退出付呕。當然计福,直接給master進程發(fā)送信號,這是比較老的操作方式徽职,nginx在0.8版本之后象颖,引入了一系列命令行參數(shù),來方便我們管理姆钉。比如说订,./nginx -s reload,就是來重啟nginx潮瓶,./nginx -s stop陶冷,就是來停止nginx的運行。如何做到的呢毯辅?我們還是拿reload來說埂伦,我們看到,執(zhí)行命令時思恐,我們是啟動一個新的nginx進程沾谜,而新的nginx進程在解析到reload參數(shù)后,就知道我們的目的是控制nginx來重新加載配置文件了胀莹,它會向master進程發(fā)送信號基跑,然后接下來的動作,就和我們直接向master進程發(fā)送信號一樣了嗜逻。

現(xiàn)在涩僻,我們知道了當我們在操作nginx的時候,nginx內(nèi)部做了些什么事情栈顷,那么逆日,worker進程又是如何處理請求的呢?我們前面有提到萄凤,worker進程之間是平等的室抽,每個進程,處理請求的機會也是一樣的靡努。當我們提供80端口的http服務(wù)時坪圾,一個連接請求過來晓折,每個進程都有可能處理這個連接,怎么做到的呢兽泄?首先漓概,每個worker進程都是從master進程fork過來,在master進程里面病梢,先建立好需要listen的socket(listenfd)之后胃珍,然后再fork出多個worker進程。所有worker進程的listenfd會在新連接到來時變得可讀蜓陌,為保證只有一個進程處理該連接觅彰,所有worker進程在注冊listenfd讀事件前搶accept_mutex,搶到互斥鎖的那個進程注冊listenfd讀事件钮热,在讀事件里調(diào)用accept接受該連接填抬。當一個worker進程在accept這個連接之后,就開始讀取請求隧期,解析請求飒责,處理請求,產(chǎn)生數(shù)據(jù)后仆潮,再返回給客戶端读拆,最后才斷開連接,這樣一個完整的請求就是這樣的了鸵闪。我們可以看到檐晕,一個請求,完全由worker進程來處理蚌讼,而且只在一個worker進程中處理辟灰。

那么,nginx采用這種進程模型有什么好處呢篡石?當然芥喇,好處肯定會很多了。首先凰萨,對于每個worker進程來說继控,獨立的進程,不需要加鎖胖眷,所以省掉了鎖帶來的開銷武通,同時在編程以及問題查找時,也會方便很多珊搀。其次冶忱,采用獨立的進程,可以讓互相之間不會影響境析,一個進程退出后囚枪,其它進程還在工作派诬,服務(wù)不會中斷,master進程則很快啟動新的worker進程链沼。當然默赂,worker進程的異常退出,肯定是程序有bug了括勺,異常退出放可,會導(dǎo)致當前worker上的所有請求失敗,不過不會影響到所有請求朝刊,所以降低了風(fēng)險。當然蜈缤,好處還有很多拾氓,大家可以慢慢體會。眾所周知底哥,nginx性能高咙鞍,而nginx的高性能與其架構(gòu)是分不開的。

NGINX事件模型

上面是關(guān)于nginx的進程模型趾徽,接下來续滋,我們來看看nginx是如何處理事件的。有人可能要問了孵奶,nginx采用多worker的方式來處理請求疲酌,每個worker里面只有一個主線程,那能夠處理的并發(fā)數(shù)很有限啊了袁,多少個worker就能處理多少個并發(fā)朗恳,何來高并發(fā)呢?非也载绿,這就是nginx的高明之處粥诫,nginx采用了異步非阻塞的方式來處理請求,也就是說崭庸,nginx是可以同時處理成千上萬個請求的怀浆。想想apache的常用工作方式(apache也有異步非阻塞版本,但因其與自帶某些模塊沖突怕享,所以不常用)执赡,每個請求會獨占一個工作線程,當并發(fā)數(shù)上到幾千時函筋,就同時有幾千的線程在處理請求了搀玖。這對操作系統(tǒng)來說,是個不小的挑戰(zhàn)驻呐,線程帶來的內(nèi)存占用非常大灌诅,線程的上下文切換帶來的cpu開銷很大芳来,自然性能就上不去了,而這些開銷完全是沒有意義的猜拾。
為什么nginx可以采用異步非阻塞的方式來處理呢即舌,或者異步非阻塞到底是怎么回事呢?我們先回到原點挎袜,看看一個請求的完整過程顽聂。首先,請求過來盯仪,要建立連接紊搪,然后再接收數(shù)據(jù),接收數(shù)據(jù)后全景,再發(fā)送數(shù)據(jù)耀石。具體到系統(tǒng)底層,就是讀寫事件爸黄,而當讀寫事件沒有準備好時滞伟,必然不可操作,如果不用非阻塞的方式來調(diào)用炕贵,那就得阻塞調(diào)用了梆奈,事件沒有準備好,那就只能等了称开,等事件準備好了亩钟,你再繼續(xù)吧。阻塞調(diào)用會進入內(nèi)核等待鳖轰,cpu就會讓出去給別人用了径荔,對單線程的worker來說,顯然不合適脆霎,當網(wǎng)絡(luò)事件越多時总处,大家都在等待呢,cpu空閑下來沒人用睛蛛,cpu利用率自然上不去了鹦马,更別談高并發(fā)了。好吧忆肾,你說加進程數(shù)荸频,這跟apache的線程模型有什么區(qū)別,注意客冈,別增加無謂的上下文切換旭从。所以,在nginx里面,最忌諱阻塞的系統(tǒng)調(diào)用了和悦。不要阻塞退疫,那就非阻塞嘍。非阻塞就是鸽素,事件沒有準備好褒繁,馬上返回EAGAIN,告訴你馍忽,事件還沒準備好呢棒坏,你慌什么,過會再來吧遭笋。好吧坝冕,你過一會,再來檢查一下事件瓦呼,直到事件準備好了為止喂窟,在這期間,你就可以先去做其它事情吵血,然后再來看看事件好了沒。雖然不阻塞了偷溺,但你得不時地過來檢查一下事件的狀態(tài)蹋辅,你可以做更多的事情了,但帶來的開銷也是不小的挫掏。所以侦另,才會有了異步非阻塞的事件處理機制,具體到系統(tǒng)調(diào)用就是像select/poll/epoll/kqueue這樣的系統(tǒng)調(diào)用尉共。它們提供了一種機制褒傅,讓你可以同時監(jiān)控多個事件,調(diào)用他們是阻塞的袄友,但可以設(shè)置超時時間殿托,在超時時間之內(nèi),如果有事件準備好了剧蚣,就返回支竹。這種機制正好解決了我們上面的兩個問題,拿epoll為例(在后面的例子中鸠按,我們多以epoll為例子礼搁,以代表這一類函數(shù)),當事件沒準備好時目尖,放到epoll里面馒吴,事件準備好了,我們就去讀寫,當讀寫返回EAGAIN時饮戳,我們將它再次加入到epoll里面豪治。這樣,只要有事件準備好了莹捡,我們就去處理它鬼吵,只有當所有事件都沒準備好時,才在epoll里面等著篮赢。這樣齿椅,我們就可以并發(fā)處理大量的并發(fā)了,當然启泣,這里的并發(fā)請求涣脚,是指未處理完的請求,線程只有一個寥茫,所以同時能處理的請求當然只有一個了遣蚀,只是在請求間進行不斷地切換而已,切換也是因為異步事件未準備好纱耻,而主動讓出的芭梯。這里的切換是沒有任何代價,你可以理解為循環(huán)處理多個準備好的事件弄喘,事實上就是這樣的玖喘。與多線程相比,這種事件處理方式是有很大的優(yōu)勢的蘑志,不需要創(chuàng)建線程累奈,每個請求占用的內(nèi)存也很少,沒有上下文切換急但,事件處理非常的輕量級澎媒。并發(fā)數(shù)再多也不會導(dǎo)致無謂的資源浪費(上下文切換)。更多的并發(fā)數(shù)波桩,只是會占用更多的內(nèi)存而已戒努。 我之前有對連接數(shù)進行過測試,在24G內(nèi)存的機器上镐躲,處理的并發(fā)請求數(shù)達到過200萬“芈保現(xiàn)在的網(wǎng)絡(luò)服務(wù)器基本都采用這種方式,這也是nginx性能高效的主要原因匀油。
我們之前說過缘缚,推薦設(shè)置worker的個數(shù)為cpu的核數(shù),在這里就很容易理解了敌蚜,更多的worker數(shù)桥滨,只會導(dǎo)致進程來競爭cpu資源了,從而帶來不必要的上下文切換。而且齐媒,nginx為了更好的利用多核特性蒲每,提供了cpu親緣性的綁定選項,我們可以將某一個進程綁定在某一個核上喻括,這樣就不會因為進程的切換帶來cache的失效邀杏。像這種小的優(yōu)化在nginx中非常常見,同時也說明了nginx作者的苦心孤詣唬血。比如望蜡,nginx在做4個字節(jié)的字符串比較時,會將4個字符轉(zhuǎn)換成一個int型拷恨,再作比較脖律,以減少cpu的指令數(shù)等等。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腕侄,一起剝皮案震驚了整個濱河市小泉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冕杠,老刑警劉巖微姊,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異分预,居然都是意外死亡兢交,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門噪舀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來魁淳,“玉大人飘诗,你說我怎么就攤上這事与倡。” “怎么了昆稿?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵纺座,是天一觀的道長。 經(jīng)常有香客問我溉潭,道長净响,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任喳瓣,我火速辦了婚禮馋贤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘畏陕。我一直安慰自己配乓,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著犹芹,像睡著了一般崎页。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腰埂,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天飒焦,我揣著相機與錄音,去河邊找鬼屿笼。 笑死牺荠,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的刁卜。 我是一名探鬼主播志电,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蛔趴!你這毒婦竟也來了挑辆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤孝情,失蹤者是張志新(化名)和其女友劉穎鱼蝉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箫荡,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡魁亦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了羔挡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洁奈。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绞灼,靈堂內(nèi)的尸體忽然破棺而出利术,到底是詐尸還是另有隱情,我是刑警寧澤低矮,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布印叁,位于F島的核電站,受9級特大地震影響军掂,放射性物質(zhì)發(fā)生泄漏轮蜕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一蝗锥、第九天 我趴在偏房一處隱蔽的房頂上張望跃洛。 院中可真熱鬧,春花似錦终议、人聲如沸汇竭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽韩玩。三九已至垒玲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間找颓,已是汗流浹背合愈。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留击狮,地道東北人佛析。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像彪蓬,于是被迫代替她去往敵國和親寸莫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

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

  • 第一章 Nginx簡介 Nginx是什么 沒有聽過Nginx档冬?那么一定聽過它的“同行”Apache吧膘茎!Ngi...
    JokerW閱讀 32,649評論 24 1,002
  • 1. Nginx的模塊與工作原理 Nginx由內(nèi)核和模塊組成,其中酷誓,內(nèi)核的設(shè)計非常微小和簡潔披坏,完成的工作也非常簡單...
    rosekissyou閱讀 10,200評論 5 124
  • 什么是Nginx? Nginx是一個高性能的HTTP和反向代理服務(wù)器盐数,也是一個IMAP/POP3/SMTP服務(wù)器N...
    jiangmo閱讀 2,536評論 1 9
  • 你聽過這樣的操作嗎玫氢,實體超市無須排隊結(jié)賬帚屉。刷手機進店、選品漾峡、拿貨攻旦,走人!一氣呵成灰殴。據(jù)說最快不到10秒就能從店里買好...
    范團點餐閱讀 401評論 1 0
  • 在城市的果殼里敬特,我點亮滿天繁星 用一具木偶的面孔 看穿梭的車流 看遠遠近近的霓虹 以及綿綿的情話 廝磨的耳鬢 多...
    鄉(xiāng)村痞子閱讀 182評論 0 3