一涛癌、3W問題
1.1 Nginx是什么
Nginx本質(zhì)上是一個輕量級的Web服務(wù)器、高性能的HTTP服務(wù)器、反向代理服務(wù)器周蹭、同時也是一個IMAP/POP3/SMTP代理服務(wù)器爵嗅。
1.2 為什么要使用Nginx
單體服務(wù)場景下可以不使用Nginx娇澎,但是集群環(huán)境為了讓請求合理地分布到各個服務(wù)器上,就需要再加上一層負(fù)載層睹晒,負(fù)責(zé)對請求進(jìn)行轉(zhuǎn)發(fā)趟庄。(沒有什么架構(gòu)難題是加一層不能解決的,如果有伪很,那就再加一層)
Nginx最大的特點(diǎn)就是性能穩(wěn)定戚啥,支持的并發(fā)數(shù)高,占用的資源較少锉试。除此之外猫十,還包含如下的功能:
- HTTP服務(wù)器;可以作為一個HTTP服務(wù)器提供HTTP請求訪問呆盖;
- 反向代理拖云;代理用戶要訪問的目標(biāo)服務(wù)器;
- 負(fù)載均衡应又;高并發(fā)場景下分流請求到多個服務(wù)器上宙项;支持的方式有輪詢、權(quán)重丁频、ip哈希杉允、url哈希、按響應(yīng)時間等席里;
- 動靜分離叔磷;應(yīng)用于前后端分離的項目,將前端和后端的請求分離奖磁;
1.3 如何使用
Windows系統(tǒng)下改基,下載zip包,解壓縮后咖为,進(jìn)入文件夾秕狰,使用命令行執(zhí)行命令./nginx.exe
即可,此時訪問localhost:80
即可躁染。
Linux系統(tǒng)下安裝可以參考《Linux安裝nginx》鸣哀,本文強(qiáng)烈推薦使用Docker拉取nginx鏡像進(jìn)行學(xué)習(xí)。
docker pull nginx:latest
docer run -d -p 80:80 --name my-nginx nginx:latest
如下內(nèi)容都是基于Linux下的nginx進(jìn)行講解吞彤。
如下是一些常用的命令來實現(xiàn)nginx的不同功能:
./nginx
我衬、./nginx -c path/nginx.conf
叹放,使用默認(rèn)配置文件或者使用指定的配置文件啟動;-
nginx -t
挠羔、nginx -t -c path/nginx.conf
井仰,驗證配置是否正確;# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
-
nginx -v
破加,查看版本號俱恶;# nginx -v nginx version: nginx/1.21.4
nginx -s quit
,正常停止和關(guān)閉nginx范舀;nginx -s stop
合是,強(qiáng)制快速停止和關(guān)閉nginx;-
nginx -s reload
尿背,配置文件修改后重新裝載啟動端仰;# nginx -s reload 2021/11/23 01:14:51 [notice] 40#40: signal process started
二、文件夾分類
2.1 Windows
- conf田藐,用來存放配置的目錄,其中最主要的就是nginx.conf文件吱七;
- html汽久,默認(rèn)的靜態(tài)資源目錄,index.html作為默認(rèn)主頁踊餐;
- logs景醇,默認(rèn)的日志目錄,主要有access.log和error.log吝岭;
2.2 Docker
-
/usr/share/nginx/html/
三痰,默認(rèn)的靜態(tài)資源目錄,index.html作為默認(rèn)主頁窜管; -
/etc/nginx/
散劫,用來存放配置的目錄,其中最主要的就是nginx.conf文件幕帆; -
/var/log/nginx/
获搏,用來存放日志的目錄,主要有access.log和error.log失乾;
三常熙、默認(rèn)配置文件
配置文件內(nèi)容可以有很多很復(fù)雜,但是總體來說分為如下幾個模塊:
- 全局塊碱茁,配置影響nginx全局的指令裸卫。一般有運(yùn)行nginx服務(wù)器的用戶組,nginx進(jìn)程pid存放路徑纽竣,日志存放路徑墓贿,配置文件引入,允許生成worker process數(shù)等;
- 事件塊募壕,配置影響nginx服務(wù)器或與用戶的網(wǎng)絡(luò)連接调炬。有每個進(jìn)程的最大連接數(shù),選取哪種事件驅(qū)動模型處理連接請求舱馅,是否允許同時接受多個網(wǎng)路連接缰泡,開啟多個網(wǎng)絡(luò)連接序列化等;
- HTTP塊代嗤,可以嵌套多個server棘钞,配置代理,緩存干毅,日志定義等絕大多數(shù)功能和第三方模塊的配置宜猜。如文件引入,mime-type定義硝逢,日志自定義姨拥,是否使用sendfile傳輸文件,連接超時時間渠鸽,單連接請求數(shù)等叫乌;
- server塊,配置虛擬主機(jī)的相關(guān)參數(shù)徽缚,一個http中可以有多個server憨奸。
- location塊,配置請求的路由凿试,以及各種頁面的處理情況排宰。
- server塊,配置虛擬主機(jī)的相關(guān)參數(shù)徽缚,一個http中可以有多個server憨奸。
如下是初始狀態(tài)下nginx.conf
配置的內(nèi)容:
########### 每個指令必須有分號結(jié)束。#################
#####全局塊#####
#配置的用戶或者組
user nginx;
#配置工作進(jìn)程數(shù)量
worker_processes auto;
#配置錯誤日志目錄和級別
error_log /var/log/nginx/error.log notice;
#主進(jìn)程ID記錄
pid /var/run/nginx.pid;
#####全局塊#####
#####事件塊#####
events {
#配置最大連接數(shù)
worker_connections 1024;
}
#####事件塊#####
#####HTTP塊#####
http {
#包含其它配置文件那婉,mime.types是MIME類型映射表板甘,根據(jù)返回文件的后綴名在該配置中找到MIME類型放到"Content_Type"中
include /etc/nginx/mime.types;
#默認(rèn)文件類型,即MIME類型的"Content_Type"
default_type application/octet-stream;
#配置日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#配置訪問日志目錄和級別
access_log /var/log/nginx/access.log main;
#配置允許傳輸文件
sendfile on;
#配置啟用最小傳輸限制功能
#tcp_nopush on;
#配置連接超時時間
keepalive_timeout 65;
#配置開啟gizp壓縮
#gzip on;
#引入其它配置項內(nèi)容
include /etc/nginx/conf.d/*.conf;
}
#####HTTP塊#####
引入的mime.types
默認(rèn)配置如下:
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
......
text/mathml mml;
text/plain txt;
......
image/avif avif;
image/png png;
......
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
......
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
......
}
引入的conf.d
文件夾下面就一個default.conf
配置文件吧恃,內(nèi)容如下:
#配置一個虛擬主機(jī)
server {
#配置監(jiān)聽的端口
listen 80;
listen [::]:80;
#配置當(dāng)前server的虛擬服務(wù)器識別路徑虾啦,nginx根據(jù)請求頭中的Host字段來匹配具體的server進(jìn)行處理
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
#配置匹配的路徑
location / {
#尋找文件的目錄
root /usr/share/nginx/html;
#默認(rèn)返回的文件資源
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
如此,一個默認(rèn)的配置就是如此痕寓。我們啟動nginx之后傲醉,訪問localhost:80
就能訪問到index.html的內(nèi)容了。
四呻率、實例演示——反向代理
目標(biāo):使用Docker啟動兩個nginx服務(wù):service1和service2硬毕,代表兩個后端服務(wù)。然后再啟動一個nginx服務(wù)作為反向代理服務(wù)器礼仗,根據(jù)請求路徑的不同將請求分發(fā)給service1和service2吐咳。
創(chuàng)建文件夾nginx-demo逻悠,里面創(chuàng)建service1文件夾、service2文件夾韭脊、my-nginx文件夾童谒;
service1下面文件內(nèi)容分別如下:
-
index.html
,代表service1服務(wù)的內(nèi)容沪羔;<!DOCTYPE html> <head> <title>Service1</title> </head> <body> <h1>Message from Service1!</h1> </body>
-
default.conf
饥伊,代表service1的nginx-server的配置;server { listen 80; server_name localhost; #匹配/service1/路徑 location /service1 { # 去/usr/share/nginx/html/下面找文件 alias /usr/share/nginx/html/; # 默認(rèn)返回文件 index index.html; } # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
-
Dockerfile
蔫饰,鏡像打包文件琅豆;FROM nginx:latest COPY ./default.conf /etc/nginx/conf.d/ COPY ./index.html /usr/share/nginx/html/ EXPOSE 80
此時執(zhí)行如下打包鏡像和運(yùn)行容器的命令:
docker build -t zhangxun/service1:1.0.1 .
docker run -d -p 8081:80 --name service1 zhangxun/service1:1.0.1
此時訪問http://localhost:8081/service1/
就能訪問到service1的服務(wù)內(nèi)容了。
service2文件夾下的內(nèi)容和service1基本雷同篓吁,此處不再贅述茫因,通過http://localhost:8082/service2/
就能訪問到service2的服務(wù)內(nèi)容了。
最后杖剪,需要配置反向代理服務(wù)器冻押,在my-nginx文件夾下創(chuàng)建如下文件內(nèi)容:
-
default.conf
,代表反向代理服務(wù)器的nginx-server的配置盛嘿;server { listen 80; server_name localhost; location /service1 { # 需要填寫宿主機(jī)的地址 翼雀,而不是localhost,不然就是my-nginx容器內(nèi)部 proxy_pass http://172.21.32.1:8081/service1/; } location /service2 { # 需要填寫宿主機(jī)的地址 孩擂,而不是localhost,不然就是my-nginx容器內(nèi)部 proxy_pass http://172.21.32.1:8082/service2/; } # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
-
Dockerfile
箱熬,鏡像打包文件类垦;FROM nginx:latest COPY ./default.conf /etc/nginx/conf.d/ EXPOSE 80
此時執(zhí)行如下打包鏡像和運(yùn)行容器的命令:
docker build -t zhangxun/my-nginx:1.0.1 .
docker run -d -p 80:80 --name my-nginx zhangxun/my-nginx:1.0.1
此時訪問http://localhost:80/service1
就能得到service1的內(nèi)容,訪問http://localhost:80/service2
就能得到service2的內(nèi)容城须;如此反向代理的目標(biāo)就實現(xiàn)了蚤认。大致實現(xiàn)原理圖如下。
注意事項:
location有兩種寫法糕伐,
location /path
是模糊匹配砰琢,location = /path
是精確匹配;root /path
會去/path/location/
目錄下面去找文件良瞧;alias /path
會在/path/
下面去找文件陪汽;它們的區(qū)別就是alias不會帶上location的路徑;my-nginx配置中代理的服務(wù)器地址不能寫localhost褥蚯,否則就還是訪問自己容器內(nèi)部的服務(wù)挚冤;
-
反向代理服務(wù)器中只配置了一個server,兩個location代表兩個服務(wù)赞庶,也可以配置成兩個server训挡,如下配置所示澳骤,效果是一樣的。
server { listen 80; server_name localhost; location /service1 { # 需要填寫宿主機(jī)的地址 澜薄,而不是localhost为肮,不然就是my-nginx容器內(nèi)部 proxy_pass http://172.21.32.1:8081/service1/; } # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } server { listen 80; server_name localhost; location /service2 { # 需要填寫宿主機(jī)的地址 ,而不是localhost肤京,不然就是my-nginx容器內(nèi)部 proxy_pass http://172.21.32.1:8082/service2/; } # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
五颊艳、實例演示——動靜分離
動靜分離和反向代理的原理及配置幾乎都是相同的,只不過靜態(tài)資源并不算是一個服務(wù)蟆沫,而是存放在nginx上的資源籽暇,通過請求路徑來區(qū)分,究竟是把請求轉(zhuǎn)發(fā)給服務(wù)饭庞,還是從nginx上的某個路徑下去尋找資源戒悠,由于比較簡單,不再重復(fù)演示舟山。
六绸狐、實例演示——負(fù)載均衡
目標(biāo):使用Docker啟動兩個nginx服務(wù):service1和service2,代表兩個后端服務(wù)累盗。然后再啟動一個nginx服務(wù)作為負(fù)載均衡服務(wù)器寒矿,將請求分發(fā)給service1和service2。
4.1 準(zhǔn)備工作
復(fù)用第四節(jié)的案例若债,但是service1和service2的default.conf更改如下:
server {
listen 80;
server_name localhost;
#匹配/路徑
location / {
# 去/usr/share/nginx/html/下面找文件
alias /usr/share/nginx/html/;
# 默認(rèn)返回文件
index index.html;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
其余內(nèi)容保持不變符相,構(gòu)建鏡像并啟動容器后測試下訪問http://localhost:8081
和http://localhost:8082
能否正常返回內(nèi)容。
4.2 負(fù)載均衡服務(wù)搭建
不同于反向代理蠢琳,需要根據(jù)不同的請求路徑轉(zhuǎn)發(fā)請求到不同的服務(wù)啊终;負(fù)載均衡則是將相同的請求按照負(fù)載規(guī)則轉(zhuǎn)發(fā)給某個服務(wù)集群中的一個服務(wù)。我們新建一個nginx.conf
配置文件傲须,用來替換etc/nginx/nginx.conf
的默認(rèn)配置文件蓝牲。
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
# my-service用于兩個上游服務(wù)
upstream my-service {
server 172.21.32.1:8081;
server 172.21.32.1:8082;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://my-service;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
Dockerfile稍作改變:
FROM nginx:latest
COPY ./nginx.conf /etc/nginx/
EXPOSE 80
然后執(zhí)行構(gòu)建和啟動容器的命令,我們訪問localhost:80
就會發(fā)現(xiàn)泰讽,service1和service2被輪詢?yōu)槲覀兲峁┓?wù)例衍,如此就實現(xiàn)了負(fù)載均衡的實例。
4.3 負(fù)載策略
Nginx負(fù)載均衡是通過upstream模塊來實現(xiàn)的已卸,內(nèi)置實現(xiàn)了三種負(fù)載策略:
-
輪詢(默認(rèn)策略)佛玄,根據(jù)請求次數(shù),將每個請求均勻地或者按照權(quán)重分配到每個服務(wù)上咬最;
upstream my-service { server 172.21.32.1:8081 weight=1; server 172.21.32.1:8082 weight=2; }
weight表示權(quán)重翎嫡,數(shù)值越大,被分到請求的次數(shù)越多永乌。
-
最少連接惑申,將請求分配給連接數(shù)最少的服務(wù)具伍,Nginx會統(tǒng)計哪些服務(wù)器的連接數(shù)最少;
upstream my-service { least_conn; server 172.21.32.1:8081; server 172.21.32.1:8082; }
-
IP Hash圈驼,綁定處理請求的服務(wù)器人芽;第一次請求時,根據(jù)該客戶端的IP算出一個HASH值绩脆,將請求分配到集群中的某一臺服務(wù)器上萤厅;后面該客戶端的所有請求,都將通過HASH算法靴迫,找到之前處理這臺客戶端請求的服務(wù)器惕味,然后將請求交給它來處理;
upstream my-service { ip_hash; server 172.21.32.1:8081; server 172.21.32.1:8082; }
除了內(nèi)置的負(fù)載策略玉锌,還有其它第三方插件提供的負(fù)載策略名挥,這些策略需要在nginx服務(wù)器上單獨(dú)安裝:
-
Fair,按照后端服務(wù)器的響應(yīng)時間來分配請求主守,響應(yīng)時間短的會被分配更多請求瘦材;
upstream my-service { fair; server 172.21.32.1:8081; server 172.21.32.1:8082; }
-
URL Hash刃榨,按訪問url的hash結(jié)果來分配請求曙强,使每個url定向到同一個后端服務(wù)器拣播,后端服務(wù)器為緩存服務(wù)器時比較有效;
upstream my-service { hash $request_uri; hash_method crc32; server 172.21.32.1:8081; server 172.21.32.1:8082; }
4.4 負(fù)載狀態(tài)
- weight涎才,默認(rèn)為1鞋既,表示服務(wù)的權(quán)重,數(shù)值越大耍铜,被分到的請求越多涛救;
- max_fails,默認(rèn)為1业扒,該服務(wù)被允許請求失敗的次數(shù),一旦超過則會選擇其它服務(wù)舒萎;
- fail_timeout程储,默認(rèn)10秒,服務(wù)在請求失敗max_fails次數(shù)后臂寝,在fail_timeout時間內(nèi)不會再給它分配請求章鲤;
- backup,表示備份服務(wù)咆贬,所有服務(wù)都不可用是才分配請求給備份服務(wù)败徊;
- down,表示下線掏缎,該服務(wù)不參與負(fù)載皱蹦;
- max_conns煤杀,該服務(wù)允許的最大連接數(shù)量,超過時將不會再分配請求給它沪哺,默認(rèn)為0表示不限制沈自;
- 等等其它狀態(tài)可以參考官網(wǎng)文檔;