nginx工作原理:
首先nginx,采用的是多線程&多路io復用模型,使用I/O多路復用技術的nginx,成就了”并發驅動”的服務器.
nginx的框架模型:
進程組件角色:
master進程: 監視工作進程的狀態,當工作進程死掉后重啟一個新的,處理信號和通知工作進程.
work進程: 處理客戶端請求,從主進程處獲得信號,根據指示去做對應的事情,
cache Loader進程: 加載緩存索引文件信息,人后退出,
cacheManger進程: 管理磁盤的緩存大小,超過預定值大小后最少使用數據將被刪除.
?
?
nnginx多進程的工作模式: nginx在啟動后,會有一個master進程和多個worker進程,.master進程主要用來管理worker進程,包含:接受來自外界的信號,向各worker進程發送信號,監控worker進程的運行狀態,當worker進程退出后,會自動重新啟動新的worker進程,,而基本的網絡事件,則是放在worker進程中來處理,多個worker進程之間的是對等的,他們同等競爭來自客戶端的請求.各個進程之間是相互獨立的,可能會加鎖.一個請求只可能在一個worker進程上進程處理,不能同時處理其他進程.
注意:
worker進程數,一般會設置成cpu內核數,因為更多的worker數,只會導致進程相互競爭cpu的資源,從而帶來不必要的上下文切換,使用多進程模式,不僅能提高并發效率,而在進程之間相互獨立,一個worker進程掛掉,不會影響其他worker進程工作.同時,master會接受到信號,對該任務重新分配一個worker進程.
Nginx的請求處理流程:
?
多種流量進入nginx后,nginx的三種狀態機開始工作:
調用非阻塞事件驅動模型epoll: 傳輸層狀態機, http狀態機,mail狀態機,
在nginx解析出請求后,會動用線程池處理調用將靜態資源方向代理,錯誤日志等信息分別導向不同的出口,如: fastcgi會導向php處理,html會導向nginx處理.并將處理的請求記錄日志到本地或遠程服務器
基于這樣的事件處理狀態機:我們在解析出請求需要訪問靜態資源的時候,我們看到軸走左下方箭頭,就會去訪問對應的靜態資源,.,如果我們做反向代理的時候,那么對方向代理的內容,我們可以做磁盤緩存,緩存到磁盤上,也是在這條路上.但當我們在處理靜態資源的時候,會有一個問題,就是當整個內存已經不足以完全緩存所有文件和信息,的時候,
那么就會像send File這樣調用或者AIO會退化稱為阻塞的磁盤調用,所以在這里需要有一個線程池來處理,對于每一個處理完成的請求,我們會進入access日志或者error日志,
那么這里也是進入了磁盤中的,當然我們可以通過 syslog 協議把它進入到遠程的機器上,那么更多的時候我們的 Nginx 是作為負載均衡或者反向代理來使用的,就是我們可以把請求通過協議級(HTTP,Mail 及 stream(TCP))傳輸到后面的服務器,也可以通過例如應用層的一些協議(FastCGI、uWSGI、SCGI、memcached)代理到相應的應用服務器。以上就是 Nginx 的請求處理流程。
Nginx接受請求連接事件模塊流程
os內核: 建立三次握手, 當用戶發來一個 SYN 報文時,系統內核會返回一個SYN+ACK確認給客戶端,當用戶再次發送ACK來的時候,此時就已經建立了三次握手.
完成三次握手后,os會根據系統的負載均衡算法來選中一個worker線程,它會返回一個建立連接的epoll_wait的句柄,拿到了epoll_wait的鏈接句柄后找到它監聽的端口80或者443等端口,拿到端口后,開始調用accept方法來分配512個字節的連接內存池,,分配完成后內存池后,http模塊會從事件中接入請求的處理過程,
http模塊啟動后,ngx_http_init_connection設置并啟用一個回調方法:前面的epoll_ctl,并為這個方法添加一個定時器, (client_header_timeout:60s)(這個在nginx,conf文件中有),然后繼續讀取事件添加到這個epoll事件中,并開始計算時間60s.如果超時就會返回信息.
在請求完成后,nginx會將請求數據讀取到用戶態中,并在鏈接內存池中為他分配一個讀的緩沖區, clent_header_bufer_size:1k [之前分配的是512字節,這里是可擴展的分配的1k,這里的1k 是強制占用,無論你現有字節會不會超過1k 都會強行占用1k]
接收請求HTTP模塊:收到url后,開始分配內存池,并做上下文解析,分析每一個head和http協議,所以這里需要分配一個默認請求內存池, request_poll_size:4k;
此時,狀態機會解析請求行: 如:方法名,url,協議, 解析請求行的過程中可能會發現有的URL更大,已經超過了我們之前設置的1k了 此時我們會調用一個大內存: large_client_header_buffers: 4 8k; (最多32k).
當狀態機解析完了請求行后,表示URL用于指向請求行, (這里也是nginx強大的原因,他可以指定請求行,不用遍歷).,標識結束后,開始接受head,并開始解析,head同時復用large_client_header_buffers: 4 8k;的的內存,接受完成的header后,標識header,并且移除定時器,(clent_header_timeout:60s) 移除定時器后,就開始11個階段的http請求處理.
?
驚群現象:
master進程首先通過socket()(套接字)來創建一個sock文件描述符用來監聽,然后fok生成一個子進程,(workers進程),子進程將繼承父進程的sockfd(socket 文件描述符),之后子進程accept()后將創建已連接描述符,然后通過已連接描述符與客戶端通信.
那么,由于所有子進程都繼承了父進程的 sockfd,那么當連接進來時,所有子進程都將收到通知并“爭著”與它建立連接,這就叫“驚群現象”。大量的進程被激活又掛起,只有一個進程可以accept() 到這個連接,這當然會消耗系統資源。
Nginx對驚群現象的處理:
Nginx 提供了一個 accept_mutex 這個東西,這是一個加在accept上的一把互斥鎖。即每個 worker 進程在執行 accept 之前都需要先獲取鎖,獲取不到就放棄執行 accept()。有了這把鎖之后,同一時刻,就只會有一個進程去 accpet(),這樣就不會有驚群問題了。accept_mutex 是一個可控選項,我們可以顯示地關掉,默認是打開的。
這樣做帶來的好處:
1、節省鎖帶來的開銷。每個 worker 進程都是獨立的進程,不共享資源,不需要加鎖。同時在編程以及問題查上時,也會方便很多。
2、獨立進程,減少風險。采用獨立的進程,可以讓互相之間不會影響,一個進程退出后,其它進程還在工作,服務不會中斷,master 進程則很快重新啟動新的 worker 進程。當然,worker 進程的也能發生意外退出。
總結
以上是生活随笔為你收集整理的nginx工作原理:的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Codeforces Testing R
- 下一篇: POJ1033 Defragment