# HG changeset patch # User Igor Sysoev # Date 1317393001 0 # Node ID e917fc5eceb75abc7a82291ece99f71ce165a167 # Parent 525a34d74a0a163fad46e40e24fb77cdb7316897 Merging r4011, r4012, r4136: Proxy related fixes: *) Fixing cpu hog with all upstream servers marked "down". The following configuration causes nginx to hog cpu due to infinite loop in ngx_http_upstream_get_peer(): upstream backend { server 127.0.0.1:8080 down; server 127.0.0.1:8080 down; } server { ... location / { proxy_pass http://backend; } } Make sure we don't loop infinitely in ngx_http_upstream_get_peer() but stop after resetting peer weights once. Return 0 if we are stuck. This is guaranteed to work as peer 0 always exists, and eventually ngx_http_upstream_get_round_robin_peer() will do the right thing falling back to backup servers or returning NGX_BUSY. *) Upstream: properly allocate memory for tried flags. Previous allocation only took into account number of non-backup servers, and this caused memory corruption with many backup servers. See report here: http://mailman.nginx.org/pipermail/nginx/2011-May/026531.html *) Fix of cpu hog in event pipe. If client closed connection in ngx_event_pipe_write_to_downstream(), buffers in the "out" chain were lost. This caused cpu hog if all available buffers were in the "out" chain. Fix is to call ngx_chain_update_chains() before checking return code of output filter to avoid loosing buffers in the "out" chain. Note that this situation (all available buffers in the "out" chain) isn't normal, it should be prevented by busy buffers limit. Though right now it may happen with complex protocols like fastcgi. This should be addressed separately. diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -633,13 +633,13 @@ ngx_event_pipe_write_to_downstream(ngx_e rc = p->output_filter(p->output_ctx, out); + ngx_chain_update_chains(&p->free, &p->busy, &out, p->tag); + if (rc == NGX_ERROR) { p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } - ngx_chain_update_chains(&p->free, &p->busy, &out, p->tag); - for (cl = p->free; cl; cl = cl->next) { if (cl->buf->temp_file) { diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -228,13 +228,18 @@ ngx_http_upstream_init_round_robin_peer( rrp->peers = us->peer.data; rrp->current = 0; - if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { + n = rrp->peers->number; + + if (rrp->peers->next && rrp->peers->next->number > n) { + n = rrp->peers->next->number; + } + + if (n <= 8 * sizeof(uintptr_t)) { rrp->tried = &rrp->data; rrp->data = 0; } else { - n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) - / (8 * sizeof(uintptr_t)); + n = (n + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t)); rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t)); if (rrp->tried == NULL) { @@ -585,7 +590,7 @@ failed: static ngx_uint_t ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers) { - ngx_uint_t i, n; + ngx_uint_t i, n, reset = 0; ngx_http_upstream_rr_peer_t *peer; peer = &peers->peer[0]; @@ -624,6 +629,10 @@ ngx_http_upstream_get_peer(ngx_http_upst return n; } + if (reset++) { + return 0; + } + for (i = 0; i < peers->number; i++) { peer[i].current_weight = peer[i].weight; }