Nginx 處理 HTTP 頭部的程序
Nginx 在處理 HTTP 請求之前,首先需要 Nginx 的框架先和客戶端建立好連接,然后接收用戶發來的 HTTP 的請求行,比如方法、URL 等,然后接收所有的 Header,根據這些 Header 資訊,才能決定由哪些 HTTP 模塊處理請求,下面這張圖,解釋了 Nginx 在處理 HTTP 請求之前,所經歷的一系列流程,強烈建議收藏保存,下面針對每個部分單獨講解一下,

接收請求事件模塊

首先是三次握手,當客戶端發來 ACK 之后,由作業系統內核回一個 SYN+ACK,緊接著客戶端 ACK 之后,連接建立成功,同時可能有很多 worker 行程都在監聽 80 或 443 埠,由作業系統的負載均衡演算法,選取一個 worker 行程來處理,這個 worker 行程會通過 epoll_wait 方法,回傳一個建立連接的句柄,拿到了監聽的句柄之后,這實際上是一個讀事件(因為是從作業系統中讀取到了一個請求),呼叫 accept 方法,分配連接記憶體池,
記憶體池主要分為連接記憶體池和請求記憶體池,
連接記憶體池大小的配置是 connection_pool_size,到了這一步之后,Nginx 會為已經建立的連接分配一個 512 位元組大小的連接記憶體池,分配完記憶體池,建立好連接之后,HTTP 模塊會從事件模塊手里接入請求處理的程序,HTTP 模塊在啟動時,會呼叫 ngx_http_init_connection 方法來設定回呼方法,這個時候會把新建立連接的讀事件通過 epoll_ctl 函式添加到 epoll 中,然后加一個超時定時器 client_header_timeout: 60s,這個定時器的作用是,如果超過 60s 還沒有接收到客戶端發來的請求,那么就會斷開連接,這一部分走完之后,Nginx 的事件模塊可能就會切換到其他的句柄去處理了,

當用戶真的把請求發來之后,作業系統會回復一個 ACK,同時事件模塊的 epoll_wait 也拿到了這個請求,這個時候會呼叫設定的回呼方法 ngx_http_wait_request_handler,將接收到的用戶請求讀到用戶態中,而讀取到用戶態中需要作業系統分配記憶體,那么這段記憶體分配多大?從哪里分配呢?
這段記憶體是從連接記憶體池分配的,初始雖然分配了 512 位元組,但是記憶體池可以擴展,由 client_header_buffer_size: 1k 分配 1k 記憶體,記憶體池并不是越大越好,因為用戶即使發送了 1 個位元組,也會分配出 1k 的記憶體出來,當 URL 超過 1k 后,應該怎么辦呢?
接收請求 HTTP 模塊

處理請求和處理連接是不一樣的,處理請求只需要放到 Nginx 記憶體中就行了,但是處理請求還需要做大量的背景關系分析,所以要分配一個請求記憶體池 request_pool_size: 4k,分配完以后,狀態機開始決議請求行,如果這時候發現 URL 大于 4k,那么就會再分配一個大記憶體,也就是 large_client_header_buffers: 4 8k,這個配置的意思是說,最多分配 4 個 8k,它并不是一次性分配 32k,而是先分配 8k 然后再去決議請求行,如果依然大于 8k,那么就會再分配 8k 的記憶體,
Nginx 有很多變數,這些變數都是指標,其中可以用來標識 URI,標識完成之后,就開始處理 header,狀態機決議 header 的時候,如果發現記憶體不夠,也就是假如 URL 已經用掉了 large_client_header_buffers: 4 8k 中的 2 個 8k,這時候最多也只能分配 8k,請求行和 header 是公用 4 個 8k的,
分配完大記憶體之后,就開始標識 header,確定哪一個 server 塊去處理請求,然后移除超時定時器,接下來,就開始核心的 11 個階段 HTTP 請求處理請求,
這里需要注意以下幾個地方:
- 連接記憶體池:初始大小 512 位元組
client_header_buffer_size: 1k從連接記憶體池中分配large_client_header_buffers: 4 8k也是從連接記憶體池中分配
- 請求記憶體池:
request_pool_size: 4k
公眾號「原少子楊」回復 Nginx 領取知識圖譜

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/107387.html
標籤:Linux
上一篇:lvs中虛擬IP地址疑問
