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