Nginx簡(jiǎn)介
??Nginx 是一個(gè)高性能的HTTP和反向代理服務(wù)器台夺,也是一個(gè)IMAP/POP3/SMTP服務(wù)器薄啥。
??特點(diǎn)是占有內(nèi)存少,并發(fā)能力強(qiáng)惹挟,事實(shí)上nginx的并發(fā)能力確實(shí)在同類型的網(wǎng)頁(yè)服務(wù)器中表現(xiàn)較好蒲凶。
??Nginx 可以在大多數(shù) UnixLinux OS 上編譯運(yùn)行气筋,并有 Windows 移植版。在連接高并發(fā)的情況下旋圆,Nginx是Apache服務(wù)器不錯(cuò)的替代品宠默。
??Nginx 既可以在內(nèi)部直接支持 Rails 和 PHP 程序?qū)ν膺M(jìn)行服務(wù),也可以支持作為 HTTP代理服務(wù)器對(duì)外進(jìn)行服務(wù)灵巧。
??Nginx采用C進(jìn)行編寫搀矫,不論是系統(tǒng)資源開銷還是CPU使用效率都比 Perlbal 要好很多。
Nginx 是一個(gè)安裝非常的簡(jiǎn)單刻肄、配置文件非常簡(jiǎn)潔(還能夠支持perl語(yǔ)法)瓤球、Bug非常少的服務(wù)器。Nginx 啟動(dòng)特別容易敏弃,并且?guī)缀蹩梢宰龅?*24不間斷運(yùn)行卦羡,即使運(yùn)行數(shù)個(gè)月也不需要重新啟動(dòng)。你還能夠不間斷服務(wù)的情況下進(jìn)行軟件版本的升級(jí)。
Nginx模式
??Nginx在啟動(dòng)后绿饵,在unix系統(tǒng)中會(huì)以daemon的方式在后臺(tái)運(yùn)行欠肾,后臺(tái)進(jìn)程包含一個(gè)master進(jìn)程和多個(gè)worker進(jìn)程。
??Master進(jìn)程:主要用來(lái)管理worker進(jìn)程拟赊,包含:接收來(lái)自外界的信號(hào)刺桃,向各worker進(jìn)程發(fā)送信號(hào),監(jiān)控worker進(jìn)程的運(yùn)行狀態(tài)要门,當(dāng)worker進(jìn)程退出后(異常情況下)虏肾,會(huì)自動(dòng)重新啟動(dòng)新的worker進(jìn)程。
??worker進(jìn)程:基本的網(wǎng)絡(luò)事件欢搜,則是放在worker進(jìn)程中來(lái)處理了。多個(gè)worker進(jìn)程之間是對(duì)等的谴轮,他們同等競(jìng)爭(zhēng)來(lái)自客戶端的請(qǐng)求炒瘟,各進(jìn)程互相之間是獨(dú)立的。一個(gè)請(qǐng)求第步,只可能在一個(gè)worker進(jìn)程中處理疮装。worker進(jìn)程的個(gè)數(shù)是可以設(shè)置的,一般我們會(huì)設(shè)置與機(jī)器cpu核數(shù)一致(更多的worker數(shù)粘都,只會(huì)導(dǎo)致進(jìn)程來(lái)競(jìng)爭(zhēng)cpu資源了廓推,從而帶來(lái)不必要的上下文切換。與cpu核數(shù)一樣翩隧,剛好利用好計(jì)算機(jī)的資源)
Nginx一些特性
??不影響現(xiàn)有環(huán)境重啟:master進(jìn)程在接到重啟信號(hào)后樊展,會(huì)先重新加載配置文件,然后再啟動(dòng)新的worker進(jìn)程堆生,并向所有老的worker進(jìn)程發(fā)送信號(hào)专缠,告訴他們可以光榮退休了。新的worker在啟動(dòng)后淑仆,就開始接收新的請(qǐng)求涝婉,而老的worker在收到來(lái)自master的信號(hào)后,就不再接收新的請(qǐng)求蔗怠,并且在當(dāng)前進(jìn)程中的所有未處理完的請(qǐng)求處理完成后墩弯,再退出。
??一個(gè)完整的請(qǐng)求過(guò)程:首先寞射,每個(gè)worker進(jìn)程都是從master進(jìn)程fork過(guò)來(lái)渔工,在master進(jìn)程里面,先建立好需要listen的socket(listenfd)之后怠惶,然后再fork出多個(gè)worker進(jìn)程涨缚。所有worker進(jìn)程的listenfd會(huì)在新連接到來(lái)時(shí)變得可讀,為保證只有一個(gè)進(jìn)程處理該連接,所有worker進(jìn)程在注冊(cè)listenfd讀事件前搶accept_mutex脓魏,搶到互斥鎖那個(gè)進(jìn)程注冊(cè)listenfd讀事件兰吟,在讀事件里調(diào)用accept接受該連接。當(dāng)一個(gè)worker進(jìn)程在accept這個(gè)連接之后茂翔,就開始讀取請(qǐng)求混蔼,解析請(qǐng)求,處理請(qǐng)求珊燎,產(chǎn)生數(shù)據(jù)后惭嚣,再返回給客戶端,最后才斷開連接悔政,這樣一個(gè)完整的請(qǐng)求就是這樣的了晚吞。
對(duì)于每個(gè)worker進(jìn)程來(lái)說(shuō),獨(dú)立的進(jìn)程谋国,不需要加鎖槽地。
??異步非阻塞應(yīng)對(duì)大并發(fā)量請(qǐng)求:Nginx采用了異步非阻塞的方式來(lái)處理請(qǐng)求,也就是說(shuō)芦瘾,nginx是可以同時(shí)處理成千上萬(wàn)個(gè)請(qǐng)求的捌蚊。想想apache的常用工作方式(apache也有異步非阻塞版本,但因其與自帶某些模塊沖突近弟,所以不常用)缅糟,每個(gè)請(qǐng)求會(huì)獨(dú)占一個(gè)工作線程,當(dāng)并發(fā)數(shù)上到幾千時(shí)祷愉,就同時(shí)有幾千的線程在處理請(qǐng)求了窗宦。這對(duì)操作系統(tǒng)來(lái)說(shuō),是個(gè)不小的挑戰(zhàn)谣辞,線程帶來(lái)的內(nèi)存占用非常大迫摔,線程的上下文切換帶來(lái)的cpu開銷很大,自然性能就上不去了泥从,而這些開銷完全是沒(méi)有意義的句占。
??非阻塞就是,事件沒(méi)有準(zhǔn)備好躯嫉,馬上返回EAGAIN纱烘,告訴你,事件還沒(méi)準(zhǔn)備好呢祈餐,你慌什么擂啥,過(guò)會(huì)再來(lái)吧。好吧帆阳,你過(guò)一會(huì)哺壶,再來(lái)檢查一下事件,直到事件準(zhǔn)備好了為止,在這期間山宾,你就可以先去做其它事情至扰,然后再來(lái)看看事件好了沒(méi)。雖然不阻塞了资锰,但你得不時(shí)地過(guò)來(lái)檢查一下事件的狀態(tài)敢课,你可以做更多的事情了。這樣一個(gè)worker就不用等待一次請(qǐng)求的完成绷杜,而是在等待請(qǐng)求準(zhǔn)備的過(guò)程中去處理別的請(qǐng)求直秆。只是在請(qǐng)求間進(jìn)行不斷地切換而已,切換也是因?yàn)楫惒绞录礈?zhǔn)備好鞭盟,而主動(dòng)讓出的圾结。這里的切換是沒(méi)有任何代價(jià),你可以理解為循環(huán)處理多個(gè)準(zhǔn)備好的事件懊缺,事實(shí)上就是這樣的疫稿。與多線程相比,這種事件處理方式是有很大的優(yōu)勢(shì)的鹃两,不需要?jiǎng)?chuàng)建線程,每個(gè)請(qǐng)求占用的內(nèi)存也很少舀凛,沒(méi)有上下文切換俊扳,事件處理非常的輕量級(jí)。并發(fā)數(shù)再多也不會(huì)導(dǎo)致無(wú)謂的資源浪費(fèi)(上下文切換)猛遍。在24G內(nèi)存的機(jī)器上馋记,處理的并發(fā)請(qǐng)求數(shù)達(dá)到過(guò)200萬(wàn)。現(xiàn)在的網(wǎng)絡(luò)服務(wù)器基本都采用這種方式懊烤,這也是nginx性能高效的主要原因梯醒。
??進(jìn)程文件描述符限制:在nginx中,每個(gè)進(jìn)程會(huì)有一個(gè)連接數(shù)的最大上限腌紧,這個(gè)上限與系統(tǒng)對(duì)fd的限制不一樣茸习。在操作系統(tǒng)中,通過(guò)ulimit -n壁肋,我們可以得到一個(gè)進(jìn)程所能夠打開的fd的最大數(shù)号胚,即nofile,因?yàn)槊總€(gè)socket連接會(huì)占用掉一個(gè)fd浸遗,所以這也會(huì)限制我們進(jìn)程的最大連接數(shù)猫胁,當(dāng)然也會(huì)直接影響到我們程序所能支持的最大并發(fā)數(shù),當(dāng)fd用完后跛锌,再創(chuàng)建socket時(shí)弃秆,就會(huì)失敗。nginx通過(guò)設(shè)置worker_connectons來(lái)設(shè)置每個(gè)進(jìn)程支持的最大連接數(shù)。如果該值大于nofile菠赚,那么實(shí)際的最大連接數(shù)是nofile脑豹。一般系統(tǒng)文件描述符限制為1024個(gè)文件,我們先將其改為65535锈至。
??最大連接數(shù)計(jì)算:一個(gè)nginx能建立的最大連接數(shù)晨缴,應(yīng)該是 worker_connections * worker_processes。
當(dāng)然峡捡,這里說(shuō)的是最大連接數(shù)击碗,對(duì)于HTTP請(qǐng)求本地資源來(lái)說(shuō),能夠支持的最大并發(fā)數(shù)量是worker_connections * worker_processes们拙,而如果是HTTP作為反向代理來(lái)說(shuō)稍途,最大并發(fā)數(shù)量應(yīng)該是worker_connections * worker_processes/2。因?yàn)樽鳛榉聪虼矸?wù)器砚婆,每個(gè)并發(fā)會(huì)建立與客戶端的連接和與后端服務(wù)的連接械拍,會(huì)占用兩個(gè)連接。
總結(jié)
??這里主要是講了Ngnix一些機(jī)制上概念装盯,讓我們對(duì)Ngnix實(shí)現(xiàn)機(jī)制有個(gè)大概了解坷虑。Ngnix還提供很多數(shù)據(jù)結(jié)構(gòu)和方法來(lái)開發(fā)者自定義一些請(qǐng)求處理的規(guī)則。我們用Ngnix主要是進(jìn)行反向代理和負(fù)載均衡埂奈,并不進(jìn)行復(fù)雜的開發(fā)迄损,所以這里不做講解,想了解這部分的也可以看下《Nginx開發(fā)從入門到精通》