1. 程式人生 > 其它 >高效能伺服器nginx、nginx常見配置詳解,高階功能的使用

高效能伺服器nginx、nginx常見配置詳解,高階功能的使用

1.對常用I/O模型進行比較說明

一、網路 I/O 模型

阻塞型、非阻塞型、複用型、訊號驅動型、非同步

1.阻塞型 I/O 模型(blocking IO

阻塞IO模型是最簡單的I/O模型,使用者執行緒在核心進行IO操作時被阻塞使用者執行緒通過系統呼叫read發起I/O讀操作,由使用者空間轉到核心空間。核心等到資料包到達後,然後將接收的資料拷貝到使用者空間,完成read操作使用者需要等待read將資料讀取到buffer後,才繼續處理接收的資料。整個I/O請求的過程中,使用者執行緒是被阻塞的,這導致使用者在發起IO請求時,不能做任何事情,對CPU的資源利用率不夠

優點:程式簡單,在阻塞等待資料期間程序/執行緒掛起,基本不會佔用 CPU 資源

缺點:每個連線需要獨立的程序/執行緒單獨處理,當併發請求量大時為了維護程式,記憶體、執行緒切換開銷較大,apache 的preforck使用的是這種模式。

同步阻塞:程式向核心傳送I/O請求後一直等待核心響應,如果核心處理請求的IO操作不能立即返回,則程序將一直等待並不再接受新的請求,並由程序輪訓檢視I/O是否完成,完成後程序將I/O結果返回給Client,在IO沒有返回期間程序不能接受其他客戶的請求,而且是有程序自己去檢視I/O是否完成,這種方式簡單,但是比較慢,用的比較少。

2.非阻塞型 I/O 模型 (nonblocking IO)

使用者執行緒發起IO請求時立即返回。但並未讀取到任何資料,使用者執行緒需要不斷地發起IO請求,直到資料到達後,才真正讀取到資料,繼續執行。即 “輪詢”機制存在兩個問題:如果有大量檔案描述符都要等,那麼就得一個一個的read。這會帶來大量的Context Switch(read是系統呼叫,每呼叫一次就得在使用者態和核心態切換一次)。輪詢的時間不好把握。這裡是要猜多久之後資料才能到。等待時間設的太長,程式響應延遲就過大;設的太短,就會造成過於頻繁的重試,乾耗CPU而已,是比較浪費CPU的方式,一般很少直接使用這種模型,而是在其他IO模型中使用非阻塞IO這一特性。

非阻塞:程式向核心傳送請I/O求後一直等待核心響應,如果核心處理請求的IO操作不能立即返回IO結果,程序將不再等待,而且繼續處理其他請求,但是仍然需要程序隔一段時間就要檢視核心I/O是否完成。

3.多路複用 I/O 型(I/O multiplexing)

I/O multiplexing 主要包括:select,poll,epoll三種系統呼叫,select/poll/epoll的好處就在於單個process就可以同時處理多個網路連線的IO。

它的基本原理就是select/poll/epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有資料到達了,就通知使用者程序。

當用戶程序呼叫了select,那麼整個程序會被block,而同時,kernel會“監視”所有select負責的socket,當任何一個socket中的資料準備好了,select就會返回。這個時候使用者程序再呼叫read操作,將資料從kernel拷貝到使用者程序。

Apache prefork是此模式的select,work是poll模式。

優點:可以基於一個阻塞物件,同時在多個描述符上等待就緒,而不是使用多個執行緒(每個檔案描述符一個執行緒),這樣可以大大節省系統資源

缺點:當連線數較少時效率相比多執行緒+阻塞 I/O 模型效率較低,可能延遲更大,因為單個連線處理需要 2 次系統呼叫,佔用時間會有增加

4.訊號驅動式 I/O 模型 (signal-driven IO)

訊號驅動I/O的意思就是程序現在不用傻等著,也不用去輪詢。而是讓核心在資料就緒時,傳送訊號通知程序。

呼叫的步驟是,通過系統呼叫 sigaction ,並註冊一個訊號處理的回撥函式,該呼叫會立即返回,然後主程式可以繼續向下執行,當有I/O操作準備就緒,即核心資料就緒時,核心會為該程序產生一個 SIGIO訊號,並回調註冊的訊號回撥函式,這樣就可以在訊號回撥函式中系統呼叫 recvfrom 獲取資料,將使用者程序所需要的資料從核心空間拷貝到使用者空間

此模型的優勢在於等待資料報到達期間程序不被阻塞。使用者主程式可以繼續執行,只要等待來自訊號處理函式的通知。
在訊號驅動式 I/O 模型中,應用程式使用套介面進行訊號驅動 I/O,並安裝一個訊號處理函式,程序繼續執行並不阻塞

當資料準備好時,程序會收到一個 SIGIO 訊號,可以在訊號處理函式中呼叫 I/O 操作函式處理資料。

優點:執行緒並沒有在等待資料時被阻塞,核心直接返回呼叫接收訊號,不影響程序繼續處理其他請求因此可以提高資源的利用率

缺點:訊號 I/O 在大量 IO 操作時可能會因為訊號佇列溢位導致沒法通知
非同步阻塞:程式程序向核心傳送IO呼叫後,不用等待核心響應,可以繼續接受其他請求,核心收到程序請求後進行的IO如果不能立即返回,就由核心等待結果,直到IO完成後核心再通知程序。

5.非同步 I/O 模型 (asynchronous IO)

非同步I/O 與 訊號驅動I/O最大區別在於,訊號驅動是核心通知使用者程序何時開始一個I/O操作,而非同步I/O是由核心通知使用者程序I/O操作何時完成,兩者有本質區別,相當於不用去飯店場吃飯,直接點個外賣,把等待上菜的時間也給省了

相對於同步I/O,非同步I/O不是順序執行。使用者程序進行aio_read系統呼叫之後,無論核心資料是否準備好,都會直接返回給使用者程序,然後使用者態程序可以去做別的事情。等到socket資料準備好了,核心直接複製資料給程序,然後從核心向程序傳送通知。IO兩個階段,程序都是非阻塞的。

訊號驅動IO當核心通知觸發訊號處理程式時,訊號處理程式還需要阻塞在從核心空間緩衝區拷貝資料到使用者空間緩衝區這個階段,而非同步IO直接是在第二個階段完成後,核心直接通知使用者執行緒可以進行後續操作了

優點:非同步 I/O 能夠充分利用 DMA 特性,讓 I/O 操作與計算重疊

缺點:要實現真正的非同步 I/O,作業系統需要做大量的工作。目前 Windows 下通過 IOCP 實現了真正的非同步 I/O,在 Linux 系統下,Linux 2.6才引入,目前 AIO 並不完善,因此在 Linux 下實現高併發網路程式設計時以 IO 複用模型模式+多執行緒任務的架構基本可以滿足需求

常用I/O模型比較

Select:

POSIX所規定,目前幾乎在所有的平臺上支援,其良好跨平臺支援也是它的一個

優點:本質上是通過設定或者檢查存放fd標誌位的資料結構來進行下一步處理

缺點:單個程序能夠監視的檔案描述符的數量存在最大限制,在Linux上一般為1024,可以通過修改巨集定義FD_SETSIZE,再重新編譯核心實現,但是這樣也會造成效率的降低,單個程序可監視的fd數量被限制,預設是1024,修改此值需要重新編譯核心,對socket是線性掃描,即採用輪詢的方法,效率較低

select 採取了記憶體拷貝方法來實現核心將 FD 訊息通知給使用者空間,這樣一個用來存放大量fd的資料結構,這樣會使得使用者空間和核心空間在傳遞該結構時複製開銷大

poll:

本質上和select沒有區別,它將使用者傳入的陣列拷貝到核心空間,然後查詢每個fd對應的裝置狀態其沒有最大連線數的限制,原因是它是基於連結串列來儲存的大量的fd的陣列被整體複製於使用者態和核心地址空間之間,而不管這樣的複製是不是有意義

poll特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd ,select是邊緣觸發即只通知一次

epoll:

在Linux 2.6核心中提出的select和poll的增強版本,支援水平觸發LT和邊緣觸發ET,最大的特點在於邊緣觸發,它只告訴程序哪些fd剛剛變為就需態,並且只會通知一次,使用“事件”的就緒通知方式,通過epoll_ctl註冊fd,一旦該fd就緒,核心就會採用類似callback的回撥機制來啟用該fd,epoll_wait便可以收到通知

優點:沒有最大併發連線的限制:能開啟的FD的上限遠大於1024(1G的記憶體能監聽約10萬個埠),具體檢視/proc/sys/fs/file-max,此值和系統記憶體大小相關

效率提升:非輪詢的方式,不會隨著FD數目的增加而效率下降;只有活躍可用的FD才會呼叫callback函式,即epoll最大的優點就在於它只管理“活躍”的連線,而跟連線總數無關記憶體拷貝,利用mmap(Memory Mapping)加速與核心空間的訊息傳遞;即epoll使用mmap減少複製開銷,檔案對映記憶體直接通過地址空間訪問,效率更高,把檔案對映到記憶體中

總結:

1、epoll只是一組API,比起select這種掃描全部的檔案描述符,epoll只讀取就緒的檔案描述符,再加入
基於事件的就緒通知機制,所以效能比較好

2、基於epoll的事件多路複用減少了程序間切換的次數,使得作業系統少做了相對於使用者任務來說的無用功。

3、epoll比select等多路複用方式來說,減少了遍歷迴圈及記憶體拷貝的工作量,因為活躍連線只佔總併發連
接的很小一部分。

2.nginx中的模組分類及常見核心模組有哪些

nginx 有多種模組

1.核心模組:是 Nginx 伺服器正常執行必不可少的模組,提供錯誤日誌記錄 、配置檔案解析 、事件驅動機制 、程序管理等核心功能

2.標準HTTP模組:提供 HTTP 協議解析相關的功能,比如: 埠配置 、 網頁編碼設定 、 HTTP響應頭設定 等等

3.可選HTTP模組:主要用於擴充套件標準的 HTTP 功能,讓 Nginx 能處理一些特殊的服務,比如: Flash 多媒體傳輸 、解析 GeoIP 請求、 網路傳輸壓縮 、 安全協議 SSL 支援等

4.郵件服務模組:主要用於支援 Nginx 的 郵件服務 ,包括對 POP3 協議、 IMAP 協議和 SMTP協議的支援

5.Stream服務模組: 實現反向代理功能,包括TCP協議代理

6.第三方模組:是為了擴充套件 Nginx 伺服器應用,完成開發者自定義功能,比如: Json 支援、 Lua 支援等

模組分類:

核心模組:
core,module,ngx_core,ngx_errlog,ngx_conf,ngx_events,ngx_event,ngx_epoll,ngx_regex

標準模組:
HTTP 模組: ngx_http_*
HTTP Core modules #預設功能
HTTP Optional modules #需編譯時指定

Mail 模組: ngx_mail_*

Stream 模組 ngx_stream_*

第三方模組
Rds-json-nginx,Lua-nginx,Others

3.描述nginx中worker_processes、worker_cpu_affinity、worker_rlimit_nofile、worker_connections配置項的含義

1.worker_processes [number | auto];

啟動Nginx工作程序的數量,一般設為和CPU核心數相同

2.worker_cpu_affinity

0001 0010 0100 1000;第0號---第3號CPU #將Nginx工作程序繫結到指定的CPU核心,預設Nginx是不進行程序繫結的,繫結並不是意味著當前nginx程序獨佔以一核心CPU,但是可以保證此程序不會執行在其他核心上,這就極大減少了nginx的工作程序在不同的cpu核心上的來回跳轉,減少了CPU對程序的資源分配與回收以及記憶體管理等,因此可以有效的提升nginx伺服器的效能。

3.worker_rlimit_nofile 65536;

所有worker程序能開啟的檔案數量上限,包括:Nginx的所有連線(例如與代理伺服器的連線等),而不僅僅是與客戶端的連線,另一個考慮因素是實際的併發連線數不能超過系統級別的最大開啟檔案數的限制.最好與ulimit -n 或者limits.conf的值保持一致

4.worker_connections 65536;

設定單個工作程序的最大併發連線數

4.編譯安裝nginx,實現多域名 https"

編譯安裝nginx

[root@centos8 ~]#yum -y install gcc pcre-devel openssl-devel zlib-devel

[root@centos8 ~]#useradd -s /sbin/nologin nginx

[root@centos8 ~]#cd /usr/local/src/

[root@centos8 src]#wget http://nginx.org/download/nginx-1.18.0.tar.gz

[root@centos8 src]#tar xf nginx-1.18.0.tar.gz

[root@centos8 src]#cd nginx-1.18.0/

[root@centos8 nginx-1.18.0]#./configure --prefix=/apps/nginx
--user=nginx
--group=nginx
--with-http_ssl_module
--with-http_v2_module
--with-http_realip_module
--with-http_stub_status_module
--with-http_gzip_static_module
--with-pcre
--with-stream
--with-stream_ssl_module
--with-stream_realip_module

[root@centos8 nginx-1.18.0]#make && make install

[root@centos8 nginx-1.18.0]#chown -R nginx.nginx /apps/nginx

[root@centos8 nginx-1.18.0]#ll /apps/nginx/

[root@centos8 nginx-1.18.0]#ln -s /apps/nginx/sbin/nginx /usr/sbin/

[root@centos8 nginx-1.18.0]#vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/apps/nginx/run/nginx.pid
ExecStart=/apps/nginx/sbin/nginx -c /apps/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
[Install]
WantedBy=multi-user.target

[root@centos8 nginx-1.18.0]#mkdir /apps/nginx/run/

[root@centos8 nginx-1.18.0]#vim /apps/nginx/conf/nginx.conf
pid   /apps/nginx/run/nginx.pid;

[root@centos8 nginx-1.18.0]#systemctl daemon-reload

[root@centos8 nginx-1.18.0]#systemctl enable --now nginx

[root@centos8 nginx-1.18.0]#systemctl status nginx

實現多域名 https

Nginx 支援基於單個IP實現多域名的功能,並且還支援單IP多域名的基礎之上實現HTTPS,其實是基於Nginx的 SNI(Server Name Indication)功能實現,SNI是為了解決一個Nginx伺服器內使用一個IP繫結多個域名和證書的功能,其具體功能是客戶端在連線到伺服器建立SSL連結之前先發送要訪問站點的域名(Hostname),這樣伺服器再根據這個域名返回給客戶端一個合適的證書。

自簽名CA證書

[root@centos8 ~]#mkidr /apps/nginx/certs/

[root@centos8 ~]#cd /apps/nginx/certs/

[root@centos8 certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt

自制key和csr檔案

[root@centos8 certs]#openssl req -newkey rsa:4096 -nodes -sha256 -keyout www.abc.com.key -out www.abc.com.csr
Generating a RSA private key
..........++++
...................................................................................++++
writing new private key to 'www.abc.com.key'
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Hubei
Locality Name (eg, city) [Default City]:Hubei
Organization Name (eg, company) [Default Company Ltd]:abc.com
Organizational Unit Name (eg, section) []:abc
Common Name (eg, your name or your server's hostname) []:www.abc.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

簽發證書

[root@centos8 certs]#openssl x509 -req -days 3650 -in www.abc.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out www.abc.com.crt
Signature ok
subject=C = CN, ST = Hubei, L = Hubei, O = abc.com, OU = abc, CN = www.abc.com
Getting CA Private Key

驗證證書內容

[root@centos8 certs]#openssl x509 -in www.abc.com.crt -noout -text

合併CA和伺服器證書成一個檔案,注意伺服器證書在前

[root@centos8 certs]##cat www.abc.com.crt ca.crt > www.abc.com.pem

Nginx 配置

[root@centos8 certs]#vim /apps/nginx/conf/nginx.conf
最後一個}後面加上
include /apps/nginx/conf/conf.d/*.conf;

[root@centos8 certs]#mkdir /apps/nginx/conf/conf.d

[root@centos8 certs]#vim /apps/nginx/conf/conf.d/mobile.conf
server {
listen 80 default_server;
server_name www.abc.com;
rewrite ^(.*)$ https://$server_name$1 permanent;
}
server {
listen 443 ssl;
server_name www.abc.com;
ssl_certificate /apps/nginx/certs/www.abc.com.pem;
ssl_certificate_key /apps/nginx/certs/www.abc.com.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
location / {
root "/data/nginx/html/mobile";
}
location /mobile_status {
stub_status;
}
}

[root@centos8 certs]#nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful

建立網站的測試資料

[root@centos8 certs]#mkdir -pv /data/nginx/html/mobile
mkdir: created directory '/data'
mkdir: created directory '/data/nginx'
mkdir: created directory '/data/nginx/html'
mkdir: created directory '/data/nginx/html/mobile'

[root@centos8 certs]#vim /data/nginx/html/mobile/index.html

重新載入nginx

[root@centos8 certs]#nginx -s reload

windows系統訪問需要該hosts檔案,訪問https需要匯入ca.crt證書。
linux匯入證書方法:

[root@centos8 certs]#cat ca.crt >> /etc/pki/tls/certs/ca-bundle.crt

[root@centos8 certs]#curl https://www.abc.com