利用 NGINX 在多個服務實例中作負載均衡是 NGINX 最經常使用的場景之一。在將咱們如今作的產品放到公司的 AWS 上的時候,我接觸到了這些,而且修改了 CI team 的部分 NGINX 配置,讓它可以正確地完成反向代理的工做。算法
在作負載均衡前,咱們首先須要定義一個 Server 組用來表示全部存在的後臺服務:json
http {
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
server 192.0.0.1 backup;
}
}
複製代碼
而後,咱們須要把流量重定向到上一步定義的 backend 上去, 咱們能夠經過指定 proxy_pass 的值來完成這一操做:後端
upstream backend {
server backend1.example.com;
server backend2.example.com;
server 192.0.0.1 backup;
}
server {
location / {
proxy_pass http://backend;
}
}
}
複製代碼
這裏咱們將全部的流量重定向到 http://backend , 這將這個 NGINX 實例上的全部流量重定向到以前定義的 backend 上去。服務器
當沒有指定任何信息時, NGINX 默認使用了 Round Robin(輪詢)算法來重定向流量。其實 NGINX 提供了多種算法來作負載均衡,下面咱們來介紹一下:負載均衡
在沒有指定 weight(權重) 的狀況下,Round Robin 會將全部請求均勻地分發給全部後臺服務實例:dom
upstream backend {
server backend1.example.com;
server backend2.example.com;
}
複製代碼
這裏咱們沒有指定權重,因此兩個後臺服務會收到等量的請求。可是,當指定了權重以後,NGINX 就會將權重考慮在內:函數
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com;
}
複製代碼
在 NGINX 中,weight 默認被設置爲 1。這裏咱們用一開始的配置舉例, backend1.example.com 的權重被設置爲 5,另外一個的權重沒設置,因此是默認值 1。咱們也沒有設置輪詢算法,因此這時候 NGINX 會以 5:1 的比例轉發請求,即 6 個請求中, 5 個被放到了 backend1.example.com 上, 有一個被髮到了 backend2.example.com 上。url
在這個模式下,一個請求會被 NGINX 轉發到當前活躍請求數量最少的服務實例上:spa
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
}
複製代碼
咱們用 least_conn 來指定最少鏈接優先算法, NGINX 會優先轉發請求到現有鏈接數少的那一個服務實例上。代理
在 IP Hash 模式下,NGINX 會根據發送請求的 IP 地址的 hash 值來決定將這個請求轉發給哪一個後端服務實例。被 hash 的 IP 地址要麼是 IPv4 地址的前三個 16 進制數或者是整個 IPv6 地址。使用這個模式的負載均衡模式能夠保證來自同一個 IP 的請求被轉發到同一個服務實例上。固然,這種方法在某一個後端實例發生故障時候會致使一些節點的訪問出現問題。
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
}
複製代碼
若是某一臺服務器出現故障或者沒法進行服務,咱們能夠給它標記上 down,這樣以前被轉發到這臺服務器上的請求就會從新進行 hash 計算並轉發到新的服務實例上:
upstream backend {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
}
複製代碼
這個模式容許管理員自定義 hash 函數的輸入,好比:
upstream backend {
hash $reqeust_uri consistent;
server backend1.example.com;
server backend2.example.com;
}
複製代碼
在這個例子中,咱們以請求中所帶的 url 爲 hash 的輸入。 注意到這裏在 hash 那一行的最後加入了 consistent 這個關鍵詞。這個關鍵詞會使用一種新的 hash 算法 ketama, 該算法會讓管理員添加或刪除某個服務實例的時候,只有一小部分的請求會被轉發到與以前不一樣的服務實例上去,其餘請求仍然會被轉發到原有的服務實例上去。
顧名思義,每一個請求都被隨機發送到某個服務實例上去:
upstream backend {
random;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
server backend4.example.com;
}
複製代碼
Random 模式還提供了一個參數 two,當這個參數被指定時,NGINX 會先隨機地選擇兩個服務器(考慮 weight),而後用如下幾種方法選擇其中的一個服務器:
1. `least_conn`: 最少鏈接數
2. `least_time=header(NGINX PLUS only)`: 接收到 response header 的最短平均時間
3. `least_time=last_byte(NGINX PLUS only)`: 接收到完整請求的最短平均時間
複製代碼
咱們能夠參考下面的一個例子:
upstream backend {
random two least_time=last_byte;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
server backend4.example.com;
}
複製代碼
當環境中有多個負載均衡服務器在向後端服務轉發請求時,咱們能夠考慮使用 Random 模式,在只有單個負載均衡服務器時,通常不建議使用 Random 模式。
這是一個 NGINX PLUS (NGINX 的付費版) 纔有的模式,能夠將請求優先轉發給平均響應時間較短的服務實例,它也有三個模式:
1. `header`: 從服務器接收到第一個字節的時間
2. `last_byte`: 從服務器接收到完整的 response 的時間
3. `last_byte inflight`: 從服務器接收到完整地 response 的時間(考慮不完整的請求)
複製代碼
例子以下:
upstream backend {
least_time header;
server backend1.example.com;
server backend2.example.com;
}
複製代碼
NGINX 提供了多種負載均衡模式,在實際使用中,須要根據實際業務需求去作嘗試,分析日誌來找到最適合當前場景的複雜均衡模式。