按部就班nginx(二):反向代理、負載均衡、緩存服務、靜態資源訪問


前置知識章節:
1.介紹、安裝、hello world、location匹配
2.▶▶反向代理、負載均衡、緩存服務、靜態資源訪問✅
3.日誌管理、http限流、https配置,http_rewrite模塊,第三方模塊安裝,結語。✅html


反向代理


💡代理有正向代理和反向代理
💡正向代理:
所謂的正向,就是以請求發起爲角度的,此時代理的是用戶發起的請求。
用戶A沒法訪問G網,但A能訪問B網,而B網能訪問G網。那麼若是A先經過訪問B網,B網幫他訪問G網,返回數據給他,那麼此時B網就做爲了一個代理服務器,並且是正向代理。此時A實際上是知道它要訪問G網的,G網並不知道是A訪問它的,因此此時是代理了A,正向代理。前端

💡反向代理:
相對於正向代理的代理用戶發起的請求,反向代理代理的是資源服務器的請求。
用戶A訪問B網的某個資源,但B網沒有,而後它發給C網,C網返回給B網,B網返回給C網。此時用戶A不知道它訪問的是C網,因此此時代理的是C網,反向代理。
場景通常是,A能訪問B,但不能訪問C,B能訪問C。咱們使用B這臺機來對外提供服務,讓關於C的請求都先通過B,B再請求C來返回結果。
反向代理有時候用在內網中,用來作請求轉發到內網,這樣必定程度的保護了內網的資源和利用上了內網的服務器。固然對於咱們業務來講,服務器有可能並非部署在內網中的,也能夠用在外網服務器代理上。java

💡反向代理是一個很是重要的功能,能夠說nginx你最經常使用的功能或許就是反向代理了,動靜分離、負載均衡和緩存有時候你可能用不上。nginx


使用

1.建立代理目標服務端:

咱們首先須要建立一個web服務端,因爲我是主攻java的,因此我這裏部署一個java的web服務器,並讓他監聽8081端口。(192.168.48.131是個人虛擬機的IP,nginx和這個java web服務端都部署在這裏。)
20200614012418
訪問一下這個要被代理的服務端的接口http://192.168.48.131:8081/user/list,發現調用成功。
20200614001834git


2.配置nginx反向代理目標服務端:

💡2.1 修改server:
由於此時是做爲一個代理服務器,因此咱們要新建一個server塊來充當代理服務器。


❓有人有點疑惑,上面的例子只配了location,咱們爲何要配server呢?
其實這裏是從業務需求來作區分的。由於咱們如今的目標是弄一個代理服務器,固然了你也能夠不建立,而後把下面的location放到以前的server下便可。何時是必須建立的呢?當server_name不同的時候,但這個也是須要你根據業務來判斷的,好比你本來使用80端口接收發過來的請求,而如今使用8080端口接收發過來的請求的時候就須要一個新的server_name。
這裏新建一個server其實也有介紹server_name的用法的意思。github


修改server_name:server_name是當前服務端監聽的地址的意思,
server_name支持幾種語法:web

  • 基於確切的域名,域名能夠一個或多個,多個使用空格隔開server_name example.com www.example.com
  • 支持通配符的方式,通配符*只能使用在開頭或者結尾,不能使用在中間。當有多個匹配結果的時候,會選擇最長的匹配結果server_name *.example.com www.example.*
  • 基於正則表達式,當使用正則表達式的時候,開頭必須加上一個~server_name ~^www\d+\.example\.com$;
  • 正則表達式支持<>來獲取一個變量到後面使用以實現二級域名的功能,這裏不講,有興趣自查。
  • 上面幾個語法的優先級是:
    • 精確域名 > 通配符在前 > 通配符在後 > 正則表達式

💡2.2 修改location
🔵proxy_pass用於設置被代理服務器的地址,能夠是主機名稱(https://www.baidu.com這樣的)、IP地址(域名加端口號)的形式。
🔵下面的這個location的意思是,若是請求路徑開頭是/api的,那麼都代理到proxy_pass指定的地址,好比訪問了/api/user/list,那麼獲得的結果是http://localhost:8081/user/list的結果。正則表達式

server {
  listen 8080;

  location /api/ {
    proxy_pass http://localhost:8081/;
  }
}

🔵在lcoation都是location /api/時,proxy_pass不一樣,請求的資源也是不同的:redis

  • proxy_pass http://localhost:8081;:請求nginx主機IP:8080/api/user/list,nginx會將該請求代理轉發到http://locahost:8081/api/user/list
  • proxy_pass http://localhost:8081/;:請求nginx主機IP:8080/api/user/list,nginx會將該請求代理轉發到http://locahost:8081/user/list
  • proxy_pass http://localhost:8081/test;請求nginx主機IP:8080/api/user/list,nginx會將該請求代理轉發到http://locahost:8081/testuser/list
  • proxy_pass http://localhost:8081/test/;請求nginx主機IP:8080/api/user/list,nginx會將該請求代理轉發到http://locahost:8081/test/user/list


3.測試使用:

在前面,我建立了一個8081的web服務端,並且http://nginx服務器IP:8081/user/list是有一個接口的.
20200614001834
咱們試一下使用8080來代理一下這個8081這個服務端:
注意下面的這個server若是寫在default.conf的時候,是與其它server塊同級的
20200614002940後端

若是咱們可以經過8080來訪問到http://192.168.48.131:8081/user/list這個接口,那麼就說明了咱們的反向代理成功了。此時發向8080端口的,以/api開頭的請求都會代理到8081中。

20200614003048


## 其餘反向代理指令 下面的其餘反向代理指令我解釋了一下用途,有須要就本身去了解一下吧。 * proxy_set_header:在將客戶端請求發送給後端服務器以前,更改來自客戶端的請求頭信息。 * proxy_connect_timout:配置nginx與後端服務器嘗試創建鏈接的超時時間。 * proxy_read_timeout:定義用於從代理服務器讀取響應的超時。 * proxy_send_timeout:設置用於將請求傳輸到代理服務器的超時。 * proxy_redirect:用於修改後端服務器返回的響應頭中的Location和Refresh。[proxy_redirect](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect)

負載均衡

負載均衡其實也算是基於反向代理的。

上面的反向代理提到一點反向代理能夠爲咱們的服務端進行代理,你有時候多是多個服務端提供同一功能的,爲了讓他們可以平攤壓力,那麼你可能須要負載均衡功能。


使用

1.準備服務端

🔴準備負載均衡用的業務服務端,我這裏給的是一個java Spring Boot端的簡單代碼,我部署成多個服務端的時候,因爲端口不一樣,訪問info接口返回的數據也不一樣,這樣就能夠測試是否達到了負載均衡。
20200615152747

🔴部署服務端,使用--server.port來部署到不一樣的端口,例如java -jar a-simple-web-0.0.2-SNAPSHOT.jar --server.port=8082就把個人jar程序部署到了8082端口。



2.修改nginx配置

咱們這裏新建一個conf.d/loadbalance.conf,因爲nginx.conf內部有一個include /etc/nginx/conf.d/*.conf;能夠把conf.d下的配置文件都導入到nginx.conf的http塊中,因此咱們新建的這個conf也是能夠導入到nginx.conf中的。
20200615155759



3.測試

訪問http://192.168.31.128:9001/user/info,看是不是輪詢的分發請求,若是響應的時候返回了不一樣的端口,那麼就證實了是輪詢的分發請求。



負載均衡策略

💡默認輪詢負載均衡:在不指定負載均衡策略的時候,默認的策略是按順序給負載均衡服務端發送請求,而且一次順序中每一個服務端處理兩次請求,好比兩個服務端,那麼就是AABBAABB這樣循環下去。 若是服務端有宕機的,會從負載均衡順序中去除。等到宕機的服務端可用後,會在30S(好像是)以後加入到可用負載均衡服務端列表中。


💡加權輪詢負載均衡:在輪詢的基礎上加上權重的考慮,假如服務端A的權重是1,服務端B的權重是2,那麼6個請求中,服務端A會收到2個請求,服務端B會收到4個請求。
20200615155954


💡ip_hash負載均衡:每一個請求按ip的哈希結果分配到指定的負載服務端響應,(原理相似求餘數,把服務端排序以後,根據哈希處理再處理以後獲得的餘數來選取服務端),這樣同一個ip響應的服務端是固定的。能夠在必定程度解決服務端Session共享的問題。但這樣可能負載壓力就分配的不平均了。
語法例子:

upstream ip-hash {
  ip_hash;
  server localhost:8081;
  server localhost:8082;
}

💡也可使用第三方模塊來負載均衡。但因爲咱們上面沒有講過第三方模塊,引入前置知識須要佔用大量篇幅,因此這裏只引出一下,有須要的自查吧。

  • 第三方模塊fair:能夠基於響應時間分配請求,優先分配到響應時間短的服務端上。
  • 第三方模塊url_hash:能夠基於url的hash結果來分配請求。


負載均衡的額外參數

上面介紹了使用weight參數來實現加權輪詢負載均衡,其實還有一些其餘的參數。

  • max_fails:容許請求失敗的次數。默認值是1。
  • fail_timeout:從新檢測服務的時間,當服務端請求失敗後,會在fail_timeout時間內標記成不可用,fail_timeout時間以後再次檢測是否可用,不行就再等fail_timeout時間以後再次檢測是否可用。默認是10S.
  • backup:預留的備份服務端。只有當其餘服務端都宕機或者處於忙碌狀態時,纔會分發請求給backuo標註的服務端。
  • down:暫時不參與負載均衡的服務端,只有其餘服務端都宕機的時候,這個服務端才參與負載均衡。
  • max_conns:限制接收的最大的鏈接數。
upstream web-server {
  server localhost:8081 max_fails=1 fail_timeout=10;
  server localhost:8082;
  server localhost:8083 backup;
  server localhost:8084 down;
}

💡使用ip_hash時,不能使用weight和backup。




緩存服務


💡在瀏覽器訪問某個網站的資源的時候,會看瀏覽器是否緩存了這個數據。若是本地有這個緩存數據,那麼就會直接從本地中獲取了,不會再請求網絡了。這是客戶端緩存。nginx傳遞的響應的某些數據會影響瀏覽器是否緩存數據以及緩存多久。
💡除了客戶端緩存,還有一種代理緩存nginx的緩存是代理緩存,由於它實際上是將代理的服務端的結果緩存了。代理緩存使用ngx_http_proxy_module的指令來配置。
💡(除了這兩種,還有(後端)服務端緩存,也就是使用redis等技術進行的後端服務端緩存。)。


代理緩存

語法介紹

💡proxy_cache_path path:用來定義緩存文件路徑。只能用在http塊。
語法:

proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
  • path是緩存文件存放路徑
  • levels用於定義文件存放層級,能夠有一層(1),兩層(1:2),三層(1:2:2)。目錄會根據請求URL地址的哈希結果來建立(從末尾開始截取,),假如哈希結果是9cad383e7b0ee3d1d4b7099aace20b3f,那麼levels=1:2表明第一層目錄爲長度爲一的字符f,第二層是長度爲2的字符b3
  • keys_zone用來定義當前這個緩存存放空間的名字,10m是一個大小
  • max_size用來定義目錄最大的大小。
  • inactive用來定義不活躍的緩存多久清除。
  • use_temp_path:緩存臨時目錄。通常能夠不定義。


💡proxy_cache zone|off:能夠用在http, server, location。zone是proxy_cache_path的keys_zone.
💡proxy_cache_valid [code...] time:緩存過時週期,過時以後就不返回代理緩存了。 code是http狀態碼。
💡proxy_cache_key string:配置緩存的標識,好比說請求不同的話那確定不返回一樣的代理緩存了,這就是是否返回同一個緩存的區分標識。默認值是proxy_cache_key $scheme$proxy_host$request_uri;,能夠用在http, server, location。其餘例子:proxy_cache_key $scheme$proxy_host$uri$args;



使用例子

下面來作一個實驗:嘗試使用nginx的代理緩存做爲代理的響應。


1.咱們新建一個後端接口。這個後端接口能在每一次訪問的時候都在控制檯打印出一個消息(下面是一個Spring Boot例子):
20200622222735
2.配置反向代理:
20200622223500

3.一開始先測試一下http://192.168.31.128/api/user/info,看每一次訪問是否都向後端發起了請求,確實是每一次都發請求的:
20200622223617

4.而後配置代理緩存:
20200626003102

5.再次測試訪問http://192.168.31.128/api/user/info是否每一次訪問都向後端發起了請求,結果應該是後端服務端只會打出一次,或者你能夠嘗試關閉後端服務端,而後訪問,若是仍是可以訪問,那麼應該是已經代理緩存成功了。



代理緩存補充:

💡永久緩存:上面使用proxy_cache配置的實際上是臨時緩存。也就是說必定時間後會自動過時。若是你的數據在很長很長時間都不會過時,那麼能夠考慮使用proxy_store.
💡若是你想讓部分請求不要緩存,可使用proxy_no_cache [string...],string能夠是變量,若是存在某個string值不爲空也不爲0,那麼此請求不會被緩存。
💡緩存清理:incative配置會幫咱們清除過時的緩存文件,但還沒過時的不會清除,須要咱們手動清除(場景是好比說你更新了大量數據,此時緩存中的數據不少都錯誤了,此時須要清除全部緩存。),若是你須要清除的話,那麼一種方法是手動定義一個Linux腳原本清除緩存;一種方法是使用模塊nginx-cache-purge。這些因爲篇幅問題,不講述。



瀏覽器緩存

瀏覽器是怎麼判斷緩存是否須要使用本地緩存以及緩存是否過時的呢?它經過響應頭中的expirecache-controlLast-ModifiedEtag等頭信息來判斷的。


  • 用於本地校驗是否過時的頭:expireCache-control(max-age),若是有本地緩存,那麼會使用expire來判斷是否過時,不過時,直接使用本地緩存,本地過時以後,再進行遠程校驗。
  • 用於遠程校驗的Last-Modified頭信息:用於遠程文件修改校驗的,是一個GMT時間,例如Thu, 02 Jul 2020 01:05:03 GMT,若是校驗時間不一致,那麼不使用本地緩存,一致則使用本地緩存。
  • 用於遠程校驗的的Etag頭信息:用於遠程文件修改校驗的,是一個類時間戳的數據,例如:"5efd32bf-3fa8e",若是校驗時間不一致,那麼不使用本地緩存,一致則使用本地緩存。Etag與Last-Modified的區別是,Etag更精確,因此會優先判斷Etag,而後再判斷Last-Modified。
  • 相關nginx模塊:ngx_http_headers_module

❗瀏覽器緩存機制你能夠本身瞭解一下:博客園-HTTP緩存機制


💡Expire

  • 語法:expires [modified] time;
    • modified用於執行修改後過時,好比expires modified +24h;就表明修改後24小時內不過時。
    • time:過時時間,例若有expires 24h;24天不過時,expires 30d;30天不過時,expires -1;表明永不過時

測試

測試以前咱們先要提幾點:

  • 瀏覽器有默認的緩存策略,Etag和Last-Modified默認是自帶的,會有基於對文件修改的緩存,第一次響應200以後,第二次響應爲304的時候,瀏覽器仍是會發請求,但此時發請求用於測試文件是否過時,不過時則不會傳輸文件
  • 當配置了expires的時候怎麼判斷它生效了呢?響應碼爲200,而且不對nginx發起請求。
  • expires並不會在任何狀況都生效,好比說F5刷新Ctrl+F5刷新就無效,此時測試應該使用在連接欄按回車發請求來測試。expires可用於什麼狀況能夠參考博客園-HTTP緩存機制

1.咱們先在/usr/share/nginx/html下面存儲一張圖片,後面會經過訪問這種圖片,來測試客戶端緩存。


2.咱們一開始先不要配置expires:

server {
    listen       80;
    server_name  127.0.0.1;
    location / {
      root /usr/share/nginx/html;
    }
}

3.屢次訪問一下http://192.168.31.128/a.jpg看看nginx的訪問日誌/var/log/nginx/access.log是否有添加
此時要多留意每次請求的響應碼,應當有如下幾個狀況:

  • 若是你使用F5刷新,那麼第一次響應碼爲200,後面都是304,第一個響應碼爲200的時候用於獲取文件,後面的304會檢查文件是否修改,不修改則使用緩存的文件,此時每次刷新都應該發了一次請求,access.log中能夠觀察到。
  • 若是你使用在連接欄按回車發請求來測試,那麼響應碼應當都是200,是每一次都會去請求文件,此時每次按回車都應該發了一次請求,access.log中能夠觀察到。

4.加了expires以後看看,咱們簡單的使用兩分鐘看看。

server {
    listen       80;
    server_name  127.0.0.1;
    location / {
      expires 2m;
      root /usr/share/nginx/html;
    }
}

5.屢次訪問一下http://192.168.31.128/a.jpg看看nginx的訪問日誌是否有添加

  • 若是你使用F5刷新,因爲expires不會在F5刷新時生效,因此效果應該和未配置以前是同樣的。
  • 若是你使用在連接欄按回車發請求來測試,那麼一開始響應碼應當都是200但不會真正的發起請求,而是使用緩存中的數據,access.log中不會看到請求。(由於我上面定義緩存是兩分鐘)兩分鐘以後第一次請求是304,用於校驗文件是否修改,若是沒修改,那麼後面的兩分鐘以內的響應又是不發請求的200。


靜態資源訪問

💡nginx能夠對外接收靜態資源訪問的請求。

💡在上面的location的內容的時候,其實有講到返回文件資源的知識。
好比location ~* \.(gif|jpg|jpeg)$匹配任何以.gif、.jpg 或 .jpeg 結尾的請求,而後你發的請求匹配成功的時候,會使用root+location獲得的路徑的資源做爲響應。其實這些也就是靜態資源了,因此其實也能夠經過nginx來達到靜態資源的訪問。

💡在先後端分離以後,前端做爲靜態資源訪問,應該部署到哪裏呢?由於咱們此時是不該該把前端靜態資源部署到後端服務器上的。那麼這時候放到nginx服務端上也是能夠的。利用nginx的靜態資源訪問做爲前端的服務端。

💡或者你也能夠把nginx做爲文件資源訪問的服務端。

相關文章
相關標籤/搜索