摘要:子進(jìn)程啟動(dòng)后監(jiān)控維護(hù)區(qū)。每來(lái)一個(gè)新的連接都會(huì)觸發(fā)新的事件,這些事件送給內(nèi)的狀態(tài)機(jī)來(lái)處理。大部分的邏輯上都有這樣的狀態(tài)機(jī),只是實(shí)現(xiàn)方式不一樣。另外通過(guò)進(jìn)程綁定技術(shù)可以進(jìn)一步減少上下文切換和失效等系統(tǒng)開(kāi)銷。
Nginx在web開(kāi)發(fā)者眼中就是高并發(fā)高性能的代名詞,其基于事件的架構(gòu)也被眾多開(kāi)發(fā)者效仿。我從Nginx的網(wǎng)站找到一篇技術(shù)文章將Nginx是怎樣實(shí)現(xiàn)的,文章是Nginx的產(chǎn)品老大Owen
Garrett在加入公司22個(gè)月時(shí)寫(xiě)的,深入簡(jiǎn)出。這篇博客后面的內(nèi)容盡量保證是對(duì)原文的翻譯,如果有個(gè)人理解或者延伸閱讀我會(huì)加標(biāo)“譯注”。原文地址Inside NGINX: How We Designed for Performance & Scale
Nginx強(qiáng)勁的高性能表現(xiàn)來(lái)自其合理的軟件設(shè)計(jì)。傳統(tǒng)的web服務(wù)器和應(yīng)用服務(wù)器架構(gòu)設(shè)計(jì)上采用多進(jìn)程或線程作為其處理業(yè)務(wù)的基本單位,而Nginx更多的使用了事件驅(qū)動(dòng)的架構(gòu)。正是這種架構(gòu)使得Nginx可以輕松支持?jǐn)?shù)十萬(wàn)的并發(fā)鏈接。【譯注:Nginx相比其他的web服務(wù)器使用了更少的進(jìn)程,將IO事件集中在固定的進(jìn)程內(nèi)處理,減少了很多系統(tǒng)開(kāi)銷,可以從下文理解到。】
The Inside NGINX infographic 較為清晰的講訴了Nginx如何在一個(gè)進(jìn)程內(nèi)處理并發(fā)鏈接,下面我們深入看一下細(xì)節(jié)。
Nginx進(jìn)程模型在講設(shè)計(jì)實(shí)現(xiàn)之前,有必要先看一下Ngxin如何在linux之上運(yùn)行的。Nginx啟動(dòng)會(huì)創(chuàng)建一個(gè)主進(jìn)程(主管進(jìn)程,負(fù)責(zé)讀取配置、綁定端口、管理其他子進(jìn)程)和一些worker進(jìn)程和輔助進(jìn)程。
# service nginx restart # ps -ef --forest | grep nginx root 32475 1 0 13:36 ? 00:00:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 32476 32475 0 13:36 ? 00:00:00 \_ nginx: worker process nginx 32477 32475 0 13:36 ? 00:00:00 \_ nginx: worker process nginx 32479 32475 0 13:36 ? 00:00:00 \_ nginx: worker process nginx 32480 32475 0 13:36 ? 00:00:00 \_ nginx: worker process nginx 32481 32475 0 13:36 ? 00:00:00 \_ nginx: cache manager process nginx 32482 32475 0 13:36 ? 00:00:00 \_ nginx: cache loader process
這個(gè)示例運(yùn)行在4核的server上,Nginx主進(jìn)程創(chuàng)建4個(gè)worker進(jìn)程和2個(gè)cahce輔助進(jìn)程。
為什么架構(gòu)很重要?Unix應(yīng)用程序的基本要素是進(jìn)程或者線程。(Linux OS調(diào)度不區(qū)分進(jìn)程還是線程,二者的最大區(qū)別在于它們對(duì)于memory的共享程度。)進(jìn)程或線程是一個(gè)自包含的可以獨(dú)立運(yùn)行的任務(wù),OS可以調(diào)度它到某個(gè)CPU核上執(zhí)行。有很多復(fù)雜的應(yīng)用程序運(yùn)行在多進(jìn)程或線程模式下是基于以下兩點(diǎn)考慮:
可以使用更多CPU資源。【譯注:還有memory、IO等其他資源】
可以輕松做到并行處理(比如,同時(shí)處理多個(gè)鏈接)。
進(jìn)程和線程都會(huì)消耗資源,需要占用memory和其他OS資源,并且在運(yùn)行時(shí)還有context switch的系統(tǒng)開(kāi)銷。一般的server可以負(fù)擔(dān)幾百數(shù)量級(jí)的進(jìn)程或者線程,當(dāng)進(jìn)程或線程數(shù)量繼續(xù)上升到更高的數(shù)量級(jí),memory消耗和IO阻塞引起的系統(tǒng)負(fù)荷會(huì)很高,使得應(yīng)用程序運(yùn)行比較低效。
在設(shè)計(jì)網(wǎng)絡(luò)程序時(shí),開(kāi)發(fā)者會(huì)很自然的設(shè)計(jì)成每個(gè)進(jìn)程或線程處理一個(gè)網(wǎng)絡(luò)連接。這種架構(gòu)比較簡(jiǎn)單容易實(shí)現(xiàn),但是比較難以擴(kuò)展,尤其是當(dāng)網(wǎng)絡(luò)連接增長(zhǎng)到上千以后。
Nginx怎樣工作的?Nginx可配置數(shù)量的進(jìn)程,推薦配置數(shù)量和CPU的核數(shù)量相當(dāng):
主進(jìn)程讀配置,綁定端口,然后啟動(dòng)一定數(shù)量的子進(jìn)程。
cache loader子進(jìn)程在啟動(dòng)的時(shí)候運(yùn)行,負(fù)責(zé)把硬盤(pán)上的數(shù)據(jù)搬進(jìn)內(nèi)存,然后就退出了。因?yàn)樗且淮涡缘娜蝿?wù),系統(tǒng)開(kāi)銷很小。
cahce manager子進(jìn)程啟動(dòng)后監(jiān)控維護(hù)cache區(qū)。
worker子進(jìn)程是真正處理業(yè)務(wù)的進(jìn)程,負(fù)責(zé)處理網(wǎng)絡(luò)連接,讀寫(xiě)硬盤(pán),跟上游server交互等等。
Nginx推薦配置worker的數(shù)量跟CPU核數(shù)量線性關(guān)系,每個(gè)CPU核運(yùn)行一個(gè)worker進(jìn)程。可以通過(guò)配置 worker_processes auto來(lái)使用該推薦設(shè)置。
當(dāng)Nginx server處理業(yè)務(wù)時(shí),worker進(jìn)程們是最繁忙的,每個(gè)worker通過(guò)非阻塞的IO復(fù)用方式處理很多連接,盡量減少不必要的上下文切換。
每個(gè)worker進(jìn)程都是單線程的進(jìn)程,接收連接上的request并處理后回應(yīng)。進(jìn)程間可以通過(guò)共享內(nèi)存的方式進(jìn)行進(jìn)程間通信。
每個(gè)Nginx worker進(jìn)程由主進(jìn)程讀取配置創(chuàng)建,通過(guò)accept_mutex競(jìng)爭(zhēng)獲得要listen的socket并加入自己的IO監(jiān)聽(tīng)列表中。
每來(lái)一個(gè)新的連接都會(huì)觸發(fā)新的事件,這些事件送給worker內(nèi)的狀態(tài)機(jī)來(lái)處理。(Nginx支持各種類型的狀態(tài)機(jī),如http/tcp/SMTP/IMAP/POP3等)。大部分的web server邏輯上都有這樣的狀態(tài)機(jī),只是實(shí)現(xiàn)方式不一樣。
我們可以想象類比狀態(tài)機(jī)是象棋游戲的規(guī)則。每個(gè)HTTP transaction(譯注:一組的Http請(qǐng)求,可以對(duì)應(yīng)成某個(gè)socket上發(fā)生的所有http請(qǐng)求)就是一個(gè)象棋游戲。對(duì)弈的一方是web server,可以類比為象棋大師。另一方為client,類比為象棋愛(ài)好者。
游戲的規(guī)則可以很復(fù)雜,比如web server需要跟其他application溝通協(xié)作完成業(yè)務(wù)處理,第三方的nginx模塊甚至可以擴(kuò)展規(guī)則。
大多數(shù)的web服務(wù)器和應(yīng)用程序使用每個(gè)連接對(duì)應(yīng)一個(gè)進(jìn)程或線程的模式來(lái)玩象棋游戲。每個(gè)進(jìn)程或線程給一個(gè)client完成對(duì)弈直到游戲結(jié)束。在整個(gè)過(guò)程中,進(jìn)程大部分時(shí)間都是處在阻塞狀態(tài)--等待client完成下一步走棋。
web服務(wù)器主進(jìn)程在服務(wù)端口上監(jiān)聽(tīng)新的連接(客戶端發(fā)起的新游戲的請(qǐng)求)。
有新的游戲請(qǐng)求時(shí),主進(jìn)程創(chuàng)建子進(jìn)程負(fù)責(zé)完成跟客戶端的對(duì)弈。主進(jìn)程繼續(xù)監(jiān)聽(tīng)服務(wù)端口。
當(dāng)游戲結(jié)束時(shí),子進(jìn)程要么等待client開(kāi)始新游戲(通過(guò)keepalive機(jī)制?;钜欢螘r(shí)間連接)要么退出(keepalive超時(shí)后)。
這種模型每玩一局server都要?jiǎng)?chuàng)建一個(gè)對(duì)應(yīng)的進(jìn)程來(lái)完成對(duì)弈。這種架構(gòu)簡(jiǎn)單并且容易容易擴(kuò)展新功能,但有些大炮打蚊子,殺雞用牛刀的感覺(jué)。進(jìn)程是個(gè)重器,系統(tǒng)開(kāi)銷比較大,而解決的問(wèn)題是個(gè)輕量級(jí)的問(wèn)題。容易編程實(shí)現(xiàn)但是浪費(fèi)比較大。
你可能聽(tīng)說(shuō)過(guò)一人同時(shí)對(duì)戰(zhàn)多人的象棋大賽
這就是Nginx worker進(jìn)程的工作方式。每個(gè)worker進(jìn)程(一般每個(gè)CPU核有一個(gè)worker進(jìn)程)都是一個(gè)象棋大師,可以同時(shí)對(duì)弈數(shù)十萬(wàn)對(duì)手。
worker進(jìn)程等待listen和connection sockets的事件。(譯注:listen socket就是server用來(lái)監(jiān)聽(tīng)新建連接的socket,connection socket是accept系統(tǒng)調(diào)用返回的新建socket,詳細(xì)可參加accept的手冊(cè))
事件發(fā)生后,worker進(jìn)程來(lái)處理這些事件:
listen socket的事件表示有新的客戶端要開(kāi)始新的游戲。worker通過(guò)accept()創(chuàng)建新的connection socket,并加入監(jiān)聽(tīng)列表。
connection socket的事件表示客戶端走了一步棋,worker進(jìn)程可以做下一步應(yīng)對(duì)。
worker進(jìn)程從不會(huì)在網(wǎng)絡(luò)IO上阻塞,當(dāng)它應(yīng)對(duì)完客戶端的走棋走出自己的一步后,可以馬上應(yīng)對(duì)下一個(gè)客戶端的走棋或接收新的連接請(qǐng)求。
Nginx的worker進(jìn)程很容易擴(kuò)展支持?jǐn)?shù)十萬(wàn)并發(fā)連接。每個(gè)新接入的連接只需要?jiǎng)?chuàng)建新的socket消耗少量的內(nèi)存,每個(gè)連接的系統(tǒng)開(kāi)銷相對(duì)要比進(jìn)程開(kāi)銷小很多。另外通過(guò)Nginx worker進(jìn)程綁定CPU技術(shù)可以進(jìn)一步減少上下文切換和cache失效等系統(tǒng)開(kāi)銷。
而阻塞式每個(gè)進(jìn)程服務(wù)一個(gè)連接的方式,每個(gè)連接都會(huì)消耗很多資源,而且進(jìn)程切換比較頻繁導(dǎo)致系統(tǒng)開(kāi)銷比較大。
更詳細(xì)的解釋,可以參考這篇文章--Nginx架構(gòu),作者是Ngxin的VP和共同創(chuàng)始人,Andrew Alexeev.
Nginx的這種少量進(jìn)程的架構(gòu)使得更新配置和升級(jí)Nginx版本很容易。
更新Ngxin配置是一件非常容易事情而且非??煽?。很簡(jiǎn)單的nginx -s reload就搞定了。運(yùn)行這個(gè)命令實(shí)際上是給Nginx主進(jìn)程發(fā)送了一個(gè)SIGHUP的信號(hào),主進(jìn)程收到該信號(hào)后做了兩件事情:
重新加載配置并且根據(jù)新的配置創(chuàng)建一組新的worker進(jìn)程,這些新的進(jìn)程可以馬上開(kāi)始干活。
通知老的worker進(jìn)程優(yōu)雅地退出。
重新裝載的過(guò)程會(huì)引起短暫的CPU和內(nèi)存的使用高峰,但這種影響總體來(lái)說(shuō)比較微小,你甚至可以每秒多次做這個(gè)操作。
Nginx程序的升級(jí)就更加漂亮了,根本不會(huì)影響正在處理的連接,輕輕松松升級(jí)完成用戶根本沒(méi)有感覺(jué)。
Ngxin程序升級(jí)跟更新配置相似。啟動(dòng)新的Nginx主進(jìn)程,它會(huì)跟舊的主進(jìn)程共享listen sockets。新的進(jìn)程起來(lái)后,你可以發(fā)送信號(hào)給舊的進(jìn)程退出。詳細(xì)過(guò)程可以參看Controlling Nginx.
總結(jié)The Inside NGINX infographic描述了Nginx的整體功能,其實(shí)它概括性描述的背后是Nginx開(kāi)發(fā)人員十幾年的創(chuàng)新和優(yōu)化。如果你想了解更多,可以參看這些材料:
Installing and Tuning Nginx for Performance
Tuning Nginx for Performance
The Architecture of Open Source Applications – NGINX
Socket Sharding in NGINX Release 1.9.1 (using the SO_REUSEPORT socket option)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/39238.html
摘要:,關(guān)于原生的以及十分類似于,表單提交時(shí),如果元素沒(méi)有屬性,則該元素不會(huì)被提交。,的一些動(dòng)畫(huà)效果。除了我們常見(jiàn)的還有三個(gè)參數(shù)依次為需要改變的效果完成這些效果需要的時(shí)間動(dòng)畫(huà)完成后調(diào)用的函數(shù)。 1,反引號(hào)可以轉(zhuǎn)行輸出showImg(https://segmentfault.com/img/bVbr3eE?w=268&h=138); ${var_name}串聯(lián)字符 var name = 小明;...
摘要:項(xiàng)目進(jìn)展新增換輪回退機(jī)制,提升極端條件下主鏈的穩(wěn)定性,已完成,開(kāi)始穩(wěn)定性測(cè)試優(yōu)化回退機(jī)制,降低資源占用,已完成網(wǎng)絡(luò)優(yōu)化,增加節(jié)點(diǎn)狀態(tài)管理,已完成優(yōu)化交易轉(zhuǎn)發(fā)邏輯,緩解大交易量下網(wǎng)絡(luò)壓力,已完成性能優(yōu)化,提升側(cè)鏈交易效率,已完成接口規(guī)范 showImg(https://segmentfault.com/img/bVbtKHf); 項(xiàng)目進(jìn)展 ETM-Core 新增換輪回退機(jī)制,提升極端條...
摘要:作者今年大三,在春招過(guò)程中參加了多家大公司的面試后,拿到了騰訊的前端實(shí)習(xí),在這里做一些總結(jié),希望給還未參加過(guò)實(shí)習(xí)面試的同學(xué)一些幫助。在之后的面試時(shí)就更加從容一些了。 作者今年大三,在春招過(guò)程中參加了多家大公司的面試后,拿到了騰訊的前端實(shí)習(xí) offer,在這里做一些總結(jié),希望給還未參加過(guò)實(shí)習(xí)面試的同學(xué)一些幫助。 一、簡(jiǎn)歷的準(zhǔn)備 簡(jiǎn)歷制作是很重要的一個(gè)環(huán)節(jié),一份好的簡(jiǎn)歷會(huì)給面試官留下很不錯(cuò)...
閱讀 1454·2021-11-24 09:39
閱讀 3632·2021-09-29 09:47
閱讀 1580·2021-09-29 09:34
閱讀 3074·2021-09-10 10:51
閱讀 2541·2019-08-30 15:54
閱讀 3223·2019-08-30 15:54
閱讀 878·2019-08-30 11:07
閱讀 1011·2019-08-29 18:36