fair upstream weight balancer

Igor Sysoev is at rambler-co.ru
Thu Jul 26 00:33:04 MSD 2007


На данный момент, если в nginx'е описать такой upstream:

upstream one {
    server   one  weight=1000;
    server   two  weight=1000;
}

то nginx сначала сделает 1000 запросов к серверу one, а потом - к серверу two.

Прилагаемый патч исправляет это - запросы распределяются равномерно.


-- 
Игорь Сысоев
http://sysoev.ru
-------------- next part --------------
Index: src/http/ngx_http_upstream_round_robin.c
===================================================================
--- src/http/ngx_http_upstream_round_robin.c	(revision 662)
+++ src/http/ngx_http_upstream_round_robin.c	(working copy)
@@ -9,6 +9,10 @@
 #include <ngx_http.h>
 
 
+static ngx_uint_t
+ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers);
+
+
 ngx_int_t
 ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
     ngx_http_upstream_srv_conf_t *us)
@@ -215,8 +219,13 @@
             /* it's a first try - get a current peer */
 
             for ( ;; ) {
-                rrp->current = rrp->peers->current;
+                rrp->current = ngx_http_upstream_get_peer(rrp->peers);
 
+                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+                               "get rr peer, current: %ui %i",
+                               rrp->current,
+                               rrp->peers->peer[rrp->current].current_weight);
+
                 n = rrp->current / (8 * sizeof(uintptr_t));
                 m = (uintptr_t) 1 << rrp->current % (8 * sizeof(uintptr_t));
 
@@ -236,6 +245,8 @@
                             break;
                         }
 
+                        peer->current_weight = 0;
+
                     } else {
                         rrp->tried[n] |= m;
                     }
@@ -243,12 +254,6 @@
                     pc->tries--;
                 }
 
-                rrp->peers->current++;
-
-                if (rrp->peers->current >= rrp->peers->number) {
-                    rrp->peers->current = 0;
-                }
-
                 if (pc->tries) {
                     continue;
                 }
@@ -258,16 +263,6 @@
 
             peer->current_weight--;
 
-            if (peer->current_weight == 0) {
-                peer->current_weight = peer->weight;
-
-                rrp->peers->current++;
-
-                if (rrp->peers->current >= rrp->peers->number) {
-                    rrp->peers->current = 0;
-                }
-            }
-
         } else {
             for ( ;; ) {
                 n = rrp->current / (8 * sizeof(uintptr_t));
@@ -290,6 +285,8 @@
                             break;
                         }
 
+                        peer->current_weight = 0;
+
                     } else {
                         rrp->tried[n] |= m;
                     }
@@ -311,18 +308,6 @@
             }
 
             peer->current_weight--;
-
-            if (peer->current_weight == 0) {
-                peer->current_weight = peer->weight;
-
-                if (rrp->current == rrp->peers->current) {
-                    rrp->peers->current++;
-
-                    if (rrp->peers->current >= rrp->peers->number) {
-                        rrp->peers->current = 0;
-                    }
-                }
-            }
         }
 
         rrp->tried[n] |= m;
@@ -352,6 +337,61 @@
 }
 
 
+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;
+            }
+
+            if (peer[i].current_weight > 0) {
+                n = i;
+            }
+
+            return n;
+        }
+
+        for (i = 0; i < peers->number; i++) {
+            if (peer[i].fails == 0) {
+                peer[i].current_weight += peer[i].weight;
+
+            } else {
+                /* 1 allows to go to quick recovery */
+                peer[i].current_weight = 1;
+            }
+        }
+    }
+}
+
+
 void
 ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
     ngx_uint_t state)
@@ -385,8 +425,14 @@
         peer->fails++;
         peer->accessed = now;
 
-        if (peer->current_weight > 1) {
-            peer->current_weight /= 2;
+        peer->current_weight -= peer->weight / peer->max_fails;
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+                       "free rr peer failed: %ui %i",
+                       rrp->current, peer->current_weight);
+
+        if (peer->current_weight < 0) {
+            peer->current_weight = 0;
         }
 
         /* ngx_unlock_mutex(rrp->peers->mutex); */
Index: src/http/ngx_http_upstream_round_robin.h
===================================================================
--- src/http/ngx_http_upstream_round_robin.h	(revision 662)
+++ src/http/ngx_http_upstream_round_robin.h	(working copy)
@@ -18,8 +18,8 @@
     socklen_t                       socklen;
     ngx_str_t                       name;
 
-    ngx_uint_t                      current_weight;
-    ngx_uint_t                      weight;
+    ngx_int_t                       current_weight;
+    ngx_int_t                       weight;
 
     ngx_uint_t                      fails;
     time_t                          accessed;
@@ -29,15 +29,13 @@
 
     ngx_uint_t                      down;          /* unsigned  down:1; */
 
-#if (NGX_SSL)
+#if (NGX_HTTP_SSL)
     ngx_ssl_session_t              *ssl_session;   /* local to a process */
 #endif
 } ngx_http_upstream_rr_peer_t;
 
 
 typedef struct {
-    ngx_uint_t                      current;
-
     ngx_uint_t                      number;
     ngx_uint_t                      last_cached;
 


More information about the nginx-ru mailing list