nginx 負載均衡相關知識

Nginx ("engine x") 是一個高性能的 HTTP 和 反向代理 服務器,也是一個 IMAP/POP3/SMTP 代理服務器。 Nginx 是由 Igor Sysoev 爲俄羅斯訪問量第二的 Rambler.ru 站點開發的,第一個公開版本0.1.0發佈於2004年10月4日。其將源代碼以類BSD許可證的形式發佈,因它的穩定性、豐富的功能集、示例配置文件和低系統資源的消耗而聞名。php

nginx也能夠作web站點,不過更多狀況下,nginx都是做爲負載均衡服務器來使用的。負載均衡簡單的分流相似以下圖:css

2012823231838734

nginx的upstream模塊,主要完成網絡數據的接收、處理和轉發,是作負載均衡的關鍵。下面介紹幾種常見的負載分配算法。html

 

Nginx的幾種常見負載分配算法

輪詢(round-robin 默認)

     默認狀況下,Nginx 會爲你提供輪詢做爲負載均衡策略。即每臺服務器的權重是同樣的。每一個請求按時間順序逐一分配到不一樣的後端服務器,若是後端服務器down掉,能自動剔除。 nginx

輪詢調度算法(Round-Robin Scheduling)
輪詢調度算法的原理是每一次把來自用戶的請求輪流分配給內部中的服務器,從1開始,直到N(內部服務器個數),而後從新開始循環。
算法的優勢是其簡潔性,它無需記錄當前全部鏈接的狀態,因此它是一種無狀態調度。
輪詢調度算法流程
假設有一組服務器N臺,S = {S1, S2, …, Sn},一個指示變量i表示上一次選擇的服務器ID。變量i被初始化爲N-1。其算法以下:web

j = i;
do
{
    j = (j + 1) mod n;
    i = j;
    return Si;
} while (j != i);
return NULL;

參考:http://www.iteye.com/topic/1113595算法

權重 weight

      指定輪詢概率,weight和訪問比率成正比,用於後端服務器性能不均的狀況,默認每一個服務器的weight權重是1,若是後端服務器down掉,能自動剔除。後端

      當一個客戶請求到達後,RR策略是從upstream的全部server中選擇一個當前權重(current_weight)最大的server做爲最初的server.緩存

 

權重配置例子:服務器

http {
   upstream myproject {
     server 127.0.0.18000 weight=3;
     server 127.0.0.18001;
     server 127.0.0.18002;
     server 127.0.0.18003;
   }

   server {
     listen 80;
     server_name www.domain.com;
     location / {
         proxy_pass http//myproject;
    }
   }
}

這樣的權重算法邏輯:http://blog.sina.com.cn/s/blog_7303a1dc01014i0j.html
網絡

最先的算法代碼邏輯以下:

 -13433621041 (1)

算法以下:

//按照weight來返回一個peer的下標
//找到當前比率最大的那項,返回這項的下標
static ngx_uint_t
ngx_http_upstream_get_peer( ngx_http_upstream_rr_peers_t *peers )
{
ngx_uint_t i, n;
ngx_http_upstream_rr_peer_t *peer;
peer = &peers->peer[0];
for ( ; ; ){
for ( i = 0; i < peers->number; i++ ) {
if ( peer[i].current_weight <= 0 ){
continue;
}
n = i;
while ( i < peers->number - 1 ) {
i++; // 和下一個比較是否大,若是比下一個小,則返回下一個
if ( peer[i].current_weight <= 0 ){
continue;
}
if ( peer[n].current_weight * 1000 / peer[i].current_weight
> peer[n].weight * 1000 / peer[i].weight ){
return n;
}
n = i;
}
//找到最後了,尚未比第i項比率大的,則說明這項就是,返回這項
if ( peer[i].current_weight > 0 ) {
n = i;
}
return n;
}
//走到這裏的時候,說明都是0了,從新初始化爲滿額,接着循環找,老是能找到一個
for ( i = 0; i < peers->number; i++ ){
peer[i].current_weight = peer[i].weight;
}
}
}

http://blog.xcai.net/fav/nginx-load-balance-analyze

http://stblog.baidu-tech.com/?p=2027

算法僞代碼(2012.5.14後修正的算法):

foreach peer in peers {
peer->current_weight += peer->effective_weight;
    total += peer->effective_weight;
 
    if (best == NULL || peer->current_weight > best->current_weight) {
        best = peer;
    }
}
best->current_weight -= total;

一個具體計算的例子:

selected server current_weight before selected current_weight after selected
a { 5, 1, 2 } { -3, 1, 2 }
c { 2, 2, 4 } { 2, 2, -4 }
a { 7, 3, -2 } { -1, 3, -2 }
a { 4, 4, 0 } { -4, 4, 0 }
b { 1, 5, 2 } { 1, -3, 2 }
a { 6, -2, 4 } { -2, -2, 4 }
b { 3, -1, 6 } { 3, -1, -2 }
a { 8, 0, 0 } { 0, 0, 0 }


http://book.51cto.com/art/201202/314691.htm

 

ip_hash


      每一個請求按訪問ip的hash結果分配,這樣每一個訪客固定訪問一個後端服務器,能夠解決session的問題。 

在ip_hash策略中,它選擇最初的server的方法是根據請求客戶端的IP計算出一個哈希值,再根據哈希值選擇後臺的服務器。

由IP計算哈希值的算法以下, 其中公式中hash初始值爲89,iphp->addr[i]表示客戶端的IP, 經過三次哈希計算得出一個IP的哈希值:

for (i = 0; i < 3; i++) {
      hash = (hash * 113 + iphp->addr[i]) % 6271;
}

在選擇下一個server時,ip_hash的選擇策略是這樣的:它在上一次哈希值的基礎上,再次哈希,就會獲得一個全新的哈希值,再根據哈希值選擇另一個後臺的服務器。
哈希算法仍然是:

for (i = 0; i < 3; i++) {
      hash = (hash * 113 + iphp->addr[i]) % 6271;
}

在這種ip_hash策略,若是一個後臺服務器不能提供提服務(鏈接超時或讀超時),該服務器的失敗次數就會加一,當一個服務器的失敗次數達到max_fails所設置的值,就會在fail_timeout所設置的時間段內不能對外提供服務,這點和RR是一致的。
若是當前server不能提供服務,就會根據當前的哈希值再哈希出一個新哈希值,選擇另外一個服務器繼續嘗試,嘗試的最大次是upstream中server的個數,若是server的個數超過20,也就是要最大嘗試次數在20次以上,當嘗試次數達到20次,仍然找不到一個合適的服務器,ip_hah策略再也不嘗試ip哈希值來選擇server, 而在剩餘的嘗試中,它會轉而使用RR的策略,使用輪循的方法,選擇新的server。

參考: http://blog.sina.com.cn/s/blog_9c3ba23d01010rof.html

fair


      按後端服務器的響應時間來分配請求,響應時間短的優先分配。 

配置例子以下:

upstream web_pool {
    server 172.23.136.148;
    server 172.23.136.149;
    fair;
}


url_hash

按訪問url的hash結果來分配請求,使每一個url定向到同一個後端服務器,後端服務器爲緩存時比較有效。

例:在upstream中加入hash語句,server語句中不能寫入weight等其餘的參數,hash_method是使用的hash算法。

upstream web_pool {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}

 

一致性hash模塊(淘寶 tengine特有的算法)

這個模塊提供一致性hash做爲負載均衡算法。

具體算法,將每一個server虛擬成n個節點(根據server權重對應到n個節點),均勻分佈到hash環上,每次請求,根據配置的參數計算出一個hash值,在hash環
上查找離這個hash最近的虛擬節點,對應的server做爲該次請求的後端機器。

具體哈希值的計算,依賴於客戶端信息(如:$ip, $uri, $args等變量)。

例子:

worker_processes  1;

http {
upstream test {
consistent_hash $request_uri;

server 127.0.0.1:9001 id=1001 weight=3;
server 127.0.0.1:9002 id=1002 weight=10;
server 127.0.0.1:9003 id=1003 weight=20;
}
}

說明:該模塊能夠根據配置參數採起不一樣的方式將請求均勻映射到後端機器,好比:

  • consistent_hash $remote_addr:能夠根據客戶端ip映射;
  • consistent_hash $request_uri: 根據客戶端請求的uri映射;
  • consistent_hash $args:根據客戶端攜帶的參數進行映射;

上面配置中咱們能夠看到server id 字段,若是配置id字段,則使用id字段做爲server標識,不然使用server ip和端口做爲server標識,使用id字段能夠手動設置server的標識,好比一臺機器的ip或者端口變化,id仍然能夠表示這臺機器。使用id字段.能夠減低增減服務器時hash的波動。

參考:
nginx(tengine)反向代理以及upstream的六種調度算法
http://itoedr.blog.163.com/blog/static/12028429720137113244975

 

 

這幾種負載均衡分配方法並非互相沖突的,咱們能夠組合使用。

另外還有一些其餘負載算法,好比tengine支持的: Session保持模塊、後端鏈接數限制模塊、隨機負載均衡模塊 等就不詳細描述了,參看:http://tengine.taobao.org/download/programmer-201209-Tengine.pdf

 

 

 

參考資料:

nginx 的模塊及處理流程
http://www.cnblogs.com/ghj1976/p/3363039.html

Module ngx_http_upstream_module
http://nginx.org/en/docs/http/ngx_http_upstream_module.html 

upstream模塊
http://tengine.taobao.org/book/chapter_05.html

nginx中upstream的設計和實現(三)
http://www.pagefault.info/?p=273

 

Nginx學習之六-nginx核心進程模型
http://blog.csdn.net/xiajun07061225/article/details/9241179

解析nginx負載均衡
http://stblog.baidu-tech.com/?p=2027

nginx 配置輪詢分流 實現負載均衡的方法
http://www.jbxue.com/article/11590.html

高性能Web服務器Nginx的配置與部署研究(15)Upstream負載均衡模塊
http://blog.csdn.net/poechant/article/details/7256184

Nginx中的upstream輪詢機制介紹
http://www.cnblogs.com/liqiu/p/3140329.html

高性能Linux服務器構建實戰:運維監控、性能調優與集羣應用
http://book.51cto.com/art/201202/314644.htm

Nginx 作負載均衡的幾種輪詢策略
http://zhuruxin86.iteye.com/blog/1694557

相關文章
相關標籤/搜索