1. 程式人生 > >nginx 工作原理和配置文件講解

nginx 工作原理和配置文件講解

打開 cli ssi http 狀態碼 stat pro clu libs red

1、nginx 介紹

Nginx (engine x) 是一個高性能的HTTP反向代理服務,也是一個IMAP/POP3/SMTP服務。Nginx是由伊戈爾·賽索耶夫為俄羅斯訪問量第二的Rambler.ru站點(俄文:Рамблер)開發的,第一個公開版本0.1.0發布於2004年10月4日。其將源代碼以類BSD許可證的形式發布,因它的穩定性、豐富的功能集、示例配置文件和低系統

資源的消耗而聞名。2011年6月1日,nginx 1.0.4發布。

Nginx是一款輕量級Web 服務器/反向代理服務器及電子郵件(IMAP/POP3)代理服務器,並在一個BSD-like 協議下發行。其特點是占有內存少,並發能力強,

事實上nginx的並發能力確實在同類型的網頁服務器中表現較好

2、nginx 的特點

Nginx 做為 HTTP 服務器,有以下幾項基本特性:

? 處理靜態文件,索引文件以及自動索引;打開文件描述符緩沖.

? 無緩存的反向代理加速,簡單的負載均衡和容錯.

? FastCGI,簡單的負載均衡和容錯.

? 模塊化的結構。包括 gzipping, byte ranges, chunked responses,以及 SSI-filter 等 filter。如果由 FastCGI 或其它代理服務器處理單頁中存在的多個 SSI,

則這項處理可以並行運行,而不需要相互等待。

? 支持 SSL 和 TLSSNI.

3、nginx 工作原理

3.1 nginx架構:

nginx在啟動後,在unix系統中會以daemon的方式在後臺運行,後臺進程包含一個master進程和多個worker進程。
我們也可以手動地關掉後臺模式,讓nginx在前臺運行,並且通過配置讓nginx取消master進程,從而可以使nginx以單進程方式運行。
生產環境下我們肯定不會這麽做,所以關閉後臺模式,一般是用來調試,nginx是以多進程的方式來工作的,當然nginx也是支持多線程的方式的,
只是我們主流的方式還是多進程的方式,也是nginx的默認方式。nginx采用多進程的方式有諸多好處,nginx的進程模型可以由下圖來表示:

技術分享圖片


master與worker

nginx在啟動後,會有一個master進程和多個worker進程。master進程主要用來管理worker進程,
包含:接收來自外界的信號,向各worker進程發送信號,監控worker進程的運行狀態,當worker進程退出後(異常情況下),會自動重新啟動新的worker進程。
而基本的網絡事件,則是放在worker進程中來處理了。多個worker進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的。
一個請求,只可能在一個worker進程中處理,一個worker進程,不可能處理其它進程的請求。worker進程的個數是可以設置的,一般我們會設置與機器cpu核數一致。

master與處理請求

那麽我們該怎麽操作ngnix呢?其實我們只需要通過與master進行通信(命令)就可以操作ngnix,master進程會接收來自外界發來的信號,再根據信號做不同的事情。
比如kill -HUP pid,我們一般用這個信號來重啟nginx,或重新加載配置,因為是從容地重啟,因此服務是不中斷的。首先master進程在接到信號後,會先重新加載配置文件,然後再啟動新的worker進程,並向所有老的worker進程發送信號,告訴他們可以退出了。新的worker在啟動後,就開始接收新的請求,而老的worker在收到來自master的信號後,就不再接收新的請求,並且在當前進程中的所有未處理完的請求處理完成後,再退出。
當然,直接給master進程發送信號,這是比較老的操作方式,nginx在0.8版本之後,引入了一系列命令行參數,來方便我們管理。
比如,./nginx -s reload,就是來重啟nginx,./nginx -s stop,就是來停止nginx的運行。如何做到的呢?我們還是拿reload來說,我們看到,執行命令時,我們是啟動一個新的nginx進程,而新的nginx進程在解析到reload參數後,就知道我們的目的是控制nginx來重新加載配置文件了,它會向master進程發送信號,然後接下來的動作,就和我們直接向master進程發送信號一樣了。

worker與處理請求

前面有提到,worker進程之間是平等的,每個進程,處理請求的機會也是一樣的。當我們提供80端口的http服務時,一個連接請求過來,每個進程都有可能處理這個連接。怎麽做到的呢?
首先,每個worker進程都是從master進程fork過來,在master進程裏面,先建立好需要listen的socket(listenfd)之後,然後再fork出多個worker進程。所有worker進程的listenfd會在新連接到來時變得可讀。為保證只有一個進程處理該連接,所有worker進程在註冊listenfd讀事件前搶accept_mutex,搶到互斥鎖的那個進程註冊listenfd讀事件,在讀事件裏調用accept接受該連接。
當一個worker進程在accept這個連接之後,就開始讀取請求,解析請求,處理請求,產生數據後,再返回給客戶端,最後才斷開連接,這樣一個完整的請求就是這樣的了

nginx進程模型的好處

首先,對於每個worker進程來說,獨立的進程,不需要加鎖,所以省掉了鎖帶來的開銷,同時在編程以及問題查找時,也會方便很多。
其次,采用獨立的進程,可以讓worker互相之間不會影響,一個worker退出後,其它worker還在工作,服務不會中斷,master進程則很快啟動新的worker進程。
當然,worker進程的異常退出,肯定是程序有bug了,異常退出,會導致當前worker上的所有請求失敗,不過不會影響到所有請求,所以降低了風險。
好處是很多的,只能在使用中慢慢體會了。

nginx處理高並發(網絡事件)

nginx如何處理高並發呢?按理說nginx采用多worker的方式來處理請求,每個worker裏面只有一個主線程,那能夠處理的並發數很有限啊,多少個worker就能處理多少個並發,何來高並發呢?
其實這就是nginx的高明之處,nginx采用了異步非阻塞的方式來處理請求,也就是說,nginx是可以同時處理成千上萬個請求的。
為什麽nginx可以采用異步非阻塞的方式來處理呢,或者異步非阻塞到底是怎麽回事呢?一個完整過程:請求過來,要建立連接,然後再接收數據,接收數據後,再發送數據,具體到系統底層,就是讀寫事件,而當讀寫事件沒有準備好時,必然不可操作,如果不用非阻塞的方式來調用,那就得阻塞調用了,事件沒有準備好,那就只能等了,等事件準備好了,你再繼續吧。阻塞調用會進入內核等待,cpu就會讓出去給別人用了,對單線程的worker來說,顯然不合適,當網絡事件越多時,大家都在等待呢,cpu空閑下來沒人用,cpu利用率自然上不去了,更別談高並發了。

4、配置文件介紹
[root@kg02 nginx]# grep -Ev "^$|#" nginx.conf.default 
worker_processes  1;  #work 進程的數量
events {              #事件區塊開始
    worker_connections  1024; #每個worker 進程支持的最大連接數
}
http {                        #http 區塊開始
    include       mime.types;  #nginx 支持的媒體類型庫文件
    default_type  application/octet-stream;  #默認的媒體類型
    sendfile        on; #開啟高速傳輸模式
    keepalive_timeout  65; #連接超時
    server {               #第一個server 區
        listen       80;    #提供服務的端口,默認是80 端口
        server_name  localhost; #提供服務的域名主機名
        location / {
            root   html;   #站點的根目錄
            index  index.html index.htm; #默認的首頁文件,多個用空格分開
        }
        error_page   500 502 503 504  /50x.html; #出現對應的http 狀態碼,使用50x.html 回應客戶
        location = /50x.html {  #訪問50x.html 
            root   html; #指定對應的站點目錄為html
        }
    }
}

5、配置虛擬主機
5.1 基於多域名配置虛擬主機
[root@nginx01 html]# cat /etc/nginx/nginx.conf
user root; 
error_log /var/log/nginx/error.log;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  aaa.gd.com;
        location / {
            root   /root/aaa;
            index  index.html index.htm;
       }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen       80;
        server_name  bbb.gd.com;
        location / {
            root   /root/bbb;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}
[root@nginx01 html]# /etc/init.d/nginx restart
[root@nginx01 html]# cat /root/aaa/index.html 
aaa
[root@nginx01 html]# cat /root/bbb/index.html 
Bbb

#訪問
[root@nginx02 ~]# curl aaa.gd.com
aaa
[root@nginx02 ~]# curl bbb.gd.com
bbb

5.2 基於多端口配置虛擬主機
[root@nginx01 html]# cat /etc/nginx/nginx.conf
user root;
error_log /var/log/nginx/error.log;
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  aaa.gd.com;
        location / {
            root   /root/aaa;
            index  index.html index.htm;
       }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    server {
        listen       81;
        server_name  bbb.gd.com;
        location / {
            root   /root/bbb;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

}
[root@nginx02 ~]# curl aaa.gd.com
aaa
[root@nginx02 ~]# curl bbb.gd.com:81
Bbb

6.nginx 狀態信息功能實戰
[root@nginx01 html]# cat /etc/nginx/nginx.conf
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  aaa.gd.com;
        location / {
            root   /root/aaa;
            stub_status on; #開啟狀態信息
            index  index.html index.htm;
       }
[root@nginx02 ~]# curl aaa.gd.com
Active connections: 1 
server accepts handled requests
 6 6 6 
Reading: 0 Writing: 1 Waiting: 0
# Active connections: 1 (正處理的活動連接數有1個)
Server 表示nginx 啟動到現在共處理了6個連接
Accepts 成功創建了多少次握手
Handled requests 表示總共處理了多少次請求
#這些信息不能給用戶看到,可以通過其他測試工具獲取

7、配置錯誤日誌
[root@nginx01 html]# cat /etc/nginx/nginx.conf
user root;
error_log /var/log/nginx/error.log;
[root@nginx01 ~]# head -n5 /var/log/nginx/error.log 
2018/08/26 23:43:45 [error] 2540#0: *1 "/root/aaa/index.html" is forbidden (13: Permission denied), 
client: 192.168.1.232, server: aaa.gd.com, request: "GET / HTTP/1.1", host: "aaa.gd.com" # 日誌級別warn/error/crit 默認使用error 8、access.log訪問日誌分析 [root@nginx01 ~]# cat /var/log/nginx/access.log |head -n2 192.168.1.232 - - [26/Aug/2018:23:43:45 +0800] "GET / HTTP/1.1" 403 169 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu)
libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
" #192.168.1.232 客戶端的ip 403 表示狀態碼 169 響應的大小 #可以在日誌中加入buffer和flush 參數,提高訪問性能 9、訪問日誌輪詢切割 [root@nginx01 ~]# cat log.sh #!/bin/bash DATE=`date +%F` BASEDIR="/var/log/nginx/" LOGNAME="access" cd $BASEDIR /bin/mv ${LOGNAME}.log ${LOGNAME}_${DATE}.log /etc/init.d/nginx -s reload [root@nginx01 ~]# crontab -l 0 0 * * * /bin/sh /root/log.sh >/dev/null 2>&1

nginx 工作原理和配置文件講解