Nginx詳情以及配置
1 Nginx現狀
nginx 是當前的使用最廣泛的webserver ,支援http正向/反向代理,支援TCP/UDP層代理
,來看下netcraft的資料
nginx在全部網站中佔比達到18%
,在top millon busest 達到28%
,而且一直在增加。當下最時尚的webserver非nginx莫屬
2 Nginx特點
效能好
非阻塞IO/高併發,支援檔案IO
多worker,thread pool
基於rbtree的定時器
系統特性的持續支援
功能強大
webserver/cache/keepalive/pipeline等等
各種upstream的支援【fastcgi/http/…】
輸出靈活【chunk/zip/…】
在不斷的發展 http2,tcp,udp,proxy…
運維的友好【這個對於開發和部署很重要】
配置非常規範【個人認為:約定及規範是最好的實踐】
熱載入和熱更新【後文會詳細介紹,能在二進位制的層面熱更新】
日誌強大【真的很強的,很多變數支撐】
擴充套件強大
下圖是nginx、apache和lighttpd的一個對比。系統壓力,記憶體佔用,upstream支援等多個方面都非常不錯
HTTPS = HTTP + SSL
3 Nginx工作原理
Nginx的執行方式:master-worker多程序模式執行,單執行緒/非阻塞執行
Nginx 啟動後生成master,master會啟動conf數量的worker程序
,當用戶的請求過來之後,由不同的worker調起執行執行緒
,非阻塞的執行請求。這種執行方式相對於apache的程序執行
相對輕量很多,支撐的併發性也會高很多。
Nginx 預設採用守護模式啟動,守護模式讓master程序啟動後在後臺執行。在Nginx執行期間主要由一個master主程序和多個worker程序(worker數目一般與cpu數目相同)
(1)master主程序
master主程序主要是管理worker程序,對網路事件進行收集和分發:
接收來自外界的訊號
向各worker程序傳送訊號
監控worker程序的執行狀態,當worker程序退出後(異常情況下),會自動重新啟動新的worker程序
(2)worker 工作程序
nginx用一個獨立的worker程序來處理一個請求,一個worker程序可以處理多個請求:
a. 當一個worker程序在accept這個連線之後,就開始讀取請求,解析請求,處理請求,產生資料後,再返回給客戶端,最後才斷開連線。
b. 一個請求,完全由worker程序來處理,而且只在一個worker程序中處理。採用這種方式的好處:
-
節省鎖帶來的開銷。對於每個worker程序來說,獨立的程序,不需要加鎖,所以省掉了鎖帶來的開銷,同時在程式設計以及問題查上時,也會方便很多
獨立程序,減少風險。
採用獨立的程序,可以讓互相之間不會影響,一個程序退出後,其它程序還在工作,服務不會中斷,master程序則很快重新啟動新的worker程序。
在一次請求裡無需程序切換
(3) Nginx的IO處理過程
一般的Tcp Socket處理過程:
服務端:fd = socket.socket —> fd.bind() —> fd.listen() —> accept() 等待客戶端連線 —> send / recv —> close()
客戶端:fd = socket.socket —> fd.connect() 與服務端建立連線 —> recv / send —> close()
Nginx的網路IO處理通常使用epoll,epoll函式使用了I/O複用模型。與I/O阻塞模型比較,I/O複用模型的優勢在於可以同時等待多個(而不只是一個)套接字描述符就緒。Nginx的epoll工作流程如下:
-
master程序先建好需要listen的socket後,然後再fork出多個woker程序,這樣每個work程序都可以去accept這個socket
當一個client連線到來時,所有accept的work程序都會受到通知,但只有一個程序可以accept成功,其它的則會accept失敗,Nginx提供了一把共享鎖accept_mutex來保證同一時刻只有一個work程序在accept連線,從而解決驚群問題。
當一個worker程序accept這個連線後,就開始讀取請求,解析請求,處理請求,產生資料後,再返回給客戶端,最後才斷開連線,這樣一個完成的請求就結束了.
4 Nginx 安裝與配置
Nginx服務學習我們藉助於一個第三方庫Openresty,它本身就是把nginx核心程式碼做了一層封裝,你完全可以把它當成Nginx使用。
OpenResty 是一個基於 Nginx 與 Lua 的高效能 Web 平臺,其內部集成了大量精良的 Lua 庫、第三方模組以及大多數的依賴項。用於方便地搭建能夠處理超高併發、擴充套件性極高的動態 Web 應用、Web 服務和動態閘道器。
OpenResty 的目標是讓你的Web服務直接跑在 Nginx 服務內部,充分利用 Nginx 的非阻塞 I/O 模型,不僅僅對 HTTP 客戶端請求,甚至於對遠端後端諸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都進行一致的高效能響應。
Openresty下載頁:
https://openresty.org/cn/download.html
下載最新版本:wget https://openresty.org/download/openresty-1.11.2.5.tar.gz
效能測試工具 Apache AB test
安裝過程:
(1)安裝依賴庫:
sudo apt install libpcre3 libpcre3-dev
sudo apt install openssl libssl-dev
(2)安裝openresty
#將openresty安裝到/opt/openresty目錄下 sudo mkdir /opt/openresty #修改組和使用者許可權 sudo chown -Rf zhouguangyou /opt/openresty/ sudo chgrp -Rf zhouguangyou /opt/openresty/ tar -xzvf openresty-1.11.2.5.tar.gz cd openresty-1.11.2.5 ./configure --prefix=/opt/openresty (注:./configure --help 檢視更多的配置選項) make make install
至此,安裝完成,安裝openresty就在/opt/openresty目錄下。
(3)目錄介紹
bin openresty 的啟動檔案
COPYRIGHT 版權檔案
luajit lua虛擬環境luajit
lualib lua實現的第三方庫,包括redis, mysql, upload, upstream,websocket等等。
nginx nginx核心功能塊
pod resty.index site
openresty不只是提供了nginx功能,而且提供了豐富的工具集,我們可以做除了負載均衡和反向代理之外的很多事情,快速搭建出高效能web服務。
修改 vim /opt/openresty/nginx/conf/nginx.conf 中,將listen 80改成 8080
啟動nginx服務:
$ /opt/openresty/nginx/sbin/nginx
開啟頁面:http://172.16.245.180:8080/
可以看到 Welcome to OpenResty ! 的頁面,表示已經安裝成功!
5 OpenResty 使用
5.1 配置檔案
Openresty 框架的配置和nginx配置方法一樣,配置檔案: /opt/openresty/nginx/conf/nginx.conf
Nginx主要通過nginx.conf檔案進行配置使用。在nginx.conf檔案中主要分為:
-
全域性塊:一些全域性的屬性,在執行時與具體業務功能(比如http服務或者email服務代理)無關的一些引數,比如工作程序數,執行的身份等
event塊:參考事件模型,單個程序最大連線數等
http塊:設定http伺服器
server塊:配置虛擬主機
location塊:配置請求路由及頁面的處理情況等
關鍵引數說明:
#nginx程序數,建議設定為等於CPU總核心數。 worker_processes 8; #全域性錯誤日誌定義型別,[ debug | info | notice | warn | error | crit ] error_log /usr/local/nginx/logs/error.log info; #程序pid檔案 pid /opt/openresty/nginx/logs/nginx.pid; #指定程序可以開啟的最大描述符:數目 #工作模式與連線數上限 #這個指令是指當一個nginx程序開啟的最多檔案描述符數目,理論值應該是最多開啟檔案數(ulimit -n)與nginx程序數相除,但是nginx分配請求並不是那麼均勻,所以最好與ulimit -n 的值保持一致。 worker_rlimit_nofile 65535; #虛擬主機的配置 server { #監聽埠 listen 80; #域名可以有多個,用空格隔開 server_name www.jd.com jd.com; index index.html index.htm index.php; root /data/www/jd; #url 請求路由 location /hello { default_type text/html; content_by_lua ' ngx.say("<p>Hello, World!</p>") '; } } #負載均衡配置 upstream piao.jd.com { #upstream的負載均衡,weight是權重,可以根據機器配置定義權重。weight引數表示權值,權值越高被分配到的機率越大。 server 192.168.80.121:80 weight=3; server 192.168.80.122:80 weight=2; server 192.168.80.123:80 weight=3; }
5.2 啟動測試
拷貝我們的工程檔案 artproject.zip,解壓到某一個目錄 eg: /home/zhouguangyou根目錄下
配置nginx配置檔案nginx.conf,新增如下資訊:
location /hello { default_type text/html; content_by_lua ' ngx.say("<p>Hello, World!</p>")'; } # 靜態檔案,nginx自己處理 location ~ ^/(images|javascript|js|css|flash|media|static)/ { root /home/zhouguangyou/artproject/art; # 過期1天,靜態檔案不怎麼更新,過期可以設大一點,如果頻繁更新,則可以設定得小一點。 expires 1d; }
$ /opt/openresty/nginx/sbin/nginx -s reload$ /opt/openresty/nginx/sbin/nginx -tnginx: the configuration file /opt/openresty/nginx/conf/nginx.conf syntax is oknginx: configuration file /opt/openresty/nginx/conf/nginx.conf test is successful
檢視頁面效果
http://172.16.245.180:8080/hello
http://172.16.245.180:8080/static/admin/pages/index.html
5.3 負載均衡策略
負載均衡也是Nginx常用的一個功能,負載均衡其意思就是分攤到多個操作單元上進行執行,例如Web伺服器、FTP伺服器、企業關鍵應用伺服器和其它關鍵任務伺服器等,從而共同完成工作任務。
Nginx目前支援自帶3種負載均衡策略,還有2種常用的第三方策略
RR (輪詢策略)
按照輪詢(預設)方式進行負載,每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器down掉,能自動剔除。雖然這種方式簡便、成本低廉。但缺點是:可靠性低和負載分配不均衡。
權重 指定輪詢機率,weight和訪問比率成正比,用於後端伺服器效能不均的情況。
upstream test{ server localhost:8080 weight=9; server localhost:8081 weight=1; }
此時8080和8081分別佔90%和10%。
ip_hash 上面的2種方式都有一個問題,那就是下一個請求來的時候請求可能分發到另外一個伺服器,當我們的程式不是無狀態的時候(採用了session儲存資料),這時候就有一個很大的很問題了,比如把登入資訊儲存到了session中,那麼跳轉到另外一臺伺服器的時候就需要重新登入了,所以很多時候我們需要一個客戶只訪問一個伺服器,那麼就需要用iphash了,iphash的每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決session的問題。
upstream test { ip_hash; server localhost:8080; server localhost:8081; }
fair(第三方) 按後端伺服器的響應時間來分配請求,響應時間短的優先分配。
upstream backend { fair; server localhost:8080; server localhost:8081; }
url_hash(第三方) 按訪問url的hash結果來分配請求,使每個url定向到同一個後端伺服器,後端伺服器為快取時比較有效。 在upstream中加入hash語句,server語句中不能寫入weight等其他的引數,hash_method是使用的hash演算法。
upstream backend { hash $request_uri; hash_method crc32; server localhost:8080; server localhost:8081; }
處理動態請求轉發到某一個服務
location = / {
proxy_pass http://localhost:8080
}
此處的proxy_pass 對應的服務,會導到上述upstream入口
5.4 作為靜態資源伺服器
Nginx本身也是一個靜態資源的伺服器,當只有靜態資源的時候,就可以使用Nginx來做伺服器,同時現在也很流行動靜分離,就可以通過Nginx來實現,動靜分離是讓動態網站裡的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以後,我們就可以根據靜態資源的特點將其做快取操作(CDN),這就是網站靜態化處理的核心思路。
# 靜態檔案,nginx自己處理 location ~ ^/(images|javascript|js|css|flash|media|static)/ { root /home/zhouguangyou/artproject/art; # 過期1天,靜態檔案不怎麼更新,過期可以設大一點,如果頻繁更新,則可以設定得小一點。 expires 1d; }
5.5 關於URL路由規則
語法規則:
location [=|~|~*|^~] /uri/
{
…
}
= 開頭表示精確匹配^~ 開頭表示uri以某個常規字串開頭,理解為匹配 url路徑即可。
~ 開頭表示區分大小寫的正則匹配~* 開頭表示不區分大小寫的正則匹配!~和!~*分別為區分大小寫不匹配及不區分大小寫不匹配 的正則/ 通用匹配,任何請求都會匹配到。多個location配置的情況下匹配順序為:
首先匹配 =,其次匹配^~, 其次是按檔案中順序的正則匹配,最後是交給 / 通用匹配。當有匹配成功時候,停止匹配,按當前匹配規則處理請求。
例子,有如下匹配規則:
location = / { #規則A } location = /login { #規則B } location ^~ /static/ { #規則C } location ~ \.(gif|jpg|png|js|css)$ { #規則D } location ~* \.png$ { #規則E } location !~ \.xhtml$ { #規則F } location !~* \.xhtml$ { #規則G } location / { #規則H }
那麼產生的效果如下:
訪問根目錄/, 比如http://localhost/ 將匹配規則A訪問 http://localhost/login 將匹配規則B,http://localhost/register 則匹配規則H訪問 http://localhost/static/a.html 將匹配規則C訪問 http://localhost/a.gif, http://localhost/b.jpg 將匹配規則D和規則E,但是規則D順序優先,規則E不起作用,而 http://localhost/static/c.png 則優先匹配到規則C訪問 http://localhost/a.PNG 則匹配規則E,而不會匹配規則D,因為規則E不區分大小寫。
訪問 http://localhost/a.xhtml 不會匹配規則F和規則G,http://localhost/a.XHTML不會匹配規則G,因為不區分大小寫。規則F,規則G屬於排除法,符合匹配規則但是不會匹配到,所以想想看實際應用中哪裡會用到。
訪問 http://localhost/category/id/1111 則最終匹配到規則H,因為以上規則都不匹配,這個時候應該是nginx轉發請求給後端應用伺服器,比如FastCGI(php),tomcat(jsp),nginx作為方向代理伺服器存在。