目錄導航
前言
前面我們簡單的介紹了Nginx的安裝使用,配置文件以及模塊的使用細則,這一節,主要講一下Nginx的實際應用場景~
- Nginx的初步認識及配置
- Nginx的應用實戰
- Nginx的擴展
反向代理
比較經典的Nginx服務器做反向代理/負載均衡的架構圖:
- 用戶的請求首先通過瀏覽器請求到Nginx服務器
- 由Nginx服務器做負載均衡,決定請求具體哪個Tomcat服務器
- Nginx最終將結果返回給客戶端
接下來,我們準備三臺機器模擬一下這個場景:
linux1:192.168.200.111(Nginx服務器)
linux2:192.168.200.112 (Tomcat服務器)
linux3:192.168.200.113(Tomcat服務器)
首先啓動兩臺Tomcat服務器:
linux2:
linux3同理,我就不截圖了,至於Tomcat的安裝過程基本也很簡單
- 去官網下載Tomcat的jar包
- tar -zxvf 解壓jar包
- 進入bin目錄啓動即可,同nginx一樣,也存在配置文件,可以修改端口等操作
具體安裝過程略,不懂着可自行百度,都是小白操作。
現在我們啓動了linux2與Linux3的tomcat,默認是8080端口,我們在瀏覽器上看一下效果:
篇幅有限,不截圖linux3的tomcat歡迎界面了
接下來,修改linux1上nginx安裝目錄下/conf/nginx.conf 配置文件
這裏通過include指令可以引入額外的配置文件信息,而不用修改nginx.conf主配置文件了,這裏採用通配符寫法,好處就在於:
- 便於管理多配置文件
- 解耦:根據不同功能,不同模塊進行劃分,不同的域進行分離
因此就可以將.conf
爲結尾的文件都加載到當前主配置文件中。
接下來,我們自行創建.conf文件,實現反向代理
進入剛纔在主配置文件裏設定的目錄,並添加
proxy_demo.conf
,名稱不限,只要以.conf爲後綴即可。
接下來,關鍵一步,配置代理:
server {
listen 80;
server_name localhost;
location / {
# 用戶訪問當前機器localhost:80,會跳轉此地址
proxy_pass http://192.168.200.112:8080;
# 將當前nginx機器地址暴露,放置在請求頭
proxy_set_header Host $host;
# 將實際請求的用戶ip地址暴露,放置在請求頭
proxy_set_header X-Real-IP $remote_addr;
# 獲取到所有代理服務器的地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
然後重新加載配置文件,到linux/sbin
我們發現,在linux1上啓動nginx後,由nginx代理到linux2的ip:8080 ,也就是剛纔我們啓動的Tomcat,達到了反向代理的效果
負載均衡
網絡負載均衡的大致原理是利用一定的分配策略將網絡負載平衡地分攤到網絡集羣的各個操作單元上,使得單個重負載任務能夠分擔到多個單元上並行處理,使得大量併發訪問或數據流量分擔到多個單元上分別處理,從而減少用戶的等待響應時間
upstream
upstream是Nginx的HTTP Upstream模塊,這個模塊通過一個簡單的調度算法來實現客戶端IP到後端服務器的負載均衡
- Upstream
語法: server address [paramters]
- 負載均衡策略或者算法
-
輪詢算法(默認):如果後端服務器宕機以後,會自動踢出
-
ip_hash :根據請求的ip地址進行hash
-
權重輪詢
這裏我們通過配置weight設置權重,如上圖所示,此時落在linux3的概率就比較大了,通常生產環境,將性能好的機器配置權重更高~ -
…
演示效果
接着剛纔的配置,我們在linux1上nginx的配置文件,引入兩臺tomcat服務器地址:
爲了區分跳轉不同的Tomcat上的效果,我們在linux2的tomcat首頁index.jsp加入不同的元素:
編輯index.jsp
接下來,重啓linux1上的nginx(因爲修改了nginx的配置文件),打開瀏覽器,訪問linux1:,我們發現,會輪詢訪問linux2與Linux3的tomcat地址:
這個明顯是linux2的地址,因爲剛纔我們在頁面上加入了獲取ip地址的標籤
剩下這個明顯是linux3的tomcat,linux默認輪詢算法:
除了upstream外,還有很多參數值得注意:
其他配置信息
upstream tomcat {
server 192.168.200.112:8080 max_fails=2 fail_timeout=60s;
server 192.168.200.113:8080;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://tomcat;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream error timeout http_500 http_503;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET,POST,DELETE'; add_header 'Aceess-Control-Allow-Header' 'Content-Type,*';
}
location ~ .*\.(js|css|png|svg|ico|jpg)$ {
valid_referers none blocked 192.168.200.111 www.baidu.com;
if ($invalid_referer) {
return 404;
}
root static-resource;
expires 1d;
}
}
proxy_next_upstream
語法:proxy_next_upstream [error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_404 | off ];
默認:proxy_next_upstream error timeout;
配置塊:http、server、location
這個配置表示當向一臺上有服務器轉發請求出現錯誤的時候,繼續換一臺上後服務器來處理這個請求。
默認情況下,上游服務器一旦開始發送響應數據,Nginx反向代理服務器會立刻把應答包轉發給客戶端。因此,一旦Nginx開始向客戶端發送響應包,如果中途出現錯誤也不允許切換到下一個上有服務器繼續處理的。這樣做的目的是保證客戶端只收到來自同一個上游服務器的應答。
proxy_connect_timeout
語法: proxy_connect_timeout time;
默認: proxy_connect_timeout 60s;
範圍: http, server, location
用於設置nginx與upstream server的連接超時時間,比如我們直接在location中設置proxy_connect_timeout 1ms, 1ms很短,如果無法在指定時間建立連接,就會報錯。
proxy_send_timeout
向後端寫數據的超時時間,兩次寫操作的時間間隔如果大於這個值,也就是過了指定時間後端還沒有收到數據,連接會被關閉
proxy_read_timeout
從後端讀取數據的超時時間,兩次讀取操作的時間間隔如果大於這個值,那麼nginx和後端的鏈接會被關閉,如果一個請求的處理時間比較長,可以把這個值設置得大一些
proxy_upstream_fail_timeout
設置了某一個upstream後端失敗了指定次數(max_fails)後,在fail_timeout時間內不再去請求它,默認爲10秒語法 server address [fail_timeout=30s]
#服務器集羣名字
upstream backend {
#server 192.168.200.112:8080 weight=1 max_fails=2 fail_timeout=600s;
#server 192.168.200.113:8080 weight=1 max_fails=2 fail_timeout=600s;
}
Nginx動靜分離
什麼是動靜分離
必須依賴服務器生存的我們稱爲動。不需要依賴容器的比如css/js或者圖片等,這類就叫靜。
靜態資源的類型
在Nginx的conf目錄下,有一個mime.types文件
mime.types
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng
image/x-ms-bmp
jng;
bmp;
application/font-woff woff; application/java-archive jar war ear; application/json json; application/mac-binhex40 hqx; application/msword doc; application/pdf pdf; application/postscript ps eps ai; application/rtf rtf; application/vnd.apple.mpegurl m3u8; application/vnd.google-earth.kml+xml kml; application/vnd.google-earth.kmz kmz; application/vnd.ms-excel xls; application/vnd.ms-fontobject eot; application/vnd.ms-powerpoint ppt; application/vnd.oasis.opendocument.graphics odg; application/vnd.oasis.opendocument.presentation odp; application/vnd.oasis.opendocument.spreadsheet ods; application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.wap.wmlc wmlc;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream
application/octet-stream
application/octet-stream
application/octet-stream
application/octet-stream
bin exe dll;
deb;
dmg;
iso img;
msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}
用戶訪問一個網站,然後從服務器端獲取相應的資源通過瀏覽器進行解析渲染最後展示給用戶,而服務端可以返回各種類型的內容,比如xml、jpg、png、gif、flash、MP4、html、css等等,那麼瀏覽器就是根據mime-type來決定用什麼形式來展示的
服務器返回的資源給到瀏覽器時,會把媒體類型告知瀏覽器,這個告知的標識就是Content-Type,比如Content-Type:text/html。
演示代碼
接下來,我們對於tomcat首頁的靜態資源進行攔截:
首先在linux1上nginx的配置文件加入:
location ~ .*\.(js|css|png|svg|ico|jpg)$ {
# 將攔截的資源加載到這個自定義目錄下/static-resource
root static-resource;
}
然後在根據配置文件,在當前Linux1的nginx上創建一個靜態資源目錄:
此時爲空,現在將linux2/linux3上tomcat的靜態資源全部剪切到linux1剛纔設置的靜態資源目錄下:
-
刪除tomcat的靜態資源
-
將靜態資源轉移到/static-resource
去服務器看一下靜態資源的完整性,並重啓Nginx:
看看效果:
說明靜態資源已經成功轉移至Nginx的靜態資源目錄,實現了動靜分離
以上靜態資源的分離,是將兩臺tomcat服務器的靜態資源拿到nginx上實現的,同樣的我們可以基於nginx搭建一個靜態資源服務器:
將攔截的靜態資源加載到一臺服務器上
location ~ .*\.(js|css|png|svg|ico|jpg)$ {
valid_referers none blocked 192.168.200.111 www.baidu.com;
if ($invalid_referer) {
return 404;
}
root static-resource;
expires 1d;
}
動靜分離的好處
-
Nginx本身就是一個高性能的靜態web服務器;
-
其實靜態文件有一個特點就是基本上變化不大,所以動靜分離以後我們可以對靜態文件進行緩存、或者壓縮提高網站性能
緩存
當一個客戶端請求web服務器, 請求的內容可以從以下幾個地方獲取:服務器、瀏覽器緩存中或緩存服務器中。這取決於服務器端輸出的頁面信息
瀏覽器緩存將文件保存在客戶端,好的緩存策略可以減少對網絡帶寬的佔用,可以提高訪問速度,提高用戶的體驗,還可以減輕服務器的負擔Nginx緩存配置
Nginx緩存配置
Nginx可以通過expires設置緩存,比如我們可以針對圖片做緩存,因爲圖片這類信息基本上不會改變。
在location中設置expires
格式: expires 30s|m|h|d
location ~ .*.(jpg|jpeg|gif|bmp|png|js|css|ico)$ {
root static;
expires 1d;
}
壓縮
Gzip
我們一個網站一定會包含很多的靜態文件,比如圖片、腳本、樣式等等,而這些css/js可能本身會比較大,那麼在網絡傳輸的時候就會比較慢,從而導致網站的渲染速度。因此Nginx中提供了一種Gzip的壓縮優化手段,可以對後端的文件進行壓縮傳輸,壓縮以後的好處在於能夠降低文件的大小來提高傳輸效率 "
配置信息
Gzip on|off 是否開啓gzip壓縮
Gzip_buffers 4 16k #設置gzip申請內存的大小,作用是按指定大小的倍數申請內存空間。4 16k代表按照原始數據大小以16k爲單位的4倍申請內存。
Gzip_comp_level[1-9] 壓縮級別, 級別越高,壓縮越小,但是會佔用CPU資源
Gzip_disable #正則匹配UA 表示什麼樣的瀏覽器不進行gzip
Gzip_min_length #開始壓縮的最小長度(小於多少就不做壓縮),可以指定單位,比如 1k
Gzip_http_version 1.0|1.1 表示開始壓縮的http協議版本
Gzip_proxied (nginx 做前端代理時啓用該選項,表示無論後端服務器的headers頭返回什麼信息,都無條件啓用壓縮)
Gzip_type text/pliain,application/xml 對那些類型的文件做壓縮 (conf/mime.conf)
Gzip_vary on|off 是否傳輸gzip壓縮標識; 啓用應答頭"Vary: Accept-Encoding";給代理服務器用的,有的瀏覽器支持壓縮,有的不支持,所以避免浪費不支持的也壓縮,所以根據客戶端的HTTP頭來判斷,是否需要壓縮
演示效果
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 60;
include extra/*.conf;
gzip on;
gzip_min_length 5k;
gzip_comp_level 3;
gzip_types application/javascript image/jpeg image/svg+xml;
gzip_buffers 4 32k;
gzip_vary on;
}
在nginx主配置文件加入壓縮配置,我們試驗一下效果:
原來的請求:.svg的文件大小爲26.9kb
重新加載nginx的配置文件:文件大小變爲9.2kb
防盜鏈
一個網站上會有很多的圖片,如果你不希望其他網站直接用你的圖片地址訪問自己的圖片,或者希望對圖片有版權保護。再或者不希望被第三方調用造成服務器的負載以及消耗比較多的流量問題,那麼防盜鏈就是你必須要做的
防盜鏈配置
在Nginx中配置防盜鏈其實很簡單,
語法: valid_referers none | blocked | server_names | string …;
默認值: —
上下文: server, location
“Referer”請求頭爲指定值時,內嵌變量$invalid_referer被設置爲空字符串,否則這個變量會被置成“1”。查找匹配時不區分大小寫,其中none表示缺少referer請求頭、blocked表示請求頭存在,但是它的值被防火牆或者代理服務器刪除、server_names表示referer請求頭包含指定的虛擬主機名
- 配置如下
location ~ .*.(gif|jpg|ico|png|css|svg|js)$ {
valid_referers none blocked 192.168.200.112 www.baidu.com;
if ($invalid_referer) {
return 404;
}
root static;
}
通過這樣配置後,相當於設置了一個白名單,只有linux2和百度的ip是可以訪問靜態資源的,而linux3是不能訪問到的~
需要注意的是僞造一個有效的“Referer”請求頭是相當容易的,因此這個模塊的預期目的不在於徹底地阻止這些非法請求,而是爲了阻止由正常瀏覽器發出的大規模此類請求。還有一點需要注意,即使正常瀏覽器發送的合法請求,也可能沒有“Referer”請求頭。
跨域訪問
什麼叫跨域呢?如果兩個節點的協議、域名、端口、子域名不同,那麼進行的操作都是跨域的,瀏覽器爲了安全問題都是限制跨域訪問,所以跨域其實是瀏覽器本身的限制。
解決辦法
修改proxy_demo.conf配置
server{
listen 80;
server_name localhost;
location / {
proxy_pass http://192.168.200.111:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_connect_timeout 60s;
add_header 'Access-Control-Allow-Origin' '*'; // 允許來自所有的訪問地址
add_header 'Access-Control-Allow-Methods' 'GET,PUT,POST,DELETE,OPTIONS'; //支持的請求方式
add_header 'Access-Control-Allow-Header' 'Content-Type,*'; //支持的媒體類型
}
location ~ .*\.(gif|jpg|ico|png|css|svg|js)$ {
root static;
}
}
後記
更多架構知識,歡迎關注本套Java系列文章:Java架構師成長之路