151Nginx 運(yùn)維基礎(chǔ)入門--Nginx進(jìn)程與模塊

實(shí)驗(yàn)原理

下面介紹一些實(shí)驗(yàn)原理相關(guān)內(nèi)容。
實(shí)驗(yàn)原理的簡(jiǎn)介包含以下部分:
Nginx 架構(gòu)介紹
Nginx 進(jìn)程介紹
Nginx 模塊介紹

Nginx 架構(gòu)介紹

Nginx 的代碼是由一個(gè) 核心 和一系列的 模塊 組成。
核心
核心的功能如下:
主要用于提供 WebServer 的基本功能;
實(shí)現(xiàn) Web 和 Mail 反向代理的功能;
還用于啟用網(wǎng)絡(luò)協(xié)議;
創(chuàng)建必要的運(yùn)行時(shí)環(huán)境以及確保不同的模塊之間平滑地進(jìn)行交互。
模塊
大多跟協(xié)議相關(guān)的功能和應(yīng)用特有的功能都是由 Nginx 的模塊實(shí)現(xiàn)的。
這些功能模塊大致可以分為:事件模塊、階段性處理器、輸出過濾器、變量處理器、協(xié)議、upstream 和負(fù)載均衡幾個(gè)類別,這些功能模塊共同組成了 Nginx 的 http 功能。

其中:
事件模塊主要用于提供 OS 獨(dú)立的(不同操作系統(tǒng)的事件機(jī)制有所不同)事件通知機(jī)制,如 kqueue 或 epoll 等。
協(xié)議模塊則負(fù)責(zé)實(shí)現(xiàn) Nginx 通過 HTTP、TLS/SSL、SMTP、POP3 以及 IMAP 與對(duì)應(yīng)的客戶端建立會(huì)話。

在 Nginx 內(nèi)部,進(jìn)程間的通信是通過模塊的 pipeline 或 chain 實(shí)現(xiàn)的。
每一個(gè)功能或操作都由一個(gè)模塊來實(shí)現(xiàn)。例如:壓縮、通過 FastCGI 或 uwsgi 協(xié)議與 upstream 服務(wù)器通信、以及與 memcached 建立會(huì)話等。

Nginx 進(jìn)程介紹

首先我們要知道,Nginx 是以多進(jìn)程的方式來工作的,當(dāng)然 Nginx 也是支持多線程的方式的。
Nginx 啟動(dòng)后,在 Unix 系統(tǒng)中會(huì)以 daemon (守護(hù)進(jìn)程)的方式在后臺(tái)運(yùn)行,后臺(tái)進(jìn)程包含一個(gè) master 進(jìn)程和多個(gè) worker 進(jìn)程(你可以理解為工人和管理員)。
這里就主要講解 Nginx 的多進(jìn)程模式。
Nginx 處理連接的過程
Nginx 不會(huì)為每個(gè)連接派生進(jìn)程或線程,而是由 worker 進(jìn)程通過監(jiān)聽共享套接字接收新請(qǐng)求,并且使用高效的循環(huán)來處理數(shù)千個(gè)連接。
Nginx 不使用仲裁器或分發(fā)器來分發(fā)連接,這個(gè)工作由操作系統(tǒng)內(nèi)核機(jī)制完成。
監(jiān)聽套接字在啟動(dòng)時(shí)就完成初始化,worker 進(jìn)程通過這些套接字接收、讀取請(qǐng)求和輸出響應(yīng)。
master 進(jìn)程
當(dāng) Nginx 在啟動(dòng)后,會(huì)有一個(gè) master 進(jìn)程和多個(gè) worker 進(jìn)程。
master 進(jìn)程主要用來管理 worker 進(jìn)程,master 要做的就是:接收來自外界的信號(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)程。

master 進(jìn)程主要完成如下工作:
讀取并驗(yàn)證配置信息;
創(chuàng)建、綁定及關(guān)閉套接字;
啟動(dòng)、終止 worker 進(jìn)程及維護(hù) worker 進(jìn)程的個(gè)數(shù);
無須中止服務(wù)而重新配置工作;
控制非中斷式程序升級(jí),啟用新的二進(jìn)制程序并在需要時(shí)回滾至老版本;
重新打開日志文件;
編譯嵌入式 Perl 腳本。
worker 進(jìn)程
對(duì)于基本的網(wǎng)絡(luò)事件,Nginx 則是放在 worker 進(jìn)程中來處理。多個(gè) worker 進(jìn)程之間是對(duì)等的,他們同等競(jìng)爭(zhēng)來自客戶端的請(qǐng)求,各進(jìn)程互相之間是獨(dú)立的。
一個(gè)請(qǐng)求,只可能在一個(gè) worker 進(jìn)程中處理,一個(gè) worker 進(jìn)程,不可能處理其它進(jìn)程的請(qǐng)求(一對(duì)一)。
然而 Nginx 沒有專門地仲裁或連接分布的 worker,這項(xiàng)工作是由操作系統(tǒng)內(nèi)核機(jī)制完成的。在啟動(dòng)時(shí),創(chuàng)建一組初始的監(jiān)聽套接字,HTTP 請(qǐng)求和響應(yīng)之時(shí),worker 連續(xù)接收、讀取和寫入套接字。

worker 進(jìn)程主要完成如下工作:
接收、傳入并處理來自客戶端的連接
提供反向代理及過濾功能
nginx 任何能完成的其它任務(wù)
Nginx 的進(jìn)程模型

image.png

上圖是 Nginx 的進(jìn)程模型,下面我們會(huì)簡(jiǎn)單講解圖中不同部分的含義:

既然 worker 進(jìn)程之間是平等的,每個(gè)進(jìn)程,處理請(qǐng)求的機(jī)會(huì)也是一樣的。當(dāng)我們提供 80 端口的 http 服務(wù)時(shí),一個(gè)連接請(qǐng)求過來,每個(gè)進(jìn)程都有可能處理這個(gè)連接。那么問題來了,到底最后怎樣處理,是由什么決定的呢?我們來看一看一個(gè)完整的請(qǐng)求是怎樣通過互相的協(xié)作來實(shí)現(xiàn)的:
(1)首先,每個(gè) worker 進(jìn)程都是從 master 進(jìn)程 fork 過來,在 master 進(jìn)程里面,先建立好需要 listen 的 socket(listenfd)之后,然后再 fork 出多個(gè) worker 進(jìn)程。
(2)所有 worker 進(jìn)程的 listenfd 會(huì)在新連接到來時(shí)變得可讀,為保證只有一個(gè)進(jìn)程處理該連接,所有 worker 進(jìn)程會(huì)在注冊(cè) listenfd 讀事件前搶 accept_mutex,搶到互斥鎖的那個(gè)進(jìn)程注冊(cè) listenfd 讀事件,然后在讀事件里調(diào)用 accept 接受該連接。
(3)當(dāng)一個(gè) worker 進(jìn)程在 accept 這個(gè)連接之后,就開始讀取請(qǐng)求、解析請(qǐng)求、處理請(qǐng)求。產(chǎn)生數(shù)據(jù)后,再返回給客戶端,最后才斷開連接,這樣一個(gè)完整的請(qǐng)求就是這樣的了。

我們可以看到:一個(gè)請(qǐng)求,完全由 worker 進(jìn)程來處理,而且只在一個(gè) worker 進(jìn)程中處理。
也許你還有個(gè)疑問,那就是 Nginx 采用多 worker 的方式來處理請(qǐng)求,每個(gè) worker 里面只有一個(gè)主線程,那能夠處理的并發(fā)數(shù)很有限啊,多少個(gè) worker 就能處理多少個(gè)并發(fā),何來高并發(fā)呢?這就是 Nginx 的高明之處,Nginx 采用了 異步非阻塞 的方式來處理請(qǐng)求,也就是說,Nginx 是可以同時(shí)處理成千上萬個(gè)請(qǐng)求的。

這里補(bǔ)充一下異步非阻塞的概念:
異步的概念是和同步相對(duì)的,也就是不同事件之間不是同時(shí)發(fā)生的。
非阻塞的概念是和阻塞對(duì)應(yīng)的,阻塞是事件按順序執(zhí)行,每一事件都要等待上一事件的完成,而非阻塞是如果事件沒有準(zhǔn)備好,這個(gè)事件可以直接返回,過一段時(shí)間再進(jìn)行處理詢問,這期間可以做其他事情。

Nginx 模塊介紹

Nginx 真正的魅力在于它的模塊,整個(gè)應(yīng)用程序建立在一個(gè)模塊化系統(tǒng)之上,在編譯時(shí),可以對(duì)每一個(gè)模塊進(jìn)行啟用或者禁用,需要什么就定制什么。
對(duì) Nginx 模塊的基本原理總結(jié)一下,基本就是:在特定地方調(diào)用函數(shù)。(Nginx 本身支持多種模塊,如 HTTP 模塊、EVENTS 模塊和 MAIL 模塊,這里只簡(jiǎn)單講述 HTTP 的模塊及其中的命令)
下面是配置文件結(jié)構(gòu)圖:


image.png

Nginx 本身做的工作實(shí)際很少,當(dāng)它接到一個(gè) HTTP 請(qǐng)求時(shí),它僅僅是通過查找配置文件將此次請(qǐng)求映射到一個(gè) location block,而此 location 中所配置的各個(gè)指令則會(huì)啟動(dòng)不同的模塊去完成工作,因此模塊可以看做 Nginx 真正的勞動(dòng)工作者。

通常一個(gè) location 中的指令會(huì)涉及一個(gè) handler 模塊和多個(gè) filter 模塊(當(dāng)然,多個(gè) location 可以復(fù)用同一個(gè)模塊)。
handler 模塊負(fù)責(zé)處理請(qǐng)求,完成響應(yīng)內(nèi)容的生成;
filter 模塊對(duì)響應(yīng)內(nèi)容進(jìn)行處理。

因此 Nginx 模塊開發(fā)分為 handler 開發(fā)和 filter 開發(fā)(本文不考慮 load-balancer 模塊)。
下圖展示了一次常規(guī)請(qǐng)求和響應(yīng)的過程。


image.png

http index 模塊

模塊:ngx_http_index_module
語法:

index file ...;

配置范例:

location / {
    index index.$geo.html index.html;
}

默認(rèn)值:index index.html;
作用域:http, server, location

模塊功能及注意:
定義將要被作為默認(rèn)頁(yè)的文件。
文件的名字可以包含變量。
文件以配置中指定的順序被 Nginx 檢查。
列表中的最后一個(gè)元素可以是一個(gè)帶有絕對(duì)路徑的文件。

例子:

index index.$geo.html index.0.html /index.html;

需要注意的是,index 文件會(huì)引發(fā)內(nèi)部重定向,請(qǐng)求可能會(huì)被其它 location 處理。 比如,下面這個(gè)例子:

location = / {
    index index.html;
}

location / {
    ...
}

請(qǐng)求 / 實(shí)際上將會(huì)在第二個(gè) location 中作為 /index.html 被處理。

http log 模塊

模塊:ngx_http_log_module
配置范例:

log_format  gzip '$remote_addr-$remote_user[$time_local]' '$request$status $bytes_sent' '"$ http _ referer" "$http_user_agent" "$gzip_ratio"';
access_log  /spool/logs/nginx-access.log  gzip  buffer=32k;

access_log 指令
語法:

access_log path [format [buffer=size]];
# or
access_log off;

默認(rèn)值:access_log log/access.log combined
作用域:http, server, location

指令功能及注意:
指令 access_log 指派路徑、格式和緩存大小。
參數(shù) "off" 將清除當(dāng)前級(jí)別的所有 access_log 指令。
如果未指定格式,則使用預(yù)置的 "combined" 格式。
緩存不能大于能寫入磁盤的文件的最大值。在 FreeBSD 3.0-6.0 ,緩存大小無此限制。

log_format 指令
語法:

log_format name format [format ...];

默認(rèn)值: log_format combined "..."
作用域: http server

Access 模塊

模塊:ngx_http_access_module

模塊功能及注意:
此模塊提供了一個(gè)簡(jiǎn)易的基于主機(jī)的訪問控制(對(duì)網(wǎng)絡(luò)地址有放行和禁止的權(quán)利),使 Nginx 可以對(duì)特定 IP 客戶端進(jìn)行控制。
規(guī)則為:順序匹配,以第一次匹配到的結(jié)果為準(zhǔn)。

配置范例:

location / {
  deny    192.168.1.1;
  allow   192.168.1.0/24;
  allow   10.1.1.0/16;
  deny    all;
}

在上面的例子中,僅允許網(wǎng)段 10.1.1.0/16 和 192.168.1.0/24 中除 192.168.1.1 之外的 ip 訪問。
放行語法

allow address | CIDR | all;

在上面的配置范例中, 192.168.1.1 為 address,192.168.1.0/24 為 CIDR,all 對(duì)應(yīng) all。

作用域:http, server, location, limit_except
指令功能:allow 描述的網(wǎng)絡(luò)地址有權(quán)直接訪問
禁止語法

deny address | CIDR | all;

作用域:http, server, location, limit_except
指令功能:deny 描述的網(wǎng)絡(luò)地址拒絕訪問

Rewrite 模塊

模塊:ngx_http_rewrite_module

模塊功能及注意:
執(zhí)行 URL 重定向,允許你去掉帶有惡意的 URL,包含多個(gè)參數(shù)(修改)
利用正則的匹配,分組和引用,達(dá)到目的

配置范例:

if ($http_user_agent ~ MSIE) {
  rewrite  ^(.*)$  /msie/$1  break;
}
if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {
  set  $id  $1;
}
if ($request_method = POST ) {
  return 405;
}
if (!-f $request_filename) {
  break;
  proxy_pass  http://127.0.0.1;
}
if ($slow) {
  limit_rate  10k;
}
if ($invalid_referer) {
  return   403;
}

該模塊允許使用正則表達(dá)式改變 URL,并且根據(jù)變量來轉(zhuǎn)向以及選擇配置
if 語句塊
語法:

if (condition) {
  ...
}

功能描述:對(duì)重定向進(jìn)行流程控制
作用域:server, location
return 語句
語法:

return code;

作用域:server, location, if

功能描述:這個(gè)指令根據(jù)規(guī)則的執(zhí)行情況,返回一個(gè)狀態(tài)值給客戶端。
可使用值包括:204,400,402 - 406,408,410,411,413,416 及 500 - 504。
也可以發(fā)送非標(biāo)準(zhǔn)的 444 代碼 - 未發(fā)送任何頭信息,然后結(jié)束連接。
rewrite 語句
語法:

rewrite regex replacement flag

regex :用于匹配 url 的正則表達(dá)式。使用括號(hào)()標(biāo)記要截取的內(nèi)容
replacement : 匹配成功后用于替換 url 中被截取內(nèi)容的字符串
flag : 用來設(shè)置 rewrite 對(duì) url 的處理行為

常用的 flag 如下:
last : 表示完成 rewrite
break : 本規(guī)則匹配完成后,終止匹配,不再匹配后面的規(guī)則
redirect : 返回 302 臨時(shí)重定向,地址欄會(huì)顯示跳轉(zhuǎn)后的地址
permanent : 返回 301 永久重定向,地址欄會(huì)顯示跳轉(zhuǎn)后的地址

作用域:server, location, if
功能描述:這個(gè)指令根據(jù)正則表達(dá)式或者待替換的字符串來更改 URL。指令根據(jù)配置文件中的先后順序執(zhí)行生效。

Proxy 模塊

模塊:ngx_http_proxy_module

功能描述:此模塊能代理請(qǐng)求到其它服務(wù)器。就是說允許你把客戶端的 HTTP 請(qǐng)求轉(zhuǎn)到后端服務(wù)器(這部分的指令非常多,但不是全部都會(huì)被用到,這里是比較常見的指令簡(jiǎn)介)。

指令:proxy_pass_header Server;
功能描述:該指令強(qiáng)制一些被忽略的頭傳遞到客戶端。

指令:proxy_redirect off;
功能描述:允許改寫出現(xiàn)在 HTTP 頭卻被后端服務(wù)器觸發(fā)重定向的 URL,對(duì)響應(yīng)本身不做任何處理。

指令:proxy_set_header Host $http_host;
功能描述:允許你重新定義代理 header 值再轉(zhuǎn)到后端服務(wù)器,目標(biāo)服務(wù)器可以看到客戶端的原始主機(jī)名。

指令: proxy_set_header X-Real-IP $remote_addr;
功能描述:目標(biāo)服務(wù)器可以看到客戶端的真實(shí) IP,而不是轉(zhuǎn)發(fā)服務(wù)器的 IP。

proxy 更多的指令查詢

upstream 模塊

模塊:ngx_http_upstream_module
語法:

upstream name {
  ...
}

功能簡(jiǎn)介:該指令使請(qǐng)求被上行信道之間的基于客戶端的 IP 地址分布
配置范例:

upstream backend  {
  server backend1.example.com weight=5;
  server backend2.example.com:8080;
  server unix:/tmp/backend3;
}

server {
  location / {
    proxy_pass  http://backend;
  }
}

upstream 指令
語法:

upstream name { ... }

作用域:http

指令功能及注意:
這個(gè)指令描述了一個(gè)服務(wù)器的集合,該集合可被用于 proxy_pass 和 fastcgi_pass 指令中,作為一個(gè)單獨(dú)的實(shí)體。
這些服務(wù)器可以是監(jiān)聽在不同的端口,另外,并發(fā)使用同時(shí)監(jiān)聽 TCP 端口和 Unix 套接字的服務(wù)器是可能的。
這些服務(wù)器能被分配不同的權(quán)重。如果沒有指定,則都為 1 。

示例:

upstream backend {
  server backend1.example.com weight=5;
  server 127.0.0.1:8080 max_fails=3  fail_timeout=30s;
  server unix:/tmp/backend3;
}

ip_hash 指令
作用域: upstream

upstream backend {
  ip_hash;
  server   backend1.example.com;
  server   backend2.example.com;
  server   backend3.example.com;
  server   backend4.example.com;
}

指令功能及注意:
指定服務(wù)器組的負(fù)載均衡方法,請(qǐng)求基于客戶端的 IP 地址在服務(wù)器間進(jìn)行分發(fā)。IPv4 地址的前三個(gè)字節(jié)或者 IPv6 的整個(gè)地址,會(huì)被用來作為一個(gè)散列 key。
這種方法可以確保從同一個(gè)客戶端過來的請(qǐng)求,會(huì)被傳給同一臺(tái)服務(wù)器。除了當(dāng)服務(wù)器被認(rèn)為不可用的時(shí)候,這些客戶端的請(qǐng)求會(huì)被傳給其他服務(wù)器,而且很有可能也是同一臺(tái)服務(wù)器。

如果其中一個(gè)服務(wù)器想暫時(shí)移除,應(yīng)該加上 down 參數(shù)。這樣可以保留當(dāng)前客戶端 IP 地址散列分布。就像這樣:

upstream backend {
  ip_hash;
  server   backend1.example.com;
  server   backend2.example.com;
  server   backend3.example.com  down;
  server   backend4.example.com;
}

server 指令
語法:

server address [parameters];

作用域: upstream

指令功能及注意:
定義服務(wù)器的地址 address 和其他參數(shù) parameters。
地址可以是域名或者 IP 地址,端口是可選的,或者是指定“unix:”前綴的 UNIX 域套接字的路徑。如果沒有指定端口,就使用 80 端口。
如果一個(gè)域名解析到多個(gè) IP,本質(zhì)上是定義了多個(gè) server。

實(shí)例:

upstream  backend  {
  server   backend1.example.com    weight=5;
  server   127.0.0.1:8080          max_fails=3  fail_timeout=30s;
  server   unix:/tmp/backend3;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容