面試官:說說看Nginx是如何處理請求的?為什么Nginx不采用多線程模型?Nginx負(fù)載均衡的算法有哪些?什么是正向和反向代理

面試官:說說看Nginx是如何處理請求的?
當(dāng)客戶端發(fā)起一個請求時,Nginx的工作進程會監(jiān)聽網(wǎng)絡(luò)端口,接收客戶端的連接請求。以下是Nginx處理請求的具體流程:
(1) 接收連接請求:Nginx接收到客戶端的連接請求后,會為該連接分配一個連接對象(ngx_connection_t)。連接對象包含連接的狀態(tài)信息、讀寫事件處理器等。
(2) 讀取請求頭信息:Nginx從客戶端讀取請求頭信息。請求頭包含HTTP方法(如GET、POST)、URL、HTTP版本以及各種請求頭字段(如Host、User-Agent、Content-Length等)。
(3) 解析請求頭信息:Nginx解析請求頭信息,提取必要的參數(shù),如請求方法、URI、Host等。解析后的請求頭信息存儲在ngx_http_request_t結(jié)構(gòu)體中。
(4) 查找匹配的虛擬主機和location塊:
- Nginx根據(jù)請求頭中的Host字段查找匹配的虛擬主機(server塊)。每個虛擬主機可以配置不同的域名和監(jiān)聽端口。
 - 在找到匹配的虛擬主機后,Nginx繼續(xù)查找與請求URI匹配的location塊。location塊定義了如何處理特定路徑的請求。
 
(5) 執(zhí)行處理階段:Nginx的請求處理分為多個階段,每個階段可以由多個模塊處理。這些階段包括:
- rewrite phase:執(zhí)行重寫規(guī)則,如URL重寫。
 - post rewrite phase:處理重寫后的請求。
 - preaccess phase:執(zhí)行訪問控制前的檢查,如IP地址過濾。
 - access phase:執(zhí)行訪問控制,如身份驗證。
 - postaccess phase:訪問權(quán)限控制后的處理。
 - try-files:嘗試訪問文件或目錄。
 - content phase:生成響應(yīng)內(nèi)容,如靜態(tài)文件服務(wù)、反向代理、FastCGI等。在這個階段,Nginx根據(jù)配置生成響應(yīng)內(nèi)容,這可能涉及讀取靜態(tài)文件、調(diào)用后端服務(wù)(如反向代理、FastCGI、uWSGI等)、生成動態(tài)內(nèi)容等。
 
(6) 生成并發(fā)送響應(yīng):
- Nginx將生成的響應(yīng)頭發(fā)送回客戶端。響應(yīng)頭包含HTTP狀態(tài)碼、響應(yīng)頭字段(如Content-Type、Content-Length等)。
 - Nginx將生成的響應(yīng)體發(fā)送回客戶端。響應(yīng)體可以是靜態(tài)文件內(nèi)容、后端服務(wù)返回的數(shù)據(jù)等。
 
(7) 關(guān)閉連接:一旦響應(yīng)發(fā)送完畢,Nginx會關(guān)閉連接。如果啟用了keep-alive連接,則連接可以保持打開狀態(tài),用于后續(xù)請求。
面試官:說說看Nginx的進程架構(gòu)是怎樣的?為什么Nginx不使用多線程模型?

1. 進程模型
Nginx采用Master-Worker多進程架構(gòu),這種架構(gòu)的設(shè)計可以確保責(zé)任分離,以便更好地管理系統(tǒng)資源、并發(fā)請求處理與故障恢復(fù)。
(1) Master-Worker架構(gòu):
① 主進程(Master Process):
- Nginx的核心組件,負(fù)責(zé)初始化Nginx、加載配置文件、創(chuàng)建Worker進程等。
 - 監(jiān)聽配置文件的變更,并在不重啟的情況下重新加載配置。
 - 管理Worker進程的生命周期,包括啟動、停止和管理Worker進程。
 - 不直接處理客戶端的請求,而是用于控制和管理Worker進程。
 
② 工作進程(Worker Process)
- Nginx的工作進程,負(fù)責(zé)處理客戶端的請求。
 - 每個Worker進程都是一個完整的Nginx服務(wù)器,多個Worker進程之間是對等的。
 - 每個Worker進程可以處理成千上萬的并發(fā)連接,Nginx的事件模型可以根據(jù)系統(tǒng)負(fù)載自動選擇合適的事件通知機制(如epoll)。
 
(2) 進程間協(xié)作:
- Master進程和Worker進程之間通過信號和共享內(nèi)存進行通信。Master進程會向Worker進程發(fā)送信號以管理它們的生命周期(如啟動、停止、重啟等)。
 - Worker進程之間通過共享內(nèi)存和進程間通信(IPC)機制進行必要的數(shù)據(jù)共享和同步。
 
(3) 負(fù)載均衡:
Nginx通過多進程模型實現(xiàn)了負(fù)載均衡。當(dāng)有新的客戶端連接請求到達(dá)時,這些連接會被平均分配給各個Worker進程,從而實現(xiàn)負(fù)載均衡。這種設(shè)計確保了Nginx能夠高效地處理大量并發(fā)連接,避免了單個進程成為瓶頸。
(4) 高可用性:
Nginx的多進程模型還提供了高可用性。當(dāng)一個Worker進程出現(xiàn)故障時,Master進程會自動重新啟動一個新的Worker進程來替代原來的進程,從而保證服務(wù)器的高可用性。這種設(shè)計使得Nginx能夠在高負(fù)載和復(fù)雜環(huán)境下穩(wěn)定運行。
2. 為什么Nginx不使用多線程模型?
Nginx選擇不使用多線程模型,而是采用多進程加異步非阻塞I/O的事件驅(qū)動模型,主要基于以下幾個原因:
(1) 資源隔離與穩(wěn)定性
- 多進程模型下,每個工作進程都是獨立的,它們之間不會共享內(nèi)存空間(除了通過共享內(nèi)存等特定機制進行通信)。這種隔離性使得一個工作進程的崩潰不會影響到其他進程,從而提高了整個系統(tǒng)的穩(wěn)定性。
 - 在多線程模型中,線程之間共享進程的內(nèi)存空間,這可能導(dǎo)致線程間的數(shù)據(jù)競爭、死鎖等問題,增加了系統(tǒng)的復(fù)雜性和調(diào)試難度。
 
(2) 利用多核CPU
- Nginx的多進程模型可以很好地利用現(xiàn)代操作系統(tǒng)提供的進程調(diào)度機制,將工作進程分配到不同的CPU核心上運行,從而實現(xiàn)并行處理。
 - 雖然多線程模型也可以利用多核CPU,但線程的創(chuàng)建、切換和同步開銷通常比進程更高,尤其是在高并發(fā)場景下。
 
(3) 避免線程競爭和死鎖
- 在多線程模型中,多個線程可能同時訪問共享資源(如內(nèi)存、文件等),這需要使用鎖機制來確保數(shù)據(jù)的一致性和安全性。然而,鎖的使用往往會導(dǎo)致線程競爭和死鎖問題,降低系統(tǒng)的性能。
 - Nginx通過采用異步非阻塞I/O和事件驅(qū)動模型,避免了鎖的使用,從而減少了線程競爭和死鎖的風(fēng)險。
 
(4) 簡化編程模型
- Nginx的多進程加異步非阻塞I/O模型相對簡單明了,開發(fā)者可以更容易地理解和維護代碼。
 - 多線程編程往往涉及復(fù)雜的線程同步和通信機制,增加了編程的復(fù)雜性和出錯的可能性。
 
(5) 設(shè)計初衷
- Nginx的設(shè)計初衷就是為了提供一個高性能、低資源消耗的Web服務(wù)器和反向代理服務(wù)器。在設(shè)計之初,Nginx的開發(fā)者就選擇了多進程加異步非阻塞I/O的模型,并一直沿用至今。
 - Nginx的社區(qū)和開發(fā)者群體也傾向于保持這種設(shè)計哲學(xué),以確保Nginx的穩(wěn)定性和性能優(yōu)勢。
 
面試官:什么是正向代理和反向代理?Nginx如何實現(xiàn)正向代理和反向代理功能?
反向代理功能是指代理服務(wù)器接受互聯(lián)網(wǎng)上的連接請求,然后將這些請求轉(zhuǎn)發(fā)給內(nèi)部網(wǎng)絡(luò)上的服務(wù)器,并將從內(nèi)部服務(wù)器上得到的響應(yīng)返回給互聯(lián)網(wǎng)上請求連接的客戶端。在這個過程中,代理服務(wù)器在外部世界中顯示為服務(wù)器。
一般來說反向代理中代理服務(wù)器和后臺服務(wù)是一伙兒的,綁定在一起??蛻舳瞬恢雷约簩嶋H請求的到底是誰。

現(xiàn)實中的反向代理例子有:負(fù)載均衡服務(wù)器、網(wǎng)絡(luò)安全防護(防DDoS攻擊) 和內(nèi)容分發(fā)網(wǎng)絡(luò) CDN等。
Nginx實現(xiàn)反向代理功能主要通過配置Nginx服務(wù)器,使其成為客戶端和目標(biāo)服務(wù)器之間的中介。以下是Nginx實現(xiàn)反向代理功能的具體步驟和要點:
(1) 配置Nginx:
Nginx的反向代理配置主要在nginx.conf文件中進行,或者在包含的子配置文件中進行。
- 監(jiān)聽端口:設(shè)置Nginx監(jiān)聽的端口,默認(rèn)為80端口,用于接收HTTP請求。
 - 服務(wù)器名稱:定義Nginx服務(wù)器響應(yīng)的域名。
 - location塊:根據(jù)請求的URI進行匹配,并定義相應(yīng)的操作,如反向代理。
 - 反向代理指令(proxy_pass):指定請求應(yīng)被轉(zhuǎn)發(fā)到的后端服務(wù)器的URL。
 
(2) 配置示例:
一個基本的反向代理配置示例如下:
http {
    server {
        listen 80;  # 監(jiān)聽80端口
        server_name example.com;  # 服務(wù)器名稱
        location / {
            proxy_pass http://backend-server:8080;  # 后端服務(wù)器地址與端口
            proxy_set_header Host $host;  # 保留原始Host頭
            proxy_set_header X-Real-IP $remote_addr;  # 傳遞真實客戶端IP
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;  # 傳遞請求協(xié)議(http/https)
            # 其他可選配置,如緩存、超時、重試等
        }
    }
}正向代理用于將客戶端的請求轉(zhuǎn)發(fā)到目標(biāo)服務(wù)器,并將服務(wù)器的響應(yīng)返回給客戶端。在這種方式下,客戶端將請求發(fā)送給代理服務(wù)器,由代理服務(wù)器代替客戶端向目標(biāo)服務(wù)器發(fā)出請求,并將目標(biāo)服務(wù)器的響應(yīng)返回給客戶端。通過正向代理,客戶端可以直接訪問外部網(wǎng)絡(luò),而無需直接與目標(biāo)服務(wù)器建立連接。

現(xiàn)實中的正向代理例子有:VPN。
Nginx作為高性能的Web服務(wù)器和反向代理服務(wù)器,也可以實現(xiàn)正向代理功能。以下是Nginx實現(xiàn)正向代理的具體步驟和配置方法:
Nginx正向代理的配置方法
由于默認(rèn)的Nginx發(fā)布版本不支持正向代理功能,需要借助ngx_http_proxy_connect_module這個第三方插件來完成。在配置文件中添加正向代理的配置,例如:
server {
    listen 3128;  # 監(jiān)聽端口
    resolver 114.114.114.114;  # DNS解析器
    proxy_connect;  # 允許CONNECT請求
    proxy_connect_allow 443 563;  # 允許連接的端口
    proxy_connect_connect_timeout 10s;  # 連接超時時間
    proxy_connect_data_timeout 10s;  # 數(shù)據(jù)傳輸超時時間
    location / {
        proxy_pass http://$host;  # 轉(zhuǎn)發(fā)請求到目標(biāo)服務(wù)器
        proxy_set_header Host $host;  # 設(shè)置請求頭
    }
}以上配置中,listen指令指定了Nginx監(jiān)聽的端口,resolver指令指定了DNS解析器的地址,proxy_connect等指令用于配置CONNECT請求的處理,location指令和proxy_pass指令則用于指定將請求轉(zhuǎn)發(fā)到哪個目標(biāo)服務(wù)器。
面試官:什么是動態(tài)資源、靜態(tài)資源分離?為什么要做動、靜分離?Nginx怎么做的動靜分離?
動態(tài)資源與靜態(tài)資源分離(簡稱動、靜分離)是一種常見的Web應(yīng)用架構(gòu)模式。
1. 動態(tài)資源與靜態(tài)資源
(1) 靜態(tài)資源
當(dāng)用戶多次訪問某個資源時,如果資源的源代碼不會發(fā)生改變,那么該資源就被稱為靜態(tài)資源。常見的靜態(tài)資源包括圖片(img)、樣式表(css)、腳本文件(js)、視頻(mp4)等。這些資源通??梢员粸g覽器和CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))緩存,以減少對服務(wù)器的重復(fù)請求。
(2) 動態(tài)資源當(dāng)
用戶多次訪問某個資源時,如果資源的源代碼可能會發(fā)生變化,那么該資源就被稱為動態(tài)資源。常見的動態(tài)資源包括JSP、FTL等服務(wù)器端腳本或模板文件。這些資源通常需要根據(jù)用戶的請求動態(tài)生成響應(yīng)內(nèi)容。
2. 動、靜分離的原因
(1) 性能優(yōu)化
動態(tài)內(nèi)容和靜態(tài)內(nèi)容在處理和分發(fā)上存在差異。將它們分離可以分別進行優(yōu)化,從而提高整體性能。例如,靜態(tài)資源可以由專門的靜態(tài)資源服務(wù)器(如Nginx)直接處理和提供,而動態(tài)資源則由應(yīng)用服務(wù)器處理。這樣可以顯著減少對動態(tài)資源服務(wù)器的請求量,降低其負(fù)載。
(2) 緩存管理
靜態(tài)資源易于被緩存,而動態(tài)資源通常不適宜緩存或需要更精細(xì)的緩存控制。通過動、靜分離,可以更好地管理緩存策略,提高緩存命中率,減少服務(wù)器響應(yīng)時間和帶寬消耗。
(3) 負(fù)載均衡
分離后,可以根據(jù)內(nèi)容類型對資源進行優(yōu)化分配,實現(xiàn)更有效的負(fù)載均衡。例如,可以根據(jù)動態(tài)資源的訪問量和特點,針對性地增加動態(tài)資源服務(wù)器的數(shù)量和規(guī)模,以應(yīng)對高并發(fā)的訪問需求。
(4) 安全性增強
靜態(tài)內(nèi)容服務(wù)器通常不需要執(zhí)行復(fù)雜的程序代碼,因此攻擊面較小,可以降低安全風(fēng)險。將其與執(zhí)行動態(tài)代碼的服務(wù)器分離可以降低潛在的安全威脅。
以下是Nginx動靜分離的具體實現(xiàn)方式:
3. 配置方法
在Nginx中,可以通過location指令來實現(xiàn)動靜分離。location指令用于匹配請求的URI,并根據(jù)不同的路徑將請求分發(fā)給不同的處理模塊。
(1) 靜態(tài)資源處理
在上述配置中,location /static/和location /images/分別匹配以/static/和/images/開頭的請求,Nginx將在指定的root目錄下查找對應(yīng)的文件。如果文件存在,Nginx會直接將文件返回給客戶端。location ~* \.(jpg|jpeg|png|gif|ico|css|js)$使用正則表達(dá)式匹配所有以這些擴展名結(jié)尾的請求,并設(shè)置緩存過期時間和Cache-Control頭部。
靜態(tài)資源通常直接由Nginx處理,因此可以在location塊中指定靜態(tài)資源的目錄。
使用正則表達(dá)式匹配靜態(tài)資源的文件擴展名,如.jpg、.jpeg、.png、.gif、.ico、.css、.js等。
配置示例:
server {
	listen 80;
	server_name www.example.com;
	
	# 靜態(tài)資源處理
	location /static/ {
		root /var/www/example;
	}
	location /images/ {
		root /var/www/example;
	}
	location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
		root /var/www/example;
		expires 30d;  # 設(shè)置靜態(tài)資源的緩存過期時間
		add_header Cache-Control "public";  # 添加Cache-Control頭部,強化瀏覽器緩存行為
	}
}(2) 動態(tài)請求處理
對于動態(tài)請求,可以將請求轉(zhuǎn)發(fā)給后端應(yīng)用服務(wù)器(如PHP-FPM、Django、Node.js等)處理。
配置示例:
server {
	listen 80;
	server_name www.example.com;
	
	# 動態(tài)請求處理
	location ~ \.php$ {
		root /var/www/example;
		fastcgi_pass 127.0.0.1:9000;  # 指定將這些請求轉(zhuǎn)發(fā)給PHP-FPM服務(wù)器處理
		fastcgi_index index.php;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		include fastcgi_params;
	}
}在上述配置中,location ~ \.php$使用正則表達(dá)式匹配所有以.php結(jié)尾的請求,并將這些請求視為動態(tài)請求。fastcgi_pass指定將這些請求轉(zhuǎn)發(fā)給PHP-FPM服務(wù)器處理,127.0.0.1:9000是PHP-FPM的監(jiān)聽地址。其他參數(shù)用于設(shè)置FastCGI參數(shù)和請求的文件路徑。
4. 注意事項
(1) Nginx的location匹配優(yōu)先級
Nginx的location匹配遵循特定的優(yōu)先級規(guī)則,包括精確匹配(使用=符號)、正則表達(dá)式匹配(使用~或~*)、前綴匹配(普通location)。在配置多個location塊時,需要謹(jǐn)慎考慮它們之間的優(yōu)先級關(guān)系,以確保正確的請求路由。
(2) 緩存策略
通過合理配置緩存,可以顯著提高網(wǎng)站性能。Nginx提供了強大而靈活的緩存功能,可以通過proxy_cache_path和proxy_cache指令來實現(xiàn)。對于靜態(tài)資源,可以設(shè)置較長的緩存過期時間,以減少對服務(wù)器的重復(fù)請求。
(3) 安全性
通過動靜分離,可以將靜態(tài)內(nèi)容服務(wù)器與執(zhí)行動態(tài)代碼的服務(wù)器分離,從而降低安全風(fēng)險。靜態(tài)內(nèi)容服務(wù)器通常不需要執(zhí)行復(fù)雜的程序代碼,因此攻擊面較小。
面試官:Nginx負(fù)載均衡的算法策略有哪些?
1. 輪詢(Round Robin)
原理:輪詢算法按照服務(wù)器列表的順序依次分發(fā)請求。當(dāng)一個新的請求到達(dá)時,Nginx會將其分配給列表中的下一個服務(wù)器,如果到達(dá)列表末尾,則重新開始循環(huán)。
特點:
- 簡單易用,無需額外配置。
 - 適用于后端服務(wù)器性能相近的情況,因為每個服務(wù)器都會輪流接收到請求。
 
http {
    upstream backend {
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com;
    }
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}2. 加權(quán)輪詢(Weighted Round Robin)
原理:在輪詢的基礎(chǔ)上,為每個服務(wù)器分配一個權(quán)重值。權(quán)重值越高的服務(wù)器,接收到的請求越多。Nginx會根據(jù)權(quán)重值來計算每個服務(wù)器接收請求的比例。
特點:
- 考慮了服務(wù)器性能的差異,可以靈活分配請求。
 - 需要手動配置權(quán)重值,以反映服務(wù)器的實際性能。
 - 適用于后端服務(wù)器性能不均衡的情況,可以更好地利用服務(wù)器資源。
 
http {
    upstream backend {
        server backend1.example.com weight=3;
        server backend2.example.com weight=2;
        server backend3.example.com weight=1;
    }
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}3. IP哈希(IP Hash)
原理:根據(jù)客戶端IP地址的哈希值來分配請求。Nginx會計算每個客戶端IP地址的哈希值,并使用該哈希值來選擇后端服務(wù)器。由于相同IP地址的哈希值相同,因此來自同一IP地址的請求總是被分配到同一臺后端服務(wù)器。
特點:
- 實現(xiàn)了會話粘性(Session Persistence),即同一個客戶端的請求總是被分配到同一臺后端服務(wù)器。
 - 適用于需要保持會話一致性的場景,如購物車、用戶會話等。
 - 但可能導(dǎo)致負(fù)載分布不均衡,因為某些IP地址范圍內(nèi)的客戶端可能會頻繁訪問同一臺服務(wù)器。
 
http {
    upstream backend {
        ip_hash;
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com;
    }
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}4. 最少連接(Least Connections)
原理:將請求分發(fā)到當(dāng)前連接數(shù)最少的服務(wù)器上。Nginx會監(jiān)控每臺后端服務(wù)器的當(dāng)前連接數(shù),并將新請求分配給連接數(shù)最少的服務(wù)器。
特點:
- 考慮了服務(wù)器的當(dāng)前負(fù)載情況,可以更有效地平衡負(fù)載。
 - 適用于長連接場景,如WebSocket、數(shù)據(jù)庫連接等。
 - 但需要Nginx維護連接狀態(tài),可能會增加一些開銷。
 - Nginx本身不直接支持此策略,通常需要借助第三方模塊或自定義腳本實現(xiàn)。
 
http {
    upstream backend {
        least_conn;
        server backend1.example.com;
        server backend2.example.com;
        server backend3.example.com;
    }
    server {
        location / {
            proxy_pass http://backend;
        }
    }
}5. Fair(第三方)
原理:根據(jù)后端服務(wù)器的響應(yīng)時間來分配請求。Nginx會監(jiān)控每臺后端服務(wù)器的響應(yīng)時間,并將新請求分配給響應(yīng)時間最短的服務(wù)器。
特點:
- 實現(xiàn)了更智能的負(fù)載均衡,可以根據(jù)服務(wù)器的實際性能來分配請求。
 - 適用于對響應(yīng)時間要求較高的場景。
 - 但需要安裝第三方模塊(如nginx-module-vts)來實現(xiàn)。
 
6. URL哈希(URL Hash,第三方)
原理:根據(jù)請求URL的哈希值來分配請求。Nginx會計算每個請求URL的哈希值,并使用該哈希值來選擇后端服務(wù)器。由于相同URL的哈希值相同,因此相同URL的請求總是被分配到同一臺后端服務(wù)器。
特點:
- 提高了緩存的命中率,因為相同URL的請求總是被分配到同一臺后端服務(wù)器。
 - 適用于緩存服務(wù)器集群。
 - 但同樣可能導(dǎo)致負(fù)載分布不均衡。
 - Nginx本身不支持此策略,需要安裝Nginx的hash軟件包來實現(xiàn)。
 















 
 
 










 
 
 
 