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.
This commit is contained in:
Igor Sysoev 2011-09-30 14:30:01 +00:00
parent 62e45cf0ab
commit 4f1f650ef2
2 changed files with 15 additions and 6 deletions

View File

@ -633,13 +633,13 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
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) {

View File

@ -228,13 +228,18 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
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_upstream_rr_peers_t *peers)
return n;
}
if (reset++) {
return 0;
}
for (i = 0; i < peers->number; i++) {
peer[i].current_weight = peer[i].weight;
}