Nginx處理Web請(qǐng)求機(jī)制的方法詳解
一、Nginx請(qǐng)求默認(rèn)頁(yè)面資源
1、配置文件詳解
修改端口號(hào)為8080并重啟服務(wù):
二、Nginx進(jìn)程模型
1、nginx常用命令解析
master進(jìn)程:主進(jìn)程(只有一個(gè))
worker進(jìn)程:工作進(jìn)程(可以有多個(gè),默認(rèn)只有一個(gè)進(jìn)程)
生命周期的原理:
信號(hào): (操作人在執(zhí)行以下指令操作的時(shí)候,master會(huì)轉(zhuǎn)遞給worker相關(guān)的信息讓worker去進(jìn)行相關(guān)的操作)
./nginx #開(kāi)啟nginx服務(wù)。 ./nginx -s stop #暴力的關(guān)閉,如果后端有用戶在連接如果用此命令會(huì)導(dǎo)致連接全部中斷,如果發(fā)現(xiàn)有惡意攻擊和黑客入侵的情況下可以用此命令。 ./nginx -s stop #重新加載配置文件信息。 ./nginx -s quit #優(yōu)雅的關(guān)閉,如果后端有用戶在連接會(huì)等待連接完成之后再去關(guān)閉,同時(shí)不會(huì)讓新的請(qǐng)求訪問(wèn)進(jìn)來(lái)(只針對(duì)http請(qǐng)求如果不是http請(qǐng)求時(shí)不行的)。 ./nginx -t #檢測(cè)配置文件的語(yǔ)法是否正確。 ./nginx -v #查看當(dāng)前的配置信息。 ./nginx -V #顯示詳細(xì)信息,包括了nginx的版本、gcc版本、configure編譯路徑等。 ./nginx -c #代表手動(dòng)切換nginx的配置文件。 ./nginx -h & ./nginx -h #顯示nginx的幫助命令。
每個(gè)worker之間相對(duì)獨(dú)立,如果某個(gè)worker收到黑客的攻擊,那么運(yùn)維人員只需要關(guān)閉相關(guān)的worker進(jìn)程,如果某個(gè)worker進(jìn)程不存在只需要master重新fork以下即可。
2、修改worker的進(jìn)程數(shù)
三、Worker搶占機(jī)制
當(dāng)client發(fā)起了請(qǐng)求之后client和worker之間會(huì)有一個(gè)護(hù)事鎖(accept_mutex)服務(wù)端的眾多worker會(huì)去搶這個(gè)鎖,哪個(gè)worker搶到就由哪個(gè)worker來(lái)進(jìn)行處理。
四、傳統(tǒng)服務(wù)事件處理
假設(shè)一個(gè)client在進(jìn)行請(qǐng)求的時(shí)候由worker1來(lái)進(jìn)行處理,在處理的過(guò)程中用時(shí)比較長(zhǎng)而且卡住了,客戶端的請(qǐng)求就會(huì)被阻塞,假設(shè)在阻塞的過(guò)程中又有新的請(qǐng)求進(jìn)來(lái)(假設(shè)client2、client3也同時(shí)連接到worker)要去處理。只有阻塞的請(qǐng)求處理完畢才回去處理client2、client3,所以master會(huì)去fork一個(gè)新worker進(jìn)程。(在告并發(fā)情況下,這樣的消耗會(huì)很大而且占用的資源會(huì)比較多)。
五、Nginx時(shí)間處理
假設(shè)一個(gè)client在進(jìn)行請(qǐng)求的時(shí)候由worker1來(lái)進(jìn)行處理,在處理的過(guò)程中用時(shí)比較長(zhǎng)而且卡住了。對(duì)于Nginx而言是異步非阻塞的,如果發(fā)生阻塞同時(shí)又有新的請(qǐng)求進(jìn)來(lái)那么worker會(huì)去處理下一個(gè)請(qǐng)求。用到的模型為epoll,(如果用到epoll那么一個(gè)worker進(jìn)程可以處理6~8w的請(qǐng)求量,并且不會(huì)產(chǎn)生很多的開(kāi)銷),那么需要越高的并發(fā)量只需要增加服務(wù)器的配置就可以了(有錢(qián)解決)。
(一)Nginx的events模塊支持的多種事件模型支持的模型
Nginx 的 events
模塊主要用于配置 Nginx 如何處理連接,它提供了多種事件模型,以適應(yīng)不同的操作系統(tǒng)和應(yīng)用場(chǎng)景。下面為你詳細(xì)介紹 Nginx 支持的主要事件模型:
1. select 模型
- 原理:
select
是一種較為傳統(tǒng)的事件驅(qū)動(dòng)模型,它通過(guò)對(duì)文件描述符集合進(jìn)行輪詢,檢查是否有文件描述符處于可讀、可寫(xiě)或異常狀態(tài)。當(dāng)有事件發(fā)生時(shí),select
函數(shù)會(huì)返回發(fā)生事件的文件描述符數(shù)量,然后程序需要遍歷文件描述符集合來(lái)確定具體是哪些文件描述符發(fā)生了事件。 - 適用場(chǎng)景:適用于連接數(shù)較少的場(chǎng)景,因?yàn)?nbsp;
select
模型在處理大量連接時(shí),輪詢操作會(huì)帶來(lái)較高的 CPU 開(kāi)銷,性能會(huì)顯著下降。同時(shí),select
模型對(duì)文件描述符數(shù)量有限制,通常最大為 1024。 - 配置示例:
nginx
events { use select; worker_connections 1024; }
2. poll 模型
- 原理:
poll
是對(duì)select
模型的改進(jìn),它同樣采用輪詢的方式檢查文件描述符的狀態(tài),但poll
沒(méi)有文件描述符數(shù)量的限制。poll
使用一個(gè)結(jié)構(gòu)體數(shù)組來(lái)存儲(chǔ)文件描述符和對(duì)應(yīng)的事件,避免了select
對(duì)文件描述符數(shù)量的硬限制。 - 適用場(chǎng)景:適用于連接數(shù)相對(duì)較多,但仍然不是非常大的場(chǎng)景。相比于
select
,poll
在處理大量連接時(shí)性能有所提升,但在處理超大量連接時(shí),輪詢操作仍然會(huì)帶來(lái)較高的 CPU 開(kāi)銷。 - 配置示例:
nginx
events { use poll; worker_connections 2048; }
3. epoll 模型
- 原理:
epoll
是 Linux 內(nèi)核為處理大批量文件描述符而作了改進(jìn)的poll
,是 Linux 下多路復(fù)用 IO 接口select/poll
的增強(qiáng)版本。它采用事件驅(qū)動(dòng)的方式,只關(guān)注那些有事件發(fā)生的文件描述符,避免了對(duì)所有文件描述符的輪詢,從而提高了效率。epoll
使用內(nèi)核和用戶空間共享內(nèi)存的方式,減少了數(shù)據(jù)的拷貝次數(shù)。 - 適用場(chǎng)景:適用于 Linux 系統(tǒng)下處理大量并發(fā)連接的場(chǎng)景,是 Nginx 在 Linux 系統(tǒng)上的首選事件模型。
- 配置示例:
nginx
events { use epoll; worker_connections 65535; }
4. kqueue 模型
- 原理:
kqueue
是 FreeBSD 系統(tǒng)上的一種高效事件通知機(jī)制,類似于 Linux 下的epoll
。它采用事件隊(duì)列的方式,當(dāng)有事件發(fā)生時(shí),會(huì)將事件添加到隊(duì)列中,程序可以從隊(duì)列中獲取發(fā)生事件的文件描述符。 - 適用場(chǎng)景:適用于 FreeBSD 系統(tǒng),在處理大量并發(fā)連接時(shí)性能較好。
- 配置示例:
nginx
events { use kqueue; worker_connections 65535; }
5. rtsig 模型
- 原理:
rtsig
是基于實(shí)時(shí)信號(hào)實(shí)現(xiàn)的事件模型,它通過(guò)發(fā)送實(shí)時(shí)信號(hào)來(lái)通知程序有事件發(fā)生。 - 適用場(chǎng)景:該模型在實(shí)際應(yīng)用中使用較少,因?yàn)閷?shí)時(shí)信號(hào)的處理有一些限制,并且性能不如
epoll
和kqueue
等模型。 - 配置示例:
nginx
events { use rtsig; worker_connections 1024; }
6. /dev/poll 模型
- 原理:
/dev/poll
是 Solaris 系統(tǒng)上的一種事件通知機(jī)制,它通過(guò)讀取/dev/poll
設(shè)備文件來(lái)獲取事件信息。 - 適用場(chǎng)景:適用于 Solaris 系統(tǒng),在該系統(tǒng)上可以提供較好的性能。
- 配置示例:
nginx
events { use /dev/poll; worker_connections 65535; }
自動(dòng)選擇模型
如果不指定 use
指令,Nginx 會(huì)根據(jù)操作系統(tǒng)自動(dòng)選擇最合適的事件模型。例如,在 Linux 系統(tǒng)上會(huì)優(yōu)先選擇 epoll
模型,在 FreeBSD 系統(tǒng)上會(huì)優(yōu)先選擇 kqueue
模型。示例如下:
nginx
events { worker_connections 65535; }
在實(shí)際應(yīng)用中,建議根據(jù)服務(wù)器的操作系統(tǒng)和具體的業(yè)務(wù)場(chǎng)景選擇合適的事件模型,以提高 Nginx 的性能和穩(wěn)定性。
(二)nginx默認(rèn)的模型是epoll
epoll
是 Linux 內(nèi)核為處理大批量文件描述符而作了改進(jìn)的 poll
,是 Linux 下多路復(fù)用 IO 接口 select/poll
的增強(qiáng)版本,它能顯著提高程序在大量并發(fā)連接中只有少量活躍的情況下的系統(tǒng) CPU 利用率。下面從幾個(gè)方面詳細(xì)介紹 epoll
模型:
基本概念
在網(wǎng)絡(luò)編程中,服務(wù)器需要處理多個(gè)客戶端的連接請(qǐng)求,傳統(tǒng)的方法(如 select
和 poll
)在處理大量連接時(shí)性能會(huì)下降。epoll
則通過(guò)事件驅(qū)動(dòng)的方式,只關(guān)注那些有事件發(fā)生的文件描述符,避免了對(duì)所有文件描述符的輪詢,從而提高了效率。
工作原理
epoll
的工作流程主要分為三個(gè)步驟:
- 創(chuàng)建 epoll 實(shí)例:使用 epoll_create 或 epoll_create1 函數(shù)創(chuàng)建一個(gè) epoll 實(shí)例,它會(huì)返回一個(gè)文件描述符,后續(xù)的操作都基于這個(gè)描述符進(jìn)行。
- 注冊(cè)事件:使用 epoll_ctl 函數(shù)向 epoll 實(shí)例中添加、修改或刪除需要監(jiān)控的文件描述符以及對(duì)應(yīng)的事件。例如,可以監(jiān)控文件描述符的可讀、可寫(xiě)等事件。
- 等待事件發(fā)生:使用 epoll_wait 函數(shù)等待事件的發(fā)生。當(dāng)有事件發(fā)生時(shí),該函數(shù)會(huì)返回有事件發(fā)生的文件描述符列表,程序可以對(duì)這些文件描述符進(jìn)行相應(yīng)的處理。
代碼示例
以下是一個(gè)簡(jiǎn)單的使用 epoll
實(shí)現(xiàn)的 TCP 服務(wù)器示例代碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/epoll.h> #include <unistd.h> #define MAX_EVENTS 10 #define BUF_SIZE 1024 int main() { int listen_fd, epoll_fd; struct sockaddr_in server_addr; struct epoll_event ev, events[MAX_EVENTS]; // 創(chuàng)建監(jiān)聽(tīng)套接字 listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (listen_fd == -1) { perror("socket"); return 1; } // 初始化服務(wù)器地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(8080); // 綁定地址 if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { perror("bind"); close(listen_fd); return 1; } // 監(jiān)聽(tīng)連接 if (listen(listen_fd, SOMAXCONN) == -1) { perror("listen"); close(listen_fd); return 1; } // 創(chuàng)建 epoll 實(shí)例 epoll_fd = epoll_create1(0); if (epoll_fd == -1) { perror("epoll_create1"); close(listen_fd); return 1; } // 將監(jiān)聽(tīng)套接字添加到 epoll 實(shí)例中 ev.events = EPOLLIN; ev.data.fd = listen_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev) == -1) { perror("epoll_ctl: listen_fd"); close(listen_fd); close(epoll_fd); return 1; } while (1) { int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); continue; } for (int i = 0; i < nfds; i++) { if (events[i].data.fd == listen_fd) { // 處理新的連接 struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int conn_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_addr_len); if (conn_fd == -1) { perror("accept"); continue; } // 將新的連接添加到 epoll 實(shí)例中 ev.events = EPOLLIN; ev.data.fd = conn_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &ev) == -1) { perror("epoll_ctl: conn_fd"); close(conn_fd); } } else { // 處理客戶端數(shù)據(jù) char buf[BUF_SIZE]; ssize_t n = read(events[i].data.fd, buf, BUF_SIZE); if (n <= 0) { // 客戶端關(guān)閉連接 close(events[i].data.fd); epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL); } else { // 回顯數(shù)據(jù)給客戶端 write(events[i].data.fd, buf, n); } } } } // 關(guān)閉監(jiān)聽(tīng)套接字和 epoll 實(shí)例 close(listen_fd); close(epoll_fd); return 0; }
優(yōu)點(diǎn)
- 高效處理大量連接:
epoll
使用事件驅(qū)動(dòng)機(jī)制,只關(guān)注有事件發(fā)生的文件描述符,避免了select
和poll
對(duì)所有文件描述符的輪詢,因此在處理大量并發(fā)連接時(shí)性能更優(yōu)。 - 內(nèi)存拷貝優(yōu)化:
epoll
使用內(nèi)核和用戶空間共享內(nèi)存的方式,減少了數(shù)據(jù)的拷貝次數(shù),提高了效率。 - 水平觸發(fā)和邊緣觸發(fā)模式:
epoll
支持水平觸發(fā)(LT)和邊緣觸發(fā)(ET)兩種模式,開(kāi)發(fā)者可以根據(jù)具體需求選擇合適的模式。
缺點(diǎn)
- 平臺(tái)依賴性:
epoll
是 Linux 特有的,在其他操作系統(tǒng)(如 Windows、macOS)上無(wú)法使用。 - 實(shí)現(xiàn)復(fù)雜度較高:相比于
select
和poll
,epoll
的使用和實(shí)現(xiàn)相對(duì)復(fù)雜,需要開(kāi)發(fā)者對(duì)其原理有深入的理解。
注:worker的進(jìn)程要根據(jù)CPU實(shí)際情況來(lái)定不是越高越高,如果太高會(huì)造成請(qǐng)求訪問(wèn)卡頓。影響業(yè)務(wù)的正常運(yùn)行。
epoll的配置
events { #默認(rèn)使用epoll use epoll; #每個(gè)worker允許的客端最大連接數(shù) worker_connections 1024; }
以上就是Nginx處理Web請(qǐng)求機(jī)制的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Nginx處理Web請(qǐng)求機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Nginx配置缺少導(dǎo)致CSS不起作用的問(wèn)題及解決方法
在Web開(kāi)發(fā)中,確保樣式表正確加載是前端顯示正常工作的關(guān)鍵,然而,有時(shí)候即使CSS文件的路徑和代碼本身沒(méi)有問(wèn)題,CSS樣式也可能無(wú)法正確應(yīng)用,本文將分享一個(gè)常見(jiàn)的問(wèn)題——Nginx配置缺少導(dǎo)致的CSS不起作用,以及如何解決這個(gè)問(wèn)題,感興趣的朋友一起看看吧2024-07-07通過(guò)Nginx的proxy_set_header設(shè)置請(qǐng)求頭無(wú)效的解決
這篇文章主要介紹了通過(guò)Nginx的proxy_set_header設(shè)置請(qǐng)求頭無(wú)效的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Nginx配置文件中l(wèi)ocation配置的多種場(chǎng)景
location主要做定位功能,根據(jù)uri來(lái)進(jìn)行不同的定位,下面這篇文章主要給大家介紹了關(guān)于Nginx配置文件中l(wèi)ocation配置的多種場(chǎng)景,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09nginx反向代理https內(nèi)部定向到http報(bào)302的問(wèn)題及解決
這篇文章主要介紹了nginx反向代理https內(nèi)部定向到http報(bào)302的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Nginx將http轉(zhuǎn)換成https的詳細(xì)過(guò)程
相信大家在現(xiàn)有項(xiàng)目里都會(huì)通過(guò)https訪問(wèn),這篇文章主要給大家介紹了關(guān)于Nginx將http轉(zhuǎn)換成https的詳細(xì)過(guò)程,文中將實(shí)現(xiàn)的方法介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05Nginx基礎(chǔ)配置(main、events、http、server、location)
本文主要介紹了Nginx基礎(chǔ)配置(main、events、http、server、location),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06