【轉載】負載均衡Load Balance學習

轉載於 http://www.javashuo.com/article/p-kzfudmri-bm.htmlphp

 

目錄html

1. 負載均衡簡介
2. 負載均衡算法
3. Nginx負載均衡調度算法源碼調研

 

1. 負載均衡簡介前端

0x1: 負載均衡是什麼linux

負載均衡是一種技術架構方法,它並非具體指哪種技術,也正是由於這樣,負載均衡被運用在了不少的領域nginx

嚴格來講,負載平衡(Load balancing)是一種計算機網絡技術,用來在多個計算機(計算機集羣)、網絡鏈接、CPU、磁盤驅動器或其餘資源中分配負載,以達到最佳化資源使用、最大化吞吐率、最小化響應時間、同時避免過載的目的,使用帶有負載平衡的多個服務器組件,取代單一的組件,能夠經過冗餘提升可靠性。負載平衡服務一般是由專用軟體和硬件來完成git

負載平衡最重要的一個應用是利用多臺服務器提供單一服務,這種方案有時也稱之爲"服務器農場"。一般,負載平衡主要應用於github

複製代碼
1. Web網站
2. 大型的Internet Relay Chat網絡
3. 高流量的文件下載網站
4. NNTP(Network News Transfer Protocol)服務
5. DNS服務
6. 海量SOCKET、HTTP長鏈接(常見於頁遊、MSN聊天軟件、APP等場景中)
7. 數據庫鏈接、查詢服務(稱之爲數據庫負載平衡器)
複製代碼

對於互聯網服務,負載平衡器一般是一個軟體程序,這個程序偵聽一個外部端口,互聯網用戶能夠經過這個端口來訪問服務,而做爲負載平衡器的軟體會將用戶的請求轉發給後臺內網服務器,內網服務器將請求的響應返回給負載平衡器,負載平衡器再將響應發送到用戶,這樣就向互聯網用戶隱藏了內網結構,阻止了用戶直接訪問後臺(內網)服務器,使得服務器更加安全,能夠阻止對核心網絡棧和運行在其它端口服務的攻擊
當全部後臺服務器出現故障時,有些負載平衡器會提供一些特殊的功能來處理這種狀況。例如轉發請求到一個備用的負載平衡器、顯示一條關於服務中斷的消息等。負載平衡器使得IT團隊能夠顯著提升容錯能力。它能夠自動提供大量的容量以處理任何應用程序流量的增長或減小算法

0x2: 負載均衡的類別數據庫

咱們知道,負載均衡是一種架構思想,它在不少業務場景下都有獲得運用,大致上,負載均衡有以下幾種apache

複製代碼
1. 面向應用層的負載均衡器
    1.1 WEB訪問
        1) Apache模塊mod_proxy(提供代理服務器功能)
        http://www.php100.com/manual/apache2/mod/mod_proxy.html
        此模塊實現了Apache的代理/網關。它實現瞭如下規範的代理:
            1.1) AJP13(Apache JServe Protocol v1.3): mod_proxy_ajp
            1.2) FTP: mod_proxy_ftp
            1.3) CONNECT(用於SSL): mod_proxy_connect
            1.4) HTTP/0.9: mod_proxy_http
            1.5) HTTP/1.0: mod_proxy_http
            1.6) HTTP/1.1: mod_proxy_http
        此模塊經配置後可用上述或其它協議鏈接其它代理模塊
        2) Apache Web服務器的mod_proxy_balancer擴展(提供負載均衡功能)
        在使用基於Apache的負載均衡配置的時候,須要同時開啓mod_proxy、mod_proxy_balancer、mod_proxy_xx這些模塊
        
        3) 基於反向代理的Nginx負載均衡器
        http://blog.sina.com.cn/s/blog_9c3ba23d01010rof.html

        4) Varnish負載均衡
        http://network.51cto.com/art/201005/198191.htm

        5) Pound反向代理和負載均衡器

        6) 基於URL Rewrite的負載均衡器

    1.2 DNS查詢
        1) 基於DNS輪詢的負載均衡: 
        用於將CLINET的DNS解析請求按照必定的算法均衡地分配到一個IP集羣中,針對WEB URL訪問提供負載均衡,即將一個域名解析到多個IP地址,這種方法可能存在的問題是,輪叫DNS方法的調度粒度是基於每一個域名服務器的,
域名服務器對域名解析的緩存會妨礙輪叫解析域名生效,這會致使服務器間負載的不平衡 2. 面向傳輸層的負載均衡器 1) HAProxy HAProxy提供高可用性、負載均衡以及基於TCP和HTTP應用的代理,支持虛擬主機 3. 面向網絡層的負載均衡器 3.1 LVS(Linux Virtual Server) 1) Virtual Server via Network Address Translation(VS/NAT) 經過網絡地址轉換,調度器重寫請求報文的目標地址,根據預設的調度算法,將請求分派給後端的真實服務器;真實服務器的響應報文經過調度器時,報文的源地址被重寫,再返回給客戶,完成整個負載調度過程。 2) Virtual Server via IP Tunneling(VS/TUN) 採用NAT技術時,因爲請求和響應報文都必須通過調度器地址重寫,當客戶請求愈來愈多時,調度器的處理能力將成爲瓶頸。爲了解決這個問題,調度器把請求報文經過IP隧道轉發至真實服務器,而真實服務器將響應直接返回給
客戶,因此調度器只處理請求報文。因爲通常網絡服務應答比請求報文大許多,採用VS/TUN技術後,集羣系統的最大吞吐量能夠提升10倍 3) Virtual Server via Direct Routing(VS/DR) VS/DR經過改寫請求報文的MAC地址,將請求發送到真實服務器,而真實服務器將響應直接返回給客戶。同VS/TUN技術同樣,VS/DR技術可極大地提升集羣系統的伸縮性。這種方法沒有IP隧道的開銷,對集羣中的真實服務器也
沒有必須支持IP隧道協議的要求,可是要求調度器與真實服務器都有一塊網卡連在同一物理網段上 3. 多層負載均衡: 高性能系統一般會使用 對於一個多層次架構體系,在負載均衡器或網絡分發器後面有兩種設計,術語稱之爲Bowties和Stovepipes 1) Stovepipe 事務是從頂部分發的,而後從一個固定通道經過一系列硬件和軟件設備,到達最終目的地 2) Bowties 在每一層中事務處理有多條路徑可供選擇 在事務處理的網絡結構中可能會是Stovepipes,也能夠是Bowties,或者根據每一層的實際需求採用雜貨構架 4. 跨語言異構系統間通訊負載均衡調度器 1) Gearman 使用Gearman將合適的計算任務分發給多臺計算機,如此大量的任務就能夠更快的完成了 http://baike.baidu.com/view/2926980.htm?fr=aladdin http://blog.chinaunix.net/uid-20357359-id-1963682.html 對於Gearman(齒輪工)的技術架構,咱們須要重點理解幾點 1.1) Gearman是一種API級的跨系統通訊方式,這種方式和REST、RPC相比提升了耦合度 1.2) 從某種程度上說,Gearman和數據庫技術中的存儲過程的思想很相似,經過在預處理階段實現後端的實現邏輯,並向前端暴露出API級的調用接口,這種方式提供了API的準確性、定製性、安全性 1.3) client、job schedule server、worker之間的API通訊是基於網絡IO實現的
複製代碼

0x3: 負載均衡的特性

當前,負載均衡器有各類各樣的"工做排程算法"(用於決定將前端用戶請求發送到哪個後臺服務器),這是負載均衡最核心的思想,負載均衡器至關因而在原始網絡鏈路上的中間插入一個"Proxy",這個Proxy能夠位於網絡架構上的任何一個位置,用於將原來的"1:N"的性能瓶頸關係轉化爲"N:N"關係,只要是遵循了這個思想的架構和方案,均可以說是實現了負載均衡的架構,從某種程度上來講,負載均衡器就是反向代理服務器,負載轉發並重創建原始鏈接

不管是軟件負載均衡器,仍是硬件負載均衡器都有一系列的特性

複製代碼
1. 不對稱負載調節
能夠對後臺服務器設置權重因子,權重因子用於控制服務器的請求處理量,進而控制服務器的負載。當後臺服務器的處理能力不是等同的時候,這是一種控制服務器負載的簡單方法

2. 優先啓動
當出現故障的服務器達到某個閥值,或者服務器負載太高時,備用服務器必需能夠及時上線提供服務

3. SSL截斷和加速(SSL卸載)
依賴服務器負載,處理加密數據或者經過SSL進行的受權請求會消耗Web服務器的大量CPU,隨着需求增長用戶會明顯感受到響應時間變長。爲了消除Web服務器上這部分(處理加密)負載,負載均衡器可能會將SSL通信截斷在負載均衡器上。
有些硬件負載均衡器上包含有專門用於處理SSL的硬件。當負載均衡器截斷SSL鏈接請求,再將用戶請求轉發給後臺前將HTTPS變爲HTTP。只要負載均衡器不超載,這個特性不會影響用戶體驗。 這種方法的負面效應是,因爲全部SSL都由負載均衡器一臺設備來處理,它會致使負載均衡器成爲負載均衡體系的一個瓶頸。若是不使用這個特性,SSL請求將會分發給各個Web服務器處理。是否採用這一特性,須要分析比較二者的資金投
入狀況,含有處理SSL特殊硬件的負載均衡器一般價格高昂,而Web服務器通常比較廉價。增長少許的Web服務器的花費可能明顯比升級負載均衡器要少。另外,一些服務器廠商如Oracle/Sun也開始在它們的CPU中加入加密加速模塊,
例如T2000。在負載均衡器上截斷SSL的另外一個優勢是容許負載均衡器能夠對基於HTTPS請求數據進行負載均衡或內容交換 4. DDOS攻擊防禦 負載均衡器能夠提供例如SYN cookies特性和延時綁定(在TCP握手完成以前,後臺服務器不會與用戶通信)來減緩SYN flook攻擊,and generally offload work from the servers to a more efficient platform 5. HTTP壓縮 使用gzip壓縮HTTP數據,以減小網絡上的數據傳輸量。對於響應時間較長,傳輸距離較遠的用戶,這一特性對於縮短響應時間效果明顯。這個特性會要求更多一些的負載均衡器CPU,這一功能也能夠由Web服務器來完成 6. TCP offload 其主要思想是同樣的,一般每一個用戶的每一個請求都會使用一個不一樣的TCP鏈接,這個特性利用HTTP/1.1未來自多個用戶的多個請求合併爲單個TCP socket再轉發給後臺服務器,即咱們常說的TCP緩存組包技術 7. TCP緩衝 負載均衡器能夠暫存後臺服務器對客戶的響應數據,再將它們轉發給那些響應時間較長網速較慢的客戶,如此後臺Web服務器就能夠釋放相應的線程去處理其它任務如直接整個響應數據直接發送給網速較快的用戶,這能夠從必定程度上解
決"HTTP SLOW ATTACK"慢速攻擊 8. 後臺服務器直接響應用戶(Direct Server Return) 這是不對稱負載分佈的一項功能,在不對稱負載分佈中請求和迴應經過不一樣的網絡路徑 9. 服務器健康檢查 負載均衡器能夠檢查後臺服務器應用層的健康情況並從服務器池中移除那些出現故障的服務器 10. HTTP緩存 負載均衡器能夠存儲"靜態內容"(相比於靜態內容,動態腳本的執行的緩存須要慎重考慮),當用戶請求它們時能夠直接響應用戶而沒必要再向後臺服務器請求 11. 內容過濾 負載均衡器能夠按要求修改經過它的數據 12. HTTP安全 負載均衡器能夠隱藏HTTP出錯頁面,刪除HTTP響應頭中的服務器標示信息,加密cookies以防止用戶修改 13. 優先隊列 也可稱之爲流量控制。它能夠對不一樣的內容設定不一樣的優先級 14. Content-aware switching(內容感知開關) 負載均衡器能夠基於用戶請求的URL發送請求到不一樣的後臺服務器,不管內容是加密(HTTPS)仍是沒有加密(HTTP) 15. 用戶受權 對來自不一樣身份驗證源的用戶進行驗證,而後再容許他們訪問一個網站 16. 可編程的流量控制 負載均衡器容許使用腳本編程來定製負載均衡方法,任意的流量控制以及其它功能 17. 防火牆功能 因爲安全的緣由,不容許用戶直接訪問後臺服務器。防火牆是由一系列規則構成,它們決定着哪些請求能夠經過一個接口而哪些不被容許。 提供入侵阻止功能。在防火牆保障網絡層/傳輸層安全的基礎上,提供應用層安全防範
複製代碼

 

2. 負載均衡算法

最簡單的是隨機選擇和輪詢。更爲高級的負載均衡器會考慮其它更多的相關因素,如後臺服務器的負載,響應時間,運行狀態,活動鏈接數,地理位置,處理能力,或最近分配的流量

複製代碼
1. 針對WEB訪問請求的負載均衡調度策略(反向代理的網絡鏈接方式)
    1) RR(Round Robin)
    每一個請求按時間順序逐一分配到不一樣的後端服務器,若是後端服務器down掉,能自動剔除,在實現RR算法的時候,還須要根據其餘的因素: max_fails、fail_timeout、weight等因素進行綜合評估
    
    2) WEIGHT(權重) 
    指定輪詢概率,WEIGHT和訪問比率成正比,用於後端服務器性能不均的狀況

    3) IP_HASH 
    每一個請求按訪問IP的Hash結果分配,這樣每一個訪客固定訪問一個後端服務器,能夠解決"負載集羣SESSION同步"的問題(由於Hash具備結果一致性)

    4) Fair(第三方) 
    按後端服務器的響應時間來分配請求,響應時間短的優先分配 

    5) URL_HASH(第三方)
    按訪問URL的Hash結果來分配請求,使每一個URL定向到同一個後端服務器,後端服務器爲緩存時比較有效

2. 針對網絡IP層訪問請求的負載均衡調度策略(面向SOCKET的IP負載均衡)
    1) 輪叫(Round Robin)
    調度器經過"輪叫"調度算法將外部請求按順序輪流分配到集羣中的真實服務器上,它均等地對待每一臺服務器,而無論服務器上實際的鏈接數和系統負載

    2) 加權輪叫(Weighted Round Robin)
    調度器經過"加權輪叫"調度算法根據真實服務器的不一樣處理能力來調度訪問請求。這樣能夠保證處理能力強的服務器處理更多的訪問流量。調度器能夠自動問詢真實服務器的負載狀況,並動態地調整其權值。

    3) 最少連接(Least Connections)
    調度器經過"最少鏈接"調度算法動態地將網絡請求調度到已創建的連接數最少的服務器上。若是集羣系統的真實服務器具備相近的系統性能,採用"最小鏈接"調度算法能夠較好地均衡負載。

    4) 加權最少連接(Weighted Least Connections)
    在集羣系統中的服務器性能差別較大的狀況下,調度器採用"加權最少連接"調度算法優化負載均衡性能,具備較高權值的服務器將承受較大比例的活動鏈接負載。調度器能夠自動問詢真實服務器的負載狀況,並動態地調整其權值。

    5) 基於局部性的最少連接(Locality-Based Least Connections)
    "基於局部性的最少連接" 調度算法是針對目標IP地址的負載均衡,目前主要用於Cache集羣系統。該算法根據請求的目標IP地址找出該目標IP地址最近使用的服務器,若該服務器 是可用的且沒有超載,將請求發送到該服務器;若服
務器不存在,或者該服務器超載且有服務器處於一半的工做負載,則用"最少連接"的原則選出一個可用的服務器,將請求發送到該服務器。 6) 帶複製的基於局部性最少連接(Locality-Based Least Connections with Replication) "帶複製的基於局部性最少連接"調度算法也是針對目標IP地址的負載均衡,目前主要用於Cache集羣系統。它與LBLC算法的不一樣之處是它要維護從一個目標IP地址到一組服務器的映射,而LBLC算法維護從一個目標IP地址到一臺服務
器的映射。該算法根據請求的目標IP地址找出該目標IP地址對應的服務 器組,按"最小鏈接"原則從服務器組中選出一臺服務器,若服務器沒有超載,將請求發送到該服務器,若服務器超載;則按"最小鏈接"原則從這個集羣中選出一臺服
務器,將該服務器加入到服務器組中,將請求發送到該服務器。同時,當該服務器組有一段時間沒有被修改,將最忙的服務器從服務器組中刪除,以下降複製的 程度。 7) 目標地址散列(Destination Hashing) "目標地址散列"調度算法根據請求的目標IP地址,做爲散列鍵(Hash Key)從靜態分配的散列表找出對應的服務器,若該服務器是可用的且未超載,將請求發送到該服務器,不然返回空。 8) 源地址散列(Source Hashing) "源地址散列"調度算法根據請求的源IP地址,做爲散列鍵(Hash Key)從靜態分配的散列表找出對應的服務器,若該服務器是可用的且未超載,將請求發送到該服務器,不然返回空
複製代碼

Relevant Link:

http://blog.sina.com.cn/s/blog_9c3ba23d01010rof.html
http://zh.wikipedia.org/wiki/%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1_(%E8%AE%A1%E7%AE%97%E6%9C%BA)
http://www.linuxvirtualserver.org/zh/lvs1.html#7

 

3. Nginx負載均衡調度算法源碼調研 

nginx 的負載均衡策略能夠劃分爲兩大類:內置策略和擴展策略。內置策略包含加權輪詢和ip hash,在默認狀況下這兩種策略會編譯進nginx內核,只需在nginx配置中指明參數便可。擴展策略有不少,如fair、通用hash、 consistent hash等,默認不編譯進nginx內核,是第三方模塊

在開始學習調度算法以前,咱們須要先了解一下Nginx調度算法所涉及到的數據結構,Nginx的負載均衡是根據配置文件進行的,因此Nginx在初始化的時候須要從配置文件中讀取配置並保存到相應的結構體中

1. struct ngx_conf_t

\nginx-1.0.14_comment-master\src\core\ngx_core.h

typedef struct ngx_conf_s        ngx_conf_t;

\nginx-1.0.14_comment-master\src\core\ngx_conf_file.h

複製代碼
struct ngx_conf_s 
{
    char                 *name;  //沒有使用
    ngx_array_t          *args;  //指令的參數

    ngx_cycle_t          *cycle; //指向系統參數,在系統整個運行過程當中,
                                 //須要使用的一些參數、資源須要統一的管理
    ngx_pool_t           *pool;  //內存池
    ngx_pool_t           *temp_pool; //分配臨時數據空間的內存池
    ngx_conf_file_t      *conf_file; //配置文件的信息
    ngx_log_t            *log; //日誌

    void                 *ctx;  //模塊的配置信息
    ngx_uint_t            module_type; //當前指令的類型
    ngx_uint_t            cmd_type; //命令的類型

    ngx_conf_handler_pt   handler; //指令處理函數,有本身行爲的在這裏實現
    char                 *handler_conf; //指令處理函數的配置信息
};
複製代碼

2. struct ngx_http_upstream_srv_conf_t

\nginx-1.0.14_comment-master\src\http\ngx_http_upstream.h

typedef struct ngx_http_upstream_srv_conf_s  ngx_http_upstream_srv_conf_t;

\nginx-1.0.14_comment-master\src\http\ngx_http_upstream.h

複製代碼
struct ngx_http_upstream_srv_conf_s 
{
    ngx_http_upstream_peer_t         peer;
    void                           **srv_conf;  // 在ngx_http_upstream()函數中被設置,指向的是本層的srv_conf  

    ngx_array_t                     *servers;   // ngx_http_upstream_server_t

    ngx_uint_t                       flags;     // 調用函數時ngx_http_upstream_add() 指定的標記  
    ngx_str_t                        host;      // 在函數 ngx_http_upstream_add()中設置(e.g. upstream backend中的backend)
    u_char                          *file_name; // "/usr/local/nginx/conf/nginx.conf"  
    ngx_uint_t                       line;      // proxy在配置文件中的行號  
    in_port_t                        port;      // 使用的端口號,ngx_http_upstream_add()函數中添加, 指向ngx_url_t-->port,一般在函數ngx_parse_inet_url()中解析
    in_port_t                        default_port;  //默認使用的端口號(ngx_http_upstream_add()函數中添加, 指向ngx_url_t-->default_port)
};
複製代碼

3. struct ngx_http_upstream_peer_t

\nginx-1.0.14_comment-master\src\http\ngx_http_upstream.h

複製代碼
typedef struct 
{
    //使用負載均衡的類型,默認採用ngx_http_upstream_init_round_robin()
    ngx_http_upstream_init_pt        init_upstream;

    //使用的負載均衡類型的初始化函數 
    ngx_http_upstream_init_peer_pt   init;

    //us->peer.data = peers; 指向的是 ngx_http_upstream_rr_peers_t(函數 ngx_http_upstream_init_round_robin()中設置)
    void                            *data;
} ngx_http_upstream_peer_t;
複製代碼

ngx_http_upstream_init_peer_pt、ngx_http_upstream_init_pt 是函數指針類型

\nginx-1.0.14_comment-master\src\http\ngx_http_upstream.h

typedef ngx_int_t (*ngx_http_upstream_init_pt)(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us);
typedef ngx_int_t (*ngx_http_upstream_init_peer_pt)(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us);

4. struct ngx_array_t 

\nginx-1.0.14_comment-master\src\core\ngx_core.h

typedef struct ngx_array_s       ngx_array_t;

\nginx-1.0.14_comment-master\src\core\ngx_array.h

複製代碼
// 動態數組
struct ngx_array_s 
{
    // elts指向數組的首地址
    void        *elts; 
    // nelts是數組中已經使用的元素個數
    ngx_uint_t   nelts; 
    // 每一個數組元素佔用的內存大小
    size_t       size;  
    // 當前數組中可以容納元素個數的總大小
    ngx_uint_t   nalloc; 
    // 內存池對象
    ngx_pool_t  *pool;  
};
複製代碼

5. struct ngx_http_upstream_server_t

\nginx-1.0.14_comment-master\src\http\ngx_http_upstream.h
須要注意的是,配置文件中出現的參數只能和某些策略配合使用,因此若是發現某參數沒有生效,則應該檢查這一點。在配置解析的過程當中,這些選項設置都被轉換爲Nginx內對於的變量值,對應的結構體ngx_http_upstream_server_t以下

複製代碼
typedef struct 
{
    ngx_addr_t                      *addrs;         //指向存儲IP地址的數組的指針,host信息(對應的是 ngx_url_t->addrs )  
    ngx_uint_t                       naddrs;        //與第一個參數配合使用,數組元素個數(對應的是 ngx_url_t->naddrs )  
    ngx_uint_t                       weight;
    ngx_uint_t                       max_fails;
    time_t                           fail_timeout;

    unsigned                         down:1;
    unsigned                         backup:1;
} ngx_http_upstream_server_t;
複製代碼

6. struct ngx_http_upstream_rr_peer_t

\nginx-1.0.14_comment-master\src\http\ngx_http_upstream_round_robin.h

複製代碼
typedef struct 
{
    struct sockaddr                *sockaddr;        //後端服務器地址  
    socklen_t                       socklen;        //後端服務器地址長度
    ngx_str_t                       name;        //後端名稱  
    ngx_str_t                       server;

    ngx_int_t                       current_weight;    //當前權重,nginx會在運行過程當中調整此權重  
    ngx_int_t                       effective_weight;    //配置的權重
    ngx_int_t                       weight;        //current_weight是運行時的動態權值

    ngx_uint_t                      fails;        //已嘗試失敗次數  
    time_t                          accessed;        //檢測失敗時間,用於計算超時  
    time_t                          checked;

    ngx_uint_t                      max_fails;        //最大失敗次數  
    time_t                          fail_timeout;    //多長時間內出現max_fails次失敗便認爲後端down掉了  

    ngx_uint_t                      down;          /* unsigned  down:1; */

#if (NGX_HTTP_SSL)
    ngx_ssl_session_t              *ssl_session;   /* local to a process */
#endif
} ngx_http_upstream_rr_peer_t;
複製代碼

列表最前面須要帶有一些head信息,用結構體ngx_http_upstream_rr_peers_t與之對應

7struct ngx_http_upstream_rr_peers_t

\nginx-1.0.14_comment-master\src\http\ngx_http_upstream_round_robin.h

複製代碼
typedef struct ngx_http_upstream_rr_peers_s  ngx_http_upstream_rr_peers_t;

struct ngx_http_upstream_rr_peers_s 
{
    ngx_uint_t                      single;         // unsigned  single:1;  
    ngx_uint_t                      number;         // 隊列中服務器數量 
    ngx_uint_t                      last_cached;

 /* ngx_mutex_t                    *mutex; */
    ngx_connection_t              **cached;

    ngx_str_t                      *name;

    ngx_http_upstream_rr_peers_t   *next;           // 後備服務器列表掛載在這個字段下  

    ngx_http_upstream_rr_peer_t     peer[1];
};
複製代碼

0x1: 帶權重的RR調度策略

圖片很大,能夠另存到本地看

能夠看到,Weight RR加權輪叫的流程簡單來講能夠歸納爲: 讀取配置文件->保存配置文件中的指定選項->創建後端服務器集羣的數據結構,併爲止設置參數->根據權重動態計算公式在每次請求到達時對每一個後端服務器的權值進行動態更新,每次都選出一個最優權值服務器進行調度

0x2: Nginx的負載均衡權重動態調整算法

在ngx_http_upstream_get_peer()中傳入的參數是一個ngx_http_upstream_rr_peer_t結構體

複製代碼
typedef struct 
{
    ...
    /*
    1. 當前權重,nginx會在運行過程當中調整此權重  
    current_weight至關於重量,是運行時的動態權值,它的變化基於effective_weight。可是
        1) effective_weight在其對應的peer服務異常時,會被調低
        2) 當服務恢復正常時,effective_weight會逐漸恢復到實際值(配置的weight)
    */
    ngx_int_t    current_weight;         

    /*
    2. 配置的權重
    effective_weight至關於質量(來源於配置的weight),反應了本質
    */
    ngx_int_t    effective_weight;     
    ngx_int_t    weight;            //current_weight是運行時的動態權值
    ...
 } ngx_http_upstream_rr_peer_t;
複製代碼

weight、effective_weight都是初始化爲配置項中的weight值。current_weight初始化爲0

1. weight的值在整個運行過程當中不發生變化
2. total變量記錄了針對一個服務列表的一次輪詢過程當中輪詢到的全部服務的effective_weight總和。在每一次針對服務列表的輪詢以前會置爲爲0
3. 遍歷服務列表的過程當中,每遍歷到一個服務
    1) 會在該服務的current_weight上加上其對應的effective_weight。這個是累加
    2) 若是對統一的服務列表進行另外一次輪詢,那麼會在前面計算的current_weight的基礎之上再加上effective_weight
4. 輪詢策略是取current_weight最大的服務器。每次取到後端服務(用best表示)後,都會把該對象peer的current_weight減去total的值。由於該服務剛被選中過,所以要下降權值

關於effective_weight的變化,有兩處

複製代碼
1. ngx_http_upstream_get_peer()中
//服務正常,effective_weight 逐漸恢復正常      
if (peer->effective_weight < peer->weight) 
{  
    peer->effective_weight++;  
}

2. 另外一處是在釋放後端服務的函數ngx_http_upstream_free_round_robin_peer中
if (peer->max_fails) 
{  
     //服務發生異常時,調低effective_weight  
    peer->effective_weight -= peer->weight / peer->max_fails;  
}
複製代碼

權重高的會優先被選中,並且被選中的頻率也更高。權重低的也會因爲權重逐漸增加得到被選中的機會

0x3: IP_HASH調度策略

IP_hash和RR 的策略有兩點不一樣在於: 當一個客戶請求到nginx後

1. Nginx如何選擇一個最初的server
2. 以及當前選擇的server不能提供服務時,如何選擇下一個server

在IP_hash策略中

複製代碼
1. 它選擇最初的server的方法是根據請求客戶端的IP計算出一個哈希值,再根據哈希值選擇後臺的服務器,由IP計算哈希值的算法以下
//其中公式中hash初始值爲89,iphp->addr[i]表示客戶端的IP,經過三次哈希計算得出一個IP的哈希值
for (i = 0; i < 3; i++) 
{
      hash = (hash * 113 + iphp->addr[i]) % 6271;
}
 
2. 在選擇下一個server時,ip_hash的選擇策略是這樣的:
它在上一次哈希值的基礎上,再次哈希,就會獲得一個全新的哈希值,再根據哈希值選擇另一個後臺的服務器。哈希算法仍然是
for (i = 0; i < 3; i++) 
{
      hash = (hash * 113 + iphp->addr[i]) % 6271;
}
 
3. 在這種ip_hash策略
    1) 若是一個後臺服務器不能提供提服務(鏈接超時或讀超時),該服務器的失敗次數就會加一,當一個服務器的失敗次數達到max_fails所設置的值,就會在fail_timeout所設置的時間段內不能對外提供服務,這點和RR是一致的
    2) 若是當前server不能提供服務,就會根據當前的哈希值再哈希出一個新哈希值,選擇另外一個服務器繼續嘗試,嘗試的最大次是upstream中server的個數,若是server的個數超過20,也就是要最大嘗試次數在20次以上,當嘗試
次數達到20次,仍然找不到一個合適的服務器,ip_hah策略再也不嘗試ip哈希值來選擇server, 而在剩餘的嘗試中,它會轉而使用RR的策略,使用輪循的方法,選擇新的server。 4. 除了以上部分不一樣外,IP_hash的其他部分和RR徹底同樣,由於它的其他部分功能的實現都是經過調用RR中的函數
複製代碼

Relevant Link:

複製代碼
http://www.cnblogs.com/yjf512/archive/2012/06/13/2548515.html
https://github.com/jianfengye/nginx-1.0.14_comment
http://blog.csdn.net/gzh0222/article/details/7996835
http://blog.csdn.net/livelylittlefish/article/details/6571497
http://blog.sina.com.cn/s/blog_9c3ba23d01010rof.html
http://blog.csdn.net/xiajun07061225/article/details/9318871
http://baidutech.blog.51cto.com/4114344/1033718
《nginx模塊開發與架構解析》
複製代碼
相關文章
相關標籤/搜索