先總的說幾個概念:?
1:在高并發的情況下nginx比apache快,低并發體現不明顯?
2:快的原因得益于nginx的epoll模型?
apache是多線程或者多進程,在工作的時候,當來了一個http響應,一個進程接收(listen)–>識別處理—>返回請求,在此過程中,一個進程全部處理,apche 對于套接字的I/O,讀或者寫,但是讀或者寫都是阻塞的,阻塞意味著進程就得掛起進入sleep狀態,那么一旦連接數很多,Apache必然要生成更多的進程來響應請求,一旦進程多了,CPU對于進程的切換就頻繁了,很耗資源和時間,所以就導致apache性能下降了,說白了就是處理不過來這么多進程了。
Nginx采用epoll模型,異步非阻塞。對于Nginx來說,把一個完整的連接請求處理都劃分成了事件,一個一個的事件。比如accept(), receive(),磁盤I/O,send()等,每部分都有相應的模塊去處理,一個完整的請求可能是由幾百個模塊去處理。真正核心的就是事件收集和分發模塊,這就是管理所有模塊的核心。
只有核心模塊的調度才能讓對應的模塊占用CPU資源,從而處理請求。拿一個HTTP請求來說,首先在事件收集分發模塊注冊感興趣的監聽事件,注冊好之后不阻塞直接返回,接下來就不需要再管了,等待有連接來了內核會通知你(epoll的輪詢會告訴進程),cpu就可以處理其他事情去了。
一旦有請求來,那么對整個請求分配相應的上下文(其實已經預先分配好),這時候再注冊新的感興趣的事件(read函數),同樣客戶端數據來了內核會自動通知進程可以去讀數據了,讀了數據之后就是解析,解析完后去磁盤找資源(I/O),一旦I/O完成會通知進程,進程開始給客戶端發回數據send(),這時候也不是阻塞的,調用后就等內核發回通知發送的結果就行。
整個下來把一個請求分成了很多個階段,每個階段都到很多模塊去注冊,然后處理,都是異步非阻塞。異步這里指的就是做一個事情,不需要等返回結果,做好了會自動通知你。
在網上找到了一個例子:?
可以舉一個簡單的例子來說明Apache的工作流程,我們平時去餐廳吃飯。餐廳的工作模式是一個服務員全程服務客戶,流程是這樣,服務員在門口等候客人(listen),客人到了就接待安排的餐桌上(accept),等著客戶點菜(request uri),去廚房叫師傅下單做菜(磁盤I/O),等待廚房做好(read),然后給客人上菜(send),整個下來服務員(進程)很多地方是阻塞的。
這樣客人一多(HTTP請求一多),餐廳只能通過叫更多的服務員來服務(fork進程),但是由于餐廳資源是有限的(CPU),一旦服務員太多管理成本很高(CPU上下文切換),這樣就進入一個瓶頸。?
再來看看Nginx得怎么處理?餐廳門口掛個門鈴(注冊epoll模型的listen),一旦有客人(HTTP請求)到達,派一個服務員去接待(accept),之后服務員就去忙其他事情了(比如再去接待客人),等這位客人點好餐就叫服務員(數據到了read()),服務員過來拿走菜單到廚房(磁盤I/O),服務員又做其他事情去了,等廚房做好了菜也喊服務員(磁盤I/O結束),服務員再給客人上菜(send()),廚房做好一個菜就給客人上一個,中間服務員可以去干其他事情。
整個過程被切分成很多個階段,每個階段都有相應的服務模塊。我們想想,這樣一旦客人多了,餐廳也能招待更多的人。
更多Nginx技術文章,請訪問Nginx使用教程欄目!