Nginx入門,看此文即可
Nginx概述
Nginx是什麼
Nginx是一個高效能的 HTTP 和反向代理伺服器,特點是佔有記憶體少,併發能力強,事實上 Nginx 的併發能力確實在同型別的網頁伺服器中表現較好,Nginx官網:點選這裡。
Nginx能幹什麼
Nginx 可以作為靜態頁面的 web 伺服器,同時還支援 CGI 協議的動態語言,比如 perl、php 等,使用Nginx可以繼續做反向代理、負載均衡、動靜分離等服務。
準備工作
Nginx安裝
環境
- CentOS-7
- VMware-workstation-15
安裝依賴
yum install -y gcc gcc-c++ make libtool wget pcre pcre-devel zlib zlib-devel openssl openssl-devel
安裝Nginx
- 下載從官網下載tar.gz檔案
- 解壓:
tar -zxvf nginx-1.20.1.tar.gz
,根據檔名來。 - 編譯安裝:
cd nginx-1.20.1 ./configure make && make install
Nginx常用命令
安裝完成後的路徑為:/usr/local/nginx
nginx位於/usr/local/nginx/sbin
所以以下命令都是基於這個目錄的
當然也可以將/usr/local/nginx/sbin新增到環境變數中
- 普通啟動服務:./nginx
- 配置檔案啟動:./nginx -c /usr/local/nginx/conf/nginx.conf
- 暴力停止服務:./nginx -s stop
- 優雅停止服務:./nginx -s quit
- 檢查配置檔案:./nginx -t
- 重新載入配置:./nginx -s reload
- 檢視相關程式:ps -ef | grep nginx
開啟防火牆
firewall-cmd --permanent --add-port=80/tcp
# 過載
firewall-cmd reload
瞭解配置檔案
Nginx的配置檔案的格式非常符合邏輯,每一部分都對於著相應的功能。
通過圖片,我們知道,Nginx的配置檔案分為三大部分,加上http塊包含兩個部分就是5個模組,那麼這5個模組分別是幹什麼的以及它們有哪些常用的配置呢?
全域性模組(main模組)
該模組的配置影響nginx全域性的指令。
常用的配置有:
#配置worker程式執行使用者(和使用者組),nobody也是一個linux使用者,一般用於啟動程式,沒有密碼
user nobody;
#user www www;
#配置工作程式數目,根據硬體調整,通常等於CPU數量或者2倍於CPU數量(雙核時)
worker_processes 1;
#配置全域性錯誤日誌及型別,[debug | info | notice | warn | error | crit],預設是error
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#配置程式pid檔案
pid logs/nginx.pid;
#一個nginx程式開啟的最多檔案描述符數目,理論值應該是最多開啟檔案數(系統的值ulimit -n)與nginx程式數相除,但是nginx分配請求並不均勻,所以建議與ulimit -n的值保持一致。
worker_rlimit_nofile 65535;
events模組
該配置影響nginx伺服器或與使用者的網路連線。
常用的配置有:
#參考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ];
#epoll模型是Linux 2.6以上版本核心中的高效能網路I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
use epoll;
#單個程式最大連線數(最大連線數=連線數*程式數)
worker_connections 65535;
http模組
作為web伺服器,http模組是nginx最核心的一個模組,配置項也是比較多的,專案中會設定到很多的實際業務場景,需要根據硬體資訊進行適當的配置。可以巢狀多個server,配置代理,快取,日誌定義等絕大多數功能和第三方模組的配置。
一些常用配置:
#常見的一些基礎配置
include mime.types; #副檔名與檔案型別對映表
default_type application/octet-stream; #預設檔案型別
charset utf-8; #預設編碼
server_names_hash_bucket_size 128; #伺服器名字的hash表大小
client_header_buffer_size 32k; #上傳檔案大小限制
large_client_header_buffers 4 64k; #設定請求緩衝
client_max_body_size 8m; #設定請求緩衝
sendfile on; #開啟高效檔案傳輸模式,對於普通應用設為on,如果用來進行下載等應用磁碟IO重負載應用,可設定為off,以平衡磁碟與網路I/O處理速度,降低系統的負載。注意:如果圖片顯示不正常把這個改成off。
autoindex on; #開啟目錄列表訪問,合適下載伺服器,預設關閉。
tcp_nopush on; #防止網路阻塞
tcp_nodelay on; #防止網路阻塞
keepalive_timeout 120; #長連線超時時間,單位是秒
#FastCGI相關引數是為了改善網站的效能:減少資源佔用,提高訪問速度。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
#gzip模組設定
gzip on; #開啟gzip壓縮輸出
gzip_min_length 1k; #最小壓縮檔案大小
gzip_buffers 4 16k; #壓縮緩衝區
gzip_http_version 1.0; #壓縮版本(預設1.1,前端如果是squid2.5請使用1.0)
gzip_comp_level 2; #壓縮等級
gzip_types text/plain application/x-javascript text/css application/xml; #壓縮型別
gzip_vary on; #增加響應頭'Vary: Accept-Encoding'
limit_zone crawler $binary_remote_addr 10m; #開啟限制IP連線數的時候需要使用
server模組
配置虛擬主機的相關引數,一個http中可以有多個server。server模組可以配置網路監聽、配置https服務、基於名稱的虛擬主機配置、基於IP的虛擬主機配置。
常用的配置:
#虛擬主機的常見配置
server {
listen 80; #配置監聽埠
server_name localhost; #配置服務名
charset utf-8; #配置字符集
access_log logs/host.access.log main; #配置本虛擬主機的訪問日誌
location / {
root html; #root是配置伺服器的預設網站根目錄位置,預設為nginx安裝主目錄下的html目錄
index index.html index.htm; #配置首頁檔案的名稱
}
error_page 404 /404.html; #配置404錯誤頁面
error_page 500 502 503 504 /50x.html; #配置50x錯誤頁面
}
#配置https服務,安全的網路傳輸協議,加密傳輸,埠443
server {
listen 443 ssl;
server_name localhost;
ssl_certificate cert.pem;
ssl_certificate_key cert.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
location模組
配置請求的路由,以及各種頁面的處理情況。
root html; #root是配置伺服器的預設網站根目錄位置,預設為nginx安裝主目錄下的html目錄
index index.html index.htm; #配置首頁檔案的名稱
proxy_pass http://127.0.0.1:88; #反向代理的地址
proxy_redirect off; #是否開啟重定向
#後端的Web伺服器可以通過X-Forwarded-For獲取使用者真實IP
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
#以下是一些反向代理的配置,可選。
client_max_body_size 10m; #允許客戶端請求的最大單檔案位元組數
client_body_buffer_size 128k; #緩衝區代理緩衝使用者端請求的最大位元組數,
proxy_connect_timeout 90; #nginx跟後端伺服器連線超時時間(代理連線超時)
proxy_send_timeout 90; #後端伺服器資料回傳時間(代理髮送超時)
proxy_read_timeout 90; #連線成功後,後端伺服器響應時間(代理接收超時)
proxy_buffer_size 4k; #設定代理伺服器(nginx)儲存使用者頭資訊的緩衝區大小
proxy_buffers 4 32k; #proxy_buffers緩衝區,網頁平均在32k以下的設定
proxy_busy_buffers_size 64k; #高負荷下緩衝大小(proxy_buffers*2)
proxy_temp_file_write_size 64k; #設定快取資料夾大小
我們在上面的圖片中可以看到,location的配置格式一般是這樣的:
location / {
proxy_pass http://127.0.0.1:5000;
root html;
index index.html index.htm;
}
即:
location [ = | ~ | ~* | ^~ ] uri {
}
這些符號是對uri的約束,它們表示:
- = :用於不含正規表示式的 uri 前,要求請求字串與 uri 嚴格匹配,如果匹配成功,就停止繼續向下搜尋並立即處理該請求。
- ~ :用於表示 uri 包含正規表示式,並且區分大小寫。
- ~* :用於表示 uri 包含正規表示式,並且不區分大小寫。
- ^~ :用於不含正規表示式的 uri 前,要求 Nginx 伺服器找到標識 uri 和請求字串匹配度最高的 location 後,立即使用此 location 處理請求,而不再使用 location 塊中的正則 uri 和請求字串做匹配。
需要注意的是:如果 uri 包含正規表示式,則必須要有 ~
或者~*
標識
反向代理
Nginx 不僅可以做反向代理,還能用作正向代理來進行上網等功能。反向代理(Reverse Proxy)方式是指以代理伺服器來接受internet上的連線請求,然後將請求轉發給內部網路上的伺服器,並將從伺服器上得到的結果返回給internet上請求連線的客戶端,此時代理伺服器對外就表現為一個伺服器。
更多見:【大型網站技術實踐】初級篇:藉助Nginx搭建反向代理伺服器
案例一
實現效果
即我們訪問一個url,nginx自動將我們的請求轉發到flask等伺服器上。
實現步驟
- 修改hosts檔案
windos的host檔案位於:C:\Windows\System32\drivers\etc\hosts
,linux的host檔案位於:/etc/hosts
- 修改nginx配置檔案
需要用到配置:http > server > location > proxy_passvim /usr/local/nginx/conf/nginx.conf
proxy_pass
引數,注意書寫格式,結尾不要漏掉;
。server { listen 80; server_name 192.168.43.12; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://192.168.43.13:5000; }
- 啟動或重啟nginx
# nginx未執行,直接啟動 /usr/local/nginx/sbin/nginx # nginx正在執行,則過載配置 /usr/local/nginx/sbin/nginx -s reload
- 啟動flask專案
python app.py
# app.py from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "<h1>index</h1>" if __name__ == '__main__': app.run()
- 用瀏覽器訪問:
www.abc.com
,檢驗是否代理成功。
假如沒有代理成功,請檢查防火牆,常用的防火牆命令如下:
查詢 firewall-cmd --query-port=埠/協議
開啟埠 firewall-cmd --permanent --add-port=埠/協議
關閉埠 firewall-cmd --permanent --remove-port=埠/協議
注意開啟或關閉埠後,需要重新載入才能生效:firewall-cmd reload
案例二
上面只設定了一臺代理伺服器,假如我要設定多臺呢?如何根據url將請求分配到不同伺服器中?
實現效果
實現步驟
- 修改host
- 修改配置檔案
在server模組中加入兩個location模組,~
代表什麼意思見:上文的 "準備工作" 中的 "瞭解配置檔案"
location ~ /news/ {
proxy_pass http://192.168.43.13:5000;
}
location ~ /music/ {
proxy_pass http://192.168.43.14:5001;
}
- 然後啟動兩個flask
- 再用瀏覽器訪問
負載均衡
早期的系統的架構模式相對單一:客戶端傳送多個請求到伺服器,伺服器處理請求,有一些可能要與資料庫進行互動,伺服器處理完畢後,再將結果返回給客戶端。
但是隨著資訊數量的不斷增長,訪問量和資料量的飛速增長,以及系統業務的複雜度增加,造成伺服器處理客戶端的請求變得日益緩慢,併發量特別大的時候,還容易造成伺服器直接崩潰。這時候叢集的概念產生了,單個伺服器解決不了,我們增加伺服器的數量,然後將請求分發到各個伺服器上,將原先請求集中到單個伺服器上的情況改為將請求分發到多個伺服器上,將負載分發到不同的伺服器,也就是我們所說的負載均衡。
實現效果
實現步驟
- 修改Nginx配置檔案
http > server > location > proxy_pass和http > upstream > serverupstream mysite { # 叢集名字 server 192.168.43.14:5000; server 192.168.43.13:5001; } server { location / { proxy_pass http://mysite; } }
- 啟動flask專案
- 將flask的埠新增到防火牆
- 使用瀏覽器開啟
負載均衡的策略
上面我們指定指定負載均衡,使用的是預設的策略:輪詢,除此之外,nginx還有其它策略供我們選擇:
- 輪詢(預設)
每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器宕掉,能自動剔除。upstream server_pool{ server 192.168.43.13:5000; server 192.168.43.14:5001; }
- weight
weight 代表權重,預設為1,權重越高被分配的客戶端越多,weight 和訪問比率成正比,用於後端伺服器效能不均的情況。upstream server_pool{ server 192.168.43.13:5000 weight=10; server 192.168.43.14:5001 weight=20; }
- ip_hash
每個請求按訪問 ip 的 hash 結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決 session 的問題。upstream server_pool{ ip_hash; server 192.168.43.13:5000; server 192.168.43.14:5001; }
- fair
按後端伺服器的響應時間來分配請求,響應時間短的優先分配。
注意,此為第三方模組,需要安裝。可參考此文教程:nginx負載均衡fair模組安裝和配置。upstream server_pool{ server 192.168.43.13:5000; server 192.168.43.14:5001; fair; }
動靜分離
Nginx 動靜分離簡單來說就是把動態跟靜態請求分開,不能理解成只是單純的把動態頁面和靜態頁面物理分離。嚴格意義上說應該是動態請求跟靜態請求分開,可以理解成使用 Nginx 處理靜態頁面,而其它的web應用處理動態頁面。。動靜分離從目前實現角度來講大致分為兩種,一種是純粹把靜態檔案獨立成單獨的域名,放在獨立的伺服器上,也是目前主流推崇的方案;另外一種方法就是動態跟靜態檔案混合在一起釋出,通過 Nginx 來分開。
實現效果
由圖可以看出,載入圖片並沒有走flask伺服器,而是nginx處理的。
實現步驟
由於nginx處理靜態資源的能力也強,所以這裡使用nginx處理靜態資源。
-
在nginx目錄下建立一個static目錄
─conf ├─contrib │ ├─unicode2nginx │ └─vim │ ├─ftdetect │ ├─ftplugin │ ├─indent │ └─syntax ├─docs ├─html │ └─static ├─logs ├─static └─temp ├─client_body_temp ├─fastcgi_temp ├─proxy_temp ├─scgi_temp └─uwsgi_temp
-
修改配置檔案
location ~ .*\.(gif|jpg|ico|png|css|svg|js)$ { root static; } location / { proxy_pass http://192.168.43.14:5000; }
該配置表示,gif、jpg、ico、png、css、svg、js結尾的,都去static目錄找。具體要什麼格式的檔案,可以自己根據上面的配置,加上去。
-
flask這樣配置
from flask import Flask, render_template app = Flask(__name__) @app.route("/") def index(): return render_template("index.html") if __name__ == '__main__': app.run(port=5000)
這是index.html檔案:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index page</title> </head> <body> <h1>index</h1> <img src="/img/reload.gif" alt="reload" title="reload.gif"> </body> </html>
-
將靜態資源放到static目錄下,根據請求確定是否要建立子目錄。
如我這裡請求的是/img/reload.gif
,所以要把reload.gif
檔案放在static/img/
目錄下 -
使用瀏覽器訪問
html檔案,可使用以下格式配置,然後html檔案放在nginx/html下
location ~ .*\.(html|htm)$ { root html; expires 1h; }
但我目前還不知道如何在html也分離的情況下,繼續使用flask返回頁面。知道的朋友可以在評論區留言,謝謝。
這裡有幾篇django前後端分離的文章,僅做記錄
高可用叢集
高可用叢集是指以減少服務中斷時間為目的的伺服器叢集技術。它通過保護使用者的業務程式對外不間斷提供的服務,把因軟體/硬體/人為造成的故障對業務的影響降低到最小程度。一般來說就是,假如Nginx掛了,服務怎樣才能不中斷?(代理伺服器掛了的話,Nginx不會把請求傳送過去,見負載均衡哪裡)
實現思路
實現步驟
由上圖我們可知,要實現這個功能必須要有三個部分:
- Nginx MASTER
- Nginx BACKUP
- 虛擬IP實質上就是Keepalived
關於見此文:Linux高可用之Keepalived
下面我們開始正式配置。
注意:由於我們要求兩臺機器同時做nginx代理,nginx配置的IP地址應當是一樣的,而Keepalived的router_id配置指的是當前機器的ip,所以應該不一樣。
Nginx MASTER配置
-
安裝keepalived
yum install -y keepalived
-
配置keepalived
vim /etc/keepalived/keepalived.conf
主要注意這幾個項
router_id 當前虛擬機器的IP地址
state 這個機器是MASTER還是BACKUP
interface 當前機器的網路卡名稱,用於繫結虛擬IP
virtual_router_id 虛擬路由的編號注意:ip地址和網路卡名稱都應該根據自己的機器來配置
! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc #郵件伺服器通知地址(暫不配置,預設即可) smtp_server 192.168.43.1 #郵件伺服器超時時間(暫不配置,預設即可) smtp_connect_timeout 30 #當前虛擬機器的IP地址 router_id 192.168.43.12 } vrrp_script Monitor_Nginx { script "/etc/keepalived/nginx_check.sh" #檢測指令碼執行的路徑 interval 2 #檢測指令碼執行的間隔 weight 2 #檢測指令碼執行的權重 } vrrp_instance VI_1 { state MASTER #標識這個機器是MASTER還是BACKUP interface eth3 #當前機器的網路卡名稱 virtual_router_id 51 #虛擬路由的編號,主備必須一致 priority 100 #主、備機取不同的優先順序,主機值較大,備份機值較小 advert_int 1 #(VRRP Multicast廣播週期秒數) authentication { auth_type PASS #(VRRP認證方式) auth_pass 1111 #(密碼) } track_script { Monitor_Nginx #(呼叫nginx程式檢測指令碼) } virtual_ipaddress { 192.168.43.50 #虛擬IP地址 } }
-
新增keepalived的檢測指令碼
vim /etc/keepalived/nginx_check.sh
如果 nginx 停止執行,嘗試啟動,如果無法啟動則殺死本機的 keepalived 程式, keepalied將虛擬 ip 繫結到 BACKUP 機器上。
# /etc/keepalived/nginx_check.sh #!/bin/bash A=`ps -C nginx –no-header |wc -l` if [ $A -eq 0 ];then /usr/local/nginx/sbin/nginx sleep 2 if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then killall keepalived fi fi
給指令碼賦執行許可權:
chmod +x /etc/keepalived/nginx_check.sh
-
啟動keepalived服務
systemctl start keepalived
Nginx BACKUP配置
這是另一個機器。
-
下載、配置Nginx
將MASTER的複製過來即可
注意防火牆:firewall-cmd --permanent --add-port=80/tcp
和firewall-cmd reload
-
下載安裝keepalived
見上文操作 -
配置keepalived
需要改的地方應該是:
router_id和state以及interface! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc #郵件伺服器通知地址(暫不配置,預設即可) smtp_server 192.168.43.1 #郵件伺服器超時時間(暫不配置,預設即可) smtp_connect_timeout 30 #當前虛擬機器的IP地址 router_id 192.168.43.10 } vrrp_script Monitor_Nginx { script "/etc/keepalived/nginx_check.sh" #檢測指令碼執行的路徑 interval 2 #檢測指令碼執行的間隔 weight 2 #檢測指令碼執行的權重 } vrrp_instance VI_1 { state BACKUP #標識這個機器是MASTER還是BACKUP interface eth3 #當前機器的網路卡名稱 virtual_router_id 51 #虛擬路由的編號,主備必須一致 priority 10 #主、備機取不同的優先順序,主機值較大,備份機值較小 advert_int 1 #(VRRP Multicast廣播週期秒數) authentication { auth_type PASS #(VRRP認證方式) auth_pass 1111 #(密碼) } track_script { Monitor_Nginx #(呼叫nginx程式檢測指令碼) } virtual_ipaddress { 192.168.43.50 #虛擬IP地址 } }
-
新增keepalived的檢測指令碼
vim /etc/keepalived/nginx_check.sh
如果 nginx 停止執行,嘗試啟動,如果無法啟動則殺死本機的 keepalived 程式, keepalied將虛擬 ip 繫結到 BACKUP 機器上。
# /etc/keepalived/nginx_check.sh #!/bin/bash A=`ps -C nginx –no-header |wc -l` if [ $A -eq 0 ];then /usr/local/nginx/sbin/nginx sleep 2 if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then killall keepalived fi fi
給指令碼賦執行許可權:
chmod +x /etc/keepalived/nginx_check.sh
-
啟動keepalived服務
systemctl start keepalived
原理分析
多程式單執行緒
Nginx 自己實現了對epoll的封裝,是多程式單執行緒的典型代表。使用多程式模式,不僅能提高併發率,而且程式之間是相互獨立的,一 個worker程式掛了不會影響到其他worker程式。當Nginx啟動後,會執行一個master程式和多個worker程式。其中master充當整個程式組與使用者的互動介面,同時對程式進行監護,管理worker程式來實現重啟服務、平滑升級、更換日誌檔案、配置檔案實時生效等功能。worker用來處理基本的網路事件,worker之間是平等的,他們共同競爭來處理來自客戶端的請求。
見此文Nginx工作原理(Master+Worker)
worker的工作模式
worker對於連線是採用爭搶的模式,誰先搶到就先交給誰處理。如果想要重新更新配置,由於已經搶到任務的worker不會參與爭搶,那些空閒的worker就會去爭搶連線,拿到連線後會自動更新配置資訊。而那些有任務的worker在完成任務後,會自動更新配置。這樣就實現了無縫熱部署。由於每個worker是獨立的程式,如果有其中的一個worker出現問題,並不會影響其它worker繼續進行爭搶,在實現請求的過程,不會造成服務中斷。worker數應該根據伺服器的cpu的核心數量而定,建議設定為cup數(單核)或cup數*2(雙核),詳情見評論區的連結。
worker連線數和最大的併發數
如果只訪問nginx的靜態資源,一個傳送請求會佔用了 woker 的 2 個連線數,最大併發數量應該是:worker_connections * worker_processes / 2
而如果是作為反向代理伺服器,一個傳送請求會佔用了 woker 的 4 個連線數,最大併發數量應該是:worker_connections * worker_processes / 4