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