<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                Nginx版本:1.9.1 我的博客:[http://blog.csdn.net/zhangskd](http://blog.csdn.net/zhangskd) ? **算法介紹** ? 來看一個簡單的Nginx負載均衡配置。 ~~~ http { upstream cluster { server a weight=5; server b weight=1; server c weight=1; } server { listen 80; location / { proxy_pass http://cluster; } } } ~~~ 當在upstream配置塊中沒有指定使用的負載均衡算法時,默認使用的是加權輪詢。 按照上述配置,Nginx每收到7個客戶端的請求,會把其中的5個轉發給后端a,把其中的1個轉發給后端b, 把其中的1個轉發給后端c。 ? 這就是所謂的加權輪詢,看起來很簡單,但是最早使用的加權輪詢算法有個問題,就是7個請求對應的 后端序列是這樣的:{ c, b, a, a, a, a, a },會有5個連續的請求落在后端a上,分布不太均勻。 目前使用的加權輪詢叫做平滑的加權輪詢(smooth weighted round-robin balancing),它和前者的區別是: 每7個請求對應的后端序列為 { a, a, b, a, c, a, a },轉發給后端a的5個請求現在分散開來,不再是連續的。 ? 摘錄此算法的描述: On each peer selection we increase current_weight of each eligible peer by its weight, select peer with greatest current_weight and reduce its current_weight by total number of weight points distributed among peers. To preserve weight reduction in case of failures the effective_weight variable was introduced, which usually matches peer's weight, but is reduced temoprarily on peer failures.[1] ? 每個后端peer都有三個權重變量,先解釋下它們的含義。 **(1) weight** 配置文件中指定的該后端的權重,這個值是固定不變的。 **(2) effective_weight** 后端的有效權重,初始值為weight。 在釋放后端時,如果發現和后端的通信過程中發生了錯誤,就減小effective_weight。 此后有新的請求過來時,在選取后端的過程中,再逐步增加effective_weight,最終又恢復到weight。 之所以增加這個字段,是為了當后端發生錯誤時,降低其權重。 **(3) current_weight** 后端目前的權重,一開始為0,之后會動態調整。那么是怎么個動態調整呢? 每次選取后端時,會遍歷集群中所有后端,對于每個后端,讓它的current_weight增加它的effective_weight, 同時累加所有后端的effective_weight,保存為total。 如果該后端的current_weight是最大的,就選定這個后端,然后把它的current_weight減去total。 如果該后端沒有被選定,那么current_weight不用減小。 ? 弄清了三個weight字段的含義后,加權輪詢算法可描述為: 1. 對于每個請求,遍歷集群中的所有可用后端,對于每個后端peer執行: ??? peer->current_weight += peer->effecitve_weight。 ??? 同時累加所有peer的effective_weight,保存為total。 2. 從集群中選出current_weight最大的peer,作為本次選定的后端。 3. 對于本次選定的后端,執行:peer->current_weight -= total。 ? 上述描述可能不太直觀,來看個例子。 現在使用以下的upstream配置塊: upstream backend { ??? server a weight=4; ??? server?b weight=2; ??? server?c weight=1; } 按照這個配置,每7個客戶端請求中,a會被選中4次、b會被選中2次、c會被選中1次,且分布平滑。 我們來算算看是不是這樣子的。 initial current_weight of a, b, c is { 0, 0, 0 } ![](https://box.kancloud.cn/2016-03-22_56f0c8a51631d.jpg) ? 通過上述過程,可得以下結論: 1. 7個請求中,a、b、c分別被選取了4、2、1次,符合它們的權重值。 2. 7個請求中,a、b、c被選取的順序為a, b, a, c, a, b, a,分布均勻,權重大的后端a沒有被連續選取。 3. 每經過7個請求后,a、b、c的current_weight又回到初始值{ 0, 0, 0 },因此上述流程是不斷循環的。 這個平滑的加權輪詢算法背后應該有數學論證,這里就不繼續研究了:) ? **本模塊的數據結構** ? ngx_http_upstream_rr_peer_t ? 表示一臺后端服務器。peer就是對端,指的是上游服務器端。 ~~~ struct ngx_http_upstream_rr_peer_s { struct sockaddr *sockaddr; /* 后端服務器的地址 */ socklen_t socklen; /* 地址的長度*/ ngx_str_t name; /* 后端服務器地址的字符串,server.addrs[i].name */ ngx_str_t server; /* server的名稱,server.name */ ngx_int_t current_weight; /* 當前的權重,動態調整,初始值為0 */ ngx_int_t effective_weight; /* 有效的權重,會因為失敗而降低 */ ngx_int_t weight; /* 配置項指定的權重,固定值 */ ngx_uint_t conns; /* 當前連接數 */ ngx_uint_t fails; /* "一段時間內",已經失敗的次數 */ time_t accessed; /* 最近一次失敗的時間點 */ time_t checked; /* 用于檢查是否超過了"一段時間" */ ngx_uint_t max_fails; /* "一段時間內",最大的失敗次數,固定值 */ time_t fail_timeout; /* "一段時間"的值,固定值 */ ngx_uint_t down; /* 服務器永久不可用的標志 */ ... ngx_http_upstream_rr_peer_t *next; /* 指向下一個后端,用于構成鏈表 */ ... } ngx_http_upstream_rr_peer_t; ~~~ ? ngx_http_upstream_rr_peers_t 表示一組后端服務器,比如一個后端集群。 ~~~ struct ngx_http_upstream_rr_peers_s { ngx_uint_t number; /* 后端服務器的數量 */ ... ngx_uint_t total_weight; /* 所有后端服務器權重的累加值 */ unsigned single:1; /* 是否只有一臺后端服務器 */ unsigned weighted:1; /* 是否使用權重 */ ngx_str_t *name; /* upstream配置塊的名稱 */ ngx_http_upstream_rr_peers_t *next; /* backup服務器集群 */ ngx_http_upstream_rr_peer_t *peer; /* 后端服務器組成的鏈表 */ }; ~~~ ngx_http_upstream_rr_peer_data_t 保存每個請求的負載均衡數據。 ~~~ typedef struct { ngx_http_upstream_rr_peers_t *peers; /* 后端集群 */ ngx_http_upstream_rr_peer_t *current; /* 當前使用的后端服務器 */ uintptr_t *tried; /* 指向后端服務器的位圖 */ uintptr_t data; /* 當后端服務器的數量較少時,用于存放其位圖 */ } ngx_http_upstream_rr_peer_data_t; ~~~ ? **通用的數據結構** ? 以下是所有負載均衡模塊都會使用到的一些數據結構。 ngx_http_upstream_server_t ? 表示upstream配置塊中的一條server指令。 ~~~ typedef struct { ngx_str_t name; /* 服務器的名稱 */ ngx_addr_t *addrs; /* 服務器地址的數組,因為同一個域名可能解析為多個IP */ ngx_uint_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; ~~~ ? **server指令** Syntax: server address [parameters]; Context: upstream Defines the address and other parameters of a server. The address can be specified as domain name or IP address, with an optional port, or... If a port is not specified, the port 80 is used. A domain name that resolves to serveral IP addresses defines multiple servers at once. ? **server指令支持如下參數** *weight* = number ??? sets the weight of the server, by default 1. *max_fails* = number ??? By default, the number of unsuccessful attempts is set to 1. ??? The zero value disables the accounting of attempts. *fail_timout* = number ??? By default it is set to 10 seconds. *backup* ??? marks the server as a backup server. *down* ??? marks the server as permanently unavailable. ? ngx_peer_connection_t ? 表示本機和后端的連接,也叫主動連接,用于upstream機制。 ~~~ struct ngx_peer_connection_s { ngx_connection_t *connection; /* 后端連接 */ struct sockaddr *sockaddr; /* 后端服務器的地址 */ socklen_t socklen; /* 后端服務器地址的長度 */ ngx_str_t *name; /* 后端服務器的名稱 */ ngx_uint_t tries; /* 對于一個請求,允許嘗試的后端服務器個數 */ ngx_event_get_peer_pt get; /* 負載均衡模塊實現,用于選取一個后端服務器 */ ngx_event_free_peer_pt free; /* 負載均衡模塊實現,用于釋放一個后端服務器 */ void *data; /* 請求的負載均衡數據,一般指向ngx_http_upstream_<name>_peer_data_t */ ... ngx_addr_t *local; /* 本機地址 */ int rcvbuf; /* 套接字接收緩沖區的大小 */ ngx_log_t *log; unsigned cached:1; unsigned log_error:2; }; ~~~ ngx_peer_connection_t *pc; pc->get 就是負載均衡模塊中,用于選取后端服務器的函數。 當選定一臺后端服務器時,把它的地址信息保存在pc->sockaddr、pc->socklen、pc->name。 pc->tries表示對于一個請求,最多能嘗試多少個后端。當嘗試一個后端失敗時,會調用pc->free, 一個主要目的就是更新pc->tries,比如pc->tries--。如果pc->tries降到0,就不再嘗試了。 在請求的負載均衡數據初始化函數peer.init中,會給該請求創建一個ngx_http_upstream_<name>_peer_data_t實例, 用于保存該請求的負載均衡數據,pc->data就是該實例的地址。 ? **ngx_http_upstream_peer_t** ? 保存upstream塊的數據,是負載均衡中一個很重要的結構體。 ~~~ typedef struct { /* upstream塊的初始化函數,ngx_http_upstream_module創建main配置時調用。 * 針對每個upstream塊。 */ ngx_http_upstream_init_pt init_upstream; /* request在初始化upstream機制時調用,初始化該請求的負載均衡數據。 * 針對每個request。 */ ngx_http_upstream_init_peer_pt init; void *data; /* 保存upstream塊的數據 */ } ngx_http_upstream_peer_t; ~~~ upstream塊的數據,在解析配置文件時就創建和初始化了。 如果寫了一個新的負載均衡模塊,則需要在它的指令解析函數中指定init_upstream的值, 用來創建和初始化包含該指令的upstream配置塊的數據。 ? **ngx_http_upstream_srv_conf_t** ? ngx_http_upstream_module的server塊。 ~~~ struct ngx_http_upstream_srv_conf_s { ngx_http_upstream_peer_t peer; /* upstream塊的數據 */ void **srv_conf; /* 所有HTTP模塊的server conf */ ngx_array_t *server; /* upstream塊的server數組,元素類型為ngx_http_upstream_server_t */ ngx_uint_t flags; /* upstream塊的server指令支持的參數 */ ngx_str_t host; /* upstream塊的名稱 */ u_char *file_name; ngx_uint_t line; in_port_t port; /* 使用的端口 */ in_port_t default_port; /* 默認的端口 */ ngx_uint_t no_port; ... }; #define ngx_http_conf_upstream_srv_conf(uscf, module) uscf->srv_conf[module.ctx_index] ~~~ ? **Reference** ? [1].[https://github.com/phusion/nginx/commit/27e94984486058d73157038f7950a0a36ecc6e35](https://github.com/phusion/nginx/commit/27e94984486058d73157038f7950a0a36ecc6e35) ?
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看