《前端運維》二、Nginx--4代理、負載均衡與其他

Zaking發表於2022-03-25

一、代理服務

  比較容易理解吧,簡單來說。客戶端訪問伺服器並不是直接訪問的,而是通過中間代理伺服器,代理伺服器再去訪問伺服器。就像一箇中轉站一樣,無論什麼,只要從客戶端到伺服器,你就要通過我。

一)正向代理

  正向代理,就是代理伺服器為客戶端代理,也就是說,伺服器並不知道真實的客戶端是誰,而是通過代理伺服器把請求傳送給真實的伺服器。比如,通過公司網路訪問外網百度,那麼公司的代理伺服器就會代理你的主機,訪問百度網站。百度伺服器無法獲得你個人的真實主機ip。

  就像上圖展示的那樣。web1、web2就是你在公司內的個人主機ip,然後通過公司的nginx代理伺服器,訪問外部網路。

語法:

Syntax: proxy_pass URL
Default: --
Context: server,location

實踐:

  刪除之前的配置,然後我們加下正向代理的配置:

resolver 8.8.8.8; #谷歌的域名解析地址
location / {
    # $http_host 要訪問的主機名 $request_uri請求路徑
    proxy_pass http://$http_host$request_uri;
}

  這樣,nginx的正向代理配置其實就ok了,哦對,別忘了過載nginx伺服器。為了我們可以用本地測試,還需要一些額外的修改。Windows系統,修改下本機的hosts檔案,地址在:C:\Windows\System32\drivers\etc。裡面有個hosts,通過編輯器開啟,新增如下內容:

ip(你伺服器的ip)(空格)域名(隨便一個域名)

  我的新增完了之後是這樣的:

 

   然後,你可以正常訪問百度,或者其他域名地址,或者也可以通過curl來訪問。但是這樣我們實際上比較無感,所以我們來看下nginx日誌,日誌在/var/log/nginx/access.log中。

二)反向代理

  反向代理,簡單來說就是代理伺服器代理的是伺服器,客戶端並不知道真正的伺服器是什麼。

nginx配置如下:

location ~ ^/api {
    proxy_pass http://localhost:3000;
    proxy_redirect default; #重定向

    proxy_set_header Host $http_host;        #向後傳遞頭資訊
    proxy_set_header X-Real-IP $remote_addr; #把真實IP傳給應用伺服器

    proxy_connect_timeout 30; #預設超時時間
    proxy_send_timeout 60;    # 傳送超時
    proxy_read_timeout 60;    # 讀取超時


    proxy_buffering on;             # 在proxy_buffering 開啟的情況下,Nginx將會盡可能的讀取所有的upstream端傳輸的資料到buffer,直到proxy_buffers設定的所有buffer們 被寫滿或者資料被讀取完(EOF)
    proxy_buffers 4 128k;           # proxy_buffers由緩衝區數量和緩衝區大小組成的。總的大小為number*size
    proxy_busy_buffers_size 256k;   # proxy_busy_buffers_size不是獨立的空間,他是proxy_buffers和proxy_buffer_size的一部分。nginx會在沒有完全讀完後端響應的時候就開始向客戶端傳送資料,所以它會劃出一部分緩衝區來專門向客戶端傳送資料(這部分的大小是由proxy_busy_buffers_size來控制的,建議為proxy_buffers中單個緩衝區大小的2倍),然後它繼續從後端取資料,緩衝區滿了之後就寫到磁碟的臨時檔案中。
    proxy_buffer_size 32k;          # 用來儲存upstream端response的header
    proxy_max_temp_file_size 256k; # response的內容很大的 話,Nginx會接收並把他們寫入到temp_file裡去,大小由proxy_max_temp_file_size控制。如果busy的buffer 傳輸完了會從temp_file裡面接著讀資料,直到傳輸完畢。
}

  然後需要我們在伺服器上安裝一下node,簡單來說通過下載node官網的linux版node的二進位制包,通過ftp傳輸到伺服器。然後解壓縮node包,然後配置node環境變數即可。這個就不多說了,大家可以百度一下。

  然後我們在伺服器新建一個node的http服務,埠號3000、4000、5000,對,建立三個檔案。是在伺服器上哦,實際上跟在本地沒啥區別。

  然後我們通過瀏覽器,你的ip/api/xxx就可以代理到3000埠的服務了。哦對,別忘了在伺服器啟動你的node服務。

二、負載均衡

  我們先來看張圖吧:

  

  使用叢集是網站解決高併發、海量資料問題的常用手段。當一臺伺服器的處理能力、儲存空間不足時,不要企圖去換更強大的伺服器,對大型網站而言,不管多麼強大的伺服器,都滿足不了網站持續增長的業務需求。這種情況下,更恰當的做法是增加一臺伺服器分擔原有伺服器的訪問及儲存壓力。通過負載均衡排程伺服器,將來自瀏覽器的訪問請求分發到應用伺服器叢集中的任何一臺伺服器上,如果有更多的使用者,就在叢集中加入更多的應用伺服器,使應用伺服器的負載壓力不再成為整個網站的瓶頸。

  那麼下面,我們來看下,如何通過nginx伺服器,配置叢集。首先,我們需要在nginx伺服器,同過不同的埠號,建立幾個node服務。node服務的程式碼類似這樣:

var http = require( 'http' );
var server =http.createServer( function ( request ,response ){
    response.end('server3 000');
} );
server.listen( 3000 ,function(){
console.log( 'HTTP伺服器啟動中,埠:3000' );
});

  然後,nginx中可以這樣配置:

http{
upstream zhufeng {
    server 127.0.0.1:3000 weight=10;
    server 127.0.0.1:4000;
    server 127.0.0.1:5000;
}

server {
        location / {
            proxy_pass http://zhufeng;
        }
    }
}

  然後呢,安裝一下pm2:

yum install pm2 -g

  如果太慢的話,可以試試淘寶源。這裡就不說怎麼配置了哦。然後安裝好pm2後,通過pm2啟動各個node服務。pm2是一個node應用的程式管理器。

  然後,可以通過以下命令來啟動和檢視node服務程式:

# 啟動node服務
pm2 start xxx.js name xxx
# 檢視當前服務
pm2 list

後端伺服器除錯狀態:

狀態描述
down 當前的伺服器不參與負載均衡
backup 當其它節點都無法使用時的備份的伺服器
max_fails 允許請求失敗的次數,到達最大次數就會休眠
fail_timeout 經過max_fails失敗後,服務暫停的時間,預設10秒
max_conns 限制每個server最大的接收的連線數,效能高的伺服器可以連線數多一些

例子:

upstream webserver{
  server localhost:3000 down;
  server localhost:4000 backup;
  server localhost:5000 max_fails=1 fail_timeout=10s;
}

分配方式:

型別種類
輪詢(預設) 每個請求按時間順序逐一分配到不同的後端伺服器,如果後端伺服器down掉,能自動剔除
weight(加權輪詢) 指定輪詢機率,weight和訪問比率成正比,用於後端伺服器效能不均的情況
ip_hash 每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個後端伺服器,可以解決session的問題
least_conn 哪個機器上連線數少就分發給誰
url_hash(第三方) 按訪問的URL地址來分配 請求,每個URL都定向到同一個後端 伺服器上(快取)
fair(第三方) 按後端伺服器的響應時間來分配請求,響應時間短的優先分配
正定義hash hash自定義key

例子:

upstream webserver{
  ip_hash;
  server 127.0.0.1:3000;
}
upstream webserver{
  least_conn;
  server 127.0.0.1:3000;
}
upstream webserver{
  url_hash;
  server 127.0.0.1:3000;
}
upstream webserver{
  fair;
  server 127.0.0.1:3000;
}
upstream webserver{
  hash $request_uri;
  server 127.0.0.1:3000;
}

三、其他

一)快取

  首先啊,快取有很多種,比如之前學過的瀏覽器快取,還有應用伺服器快取,代理快取,客戶端快取等等等等。我們可以在nginx中使用prxoy_cache來設定代理快取。

http{  
    # 快取路徑 目錄層級 快取空間名稱和大小 失效時間為7天 最大容量為10g
    proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=cache:100m inactive=60m max_size=10g;  
}  

  稍微複雜點的方式如下:

    if ($request_uri ~ ^/cache/(login|logout)) {
      set $nocache 1;
    }
    location / {
       proxy_pass http://webserver;
    }
    location ~ ^/cache/ {
     proxy_cache cache;
     proxy_cache_valid  200 206 304 301 302 60m;   # 對哪些狀態碼快取,過期時間為60分鐘
     proxy_cache_key $uri;  #快取的維度
     proxy_no_cache $nocache;
     proxy_set_header Host $host:$server_port;  #設定頭
     proxy_set_header X-Real-IP $remote_addr;   #設定頭
     proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;   #設定頭
     proxy_pass http://127.0.0.1:6000;
    }

  然後呢,上面的各個欄位的含義如下:

鍵值含義
proxy_cache 使用名為cache的對應快取配置
proxy_cache_valid 200 206 304 301 302 10d; 對httpcode為200的快取10天
proxy_cache_key $uri 定義快取唯一key,通過唯一key來進行hash存取
proxy_set_header 自定義http header頭,用於傳送給後端真實伺服器
proxy_pass 指代理後轉發的路徑,注意是否需要最後的/

二)location

  它的使用其實就是正規表示式,但是語法規則會有些特性,正則我就不在這裡多說,我們們直接看下location的語法:

  • location僅匹配URI,忽略引數
  • 字首字串
    • 常規
    • = 精確匹配
    • ^~ 匹配上後則不再進行正規表示式的匹配
  • 正規表示式
    • ~ 大小寫敏感的正規表示式匹配
    • ~*忽略大小寫的正規表示式匹配
  • 內部調轉
    • 用於內部跳轉的命名location @
Syntax location [=|~|~*|^~] uri {...}
       location @name{...}
default -
Context server,location    

  匹配的優先順序,按照上面的順序,從上到下,最上面的優先順序最高,我們來看個實際的例子:

location ~ /T1/$ {
    return 200 '匹配到第一個正規表示式';
}
location ~* /T1/(\w+)$ {
    return 200 '匹配到最長的正規表示式';
}
location ^~ /T1/ {
    return 200 '停止後續的正規表示式匹配';
}
location  /T1/T2 {
    return 200 '最長的字首表示式匹配';
}
location  /T1 {
    return 200 '字首表示式匹配';
}
location = /T1 {
    return 200 '精確匹配';
}
/T1     // 精確匹配
/T1/    // 停止後續的正規表示式匹配
/T1/T2  // 匹配到最長的正規表示式
/T1/T2/ // 最長的字首表示式匹配
/t1/T2  // 匹配到最長的正規表示式

 

三)rewrite

  可以實現URI的重寫和重定向,它的用處有很多,常用於URL頁面的跳轉,相容舊版本,SEO優化(偽靜態),維護(後臺維護、流量轉發),安全(偽靜態)等,它的語法是這樣的:

syntax: rewrite regex replacement [flag]
Default: —
Context: server, location, if
  • 如果正規表示式(regex)匹配到了請求的URI(request URI),這個URI會被後面的replacement替換
  • rewrite的定向會根據他們在配置檔案中出現的順序依次執行
  • 通過使用flag可以終止定向後進一步的處理

  一個例子:

rewrite ^/users/(.*)$ /show?user=$1? last;=

  flag,標誌位是標識規則對應的型別。

flag含義
last 先匹配自己的location,然後通過rewrite規則新建一個請求再次請求服務端
break 先匹配自己的location,然後生命週期會在當前的location結束,不再進行後續的匹配
redirect 返回302昨時重定向,以後還會請求這個伺服器
permanent 返回301永久重定向,以後會直接請求永久重定向後的域名

1)last

  • 結束當前的請求處理,用替換後的URI重新匹配location
  • 可理解為重寫(rewrite)後,發起了一個新請求,進入server模組,匹配location
  • 如果重新匹配迴圈的次數超過10次,nginx會返回500錯誤
  • 返回302 http狀態碼
  • 瀏覽器位址列顯示重定向後的url

2)break

  • 結束當前的請求處理,使用當前資源,不再執行location裡餘下的語句
  • 返回302 http狀態碼
  • 瀏覽器位址列顯示重定向後的url

3)redirect

  • 臨時跳轉,返回302 http狀態碼
  • 0瀏覽器位址列顯示重地向後的url

4)permanent

  • 永久跳轉,返回301 http狀態碼;
  • 瀏覽器位址列顯示重定向後的url

  例子如下:

location ~ ^/break {
    rewrite ^/break /test break;
    root /data/html;
}

location ~ ^/last {
    rewrite ^/last /test last;
}

location /test {
      default_type application/json;
      return 200 '{"code":0,"msg":"success"}';
}

location ~ ^/redirect {
 rewrite ^/redirect http://www.baidu.com redirect;
}
location ~ ^/permanent {
 rewrite ^/permanent http://www.baidu.com permanent;
}

  可以通過curl來測試一下:

curl http://115.29.148.6/break
test
curl http://115.29.148.6/last
{"code":0,"msg":"success"}
curl -vL http://115.29.148.6/redirect
curl -vL http://115.29.148.6/permanent

 

相關文章