Nginx-ru mailing list archive (nginx-ru@sysoev.ru)
[Date Prev ][Date Next ][Thread Prev ][Thread Next ][Date Index ][Thread Index ]
fair upstream weight balancer
На данный момент, если в nginx'е описать такой upstream:
upstream one {
server one weight=1000;
server two weight=1000;
}
то nginx сначала сделает 1000 запросов к серверу one, а потом - к серверу two.
Прилагаемый патч исправляет это - запросы распределяются равномерно.
--
Игорь Сысоев
http://sysoev.ru
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;