static ngx_http_upstream_rr_peer_t * ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp) { time_t now; uintptr_t m; ngx_int_t total; ngx_uint_t i, n; ngx_http_upstream_rr_peer_t *peer, *best; #if (NGX_HTTP_PERSISTENCE) ngx_int_t persist_index; persist_index = ngx_http_upstream_ps_get(rrp->request, rrp->peers->number, rrp->group); #endif now = ngx_time(); best = NULL; total = 0; for (i = 0; i < rrp->peers->number; i++) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { i = persist_index; } #endif n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); if (rrp->tried[n] & m) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { persist_index = -1; i = 0; } #endif continue; } peer = &rrp->peers->peer[i]; if (peer->down) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { persist_index = -1; i = 0; } #endif continue; } #if (NGX_HTTP_UPSTREAM_CHECK) if (ngx_http_upstream_check_peer_down(peer->check_index)) { continue; } #endif if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { persist_index = -1; i = 0; } #endif continue; } #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { best = peer; break; } #endif peer->current_weight += peer->effective_weight; total += peer->effective_weight; if (peer->effective_weight < peer->weight) { peer->effective_weight++; } if (best == NULL || peer->current_weight > best->current_weight) { best = peer; } } if (best == NULL) { return NULL; } i = best - &rrp->peers->peer[0]; rrp->current = i; n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); rrp->tried[n] |= m; best->current_weight -= total; if (now - best->checked > best->fail_timeout) { best->checked = now; } #if (NGX_HTTP_PERSISTENCE) ngx_http_upstream_ps_set(rrp->request, rrp->current, rrp->group); #endif return best; }
static ngx_int_t ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) { ngx_http_upstream_lc_peer_data_t *lcp = data; time_t now; uintptr_t m; ngx_int_t rc, total; ngx_uint_t i, n, p, many; ngx_http_upstream_rr_peer_t *peer, *best; ngx_http_upstream_rr_peers_t *peers; #if (NGX_HTTP_PERSISTENCE) ngx_int_t persist_index; #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least conn peer, try: %ui", pc->tries); if (lcp->rrp.peers->single) { return lcp->get_rr_peer(pc, &lcp->rrp); } pc->cached = 0; pc->connection = NULL; now = ngx_time(); peers = lcp->rrp.peers; best = NULL; total = 0; #if (NGX_SUPPRESS_WARN) many = 0; p = 0; #endif #if (NGX_HTTP_PERSISTENCE) persist_index = ngx_http_upstream_ps_get(lcp->rrp.request, lcp->rrp.peers->number, lcp->rrp.group); #endif for (i = 0; i < peers->number; i++) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { i = persist_index; } #endif n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); if (lcp->rrp.tried[n] & m) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { persist_index = -1; i = 0; } #endif continue; } peer = &peers->peer[i]; if (peer->down) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { persist_index = -1; i = 0; } #endif continue; } #if (NGX_HTTP_UPSTREAM_CHECK) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least_conn peer, check_index: %ui", peer->check_index); if (ngx_http_upstream_check_peer_down(peer->check_index)) { continue; } #endif if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) { #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { persist_index = -1; i = 0; } #endif continue; } #if (NGX_HTTP_PERSISTENCE) if(persist_index >= 0) { best = peer; p = persist_index; break; } #endif /* * select peer with least number of connections; if there are * multiple peers with the same number of connections, select * based on round-robin */ if (best == NULL || lcp->conns[i] * best->weight < lcp->conns[p] * peer->weight) { best = peer; many = 0; p = i; } else if (lcp->conns[i] * best->weight == lcp->conns[p] * peer->weight) { many = 1; } } if (best == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least conn peer, no peer found"); goto failed; } if (many) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least conn peer, many"); for (i = p; i < peers->number; i++) { n = i / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); if (lcp->rrp.tried[n] & m) { continue; } peer = &peers->peer[i]; if (peer->down) { continue; } #if (NGX_HTTP_UPSTREAM_CHECK) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least_conn peer, check_index: %ui", peer->check_index); if (ngx_http_upstream_check_peer_down(peer->check_index)) { continue; } #endif if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) { continue; } if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) { continue; } peer->current_weight += peer->effective_weight; total += peer->effective_weight; if (peer->effective_weight < peer->weight) { peer->effective_weight++; } if (peer->current_weight > best->current_weight) { best = peer; p = i; } } } best->current_weight -= total; if (now - best->checked > best->fail_timeout) { best->checked = now; } pc->sockaddr = best->sockaddr; pc->socklen = best->socklen; pc->name = &best->name; pc->host = &best->host; pc->dyn_resolve = best->dyn_resolve; lcp->rrp.current = p; n = p / (8 * sizeof(uintptr_t)); m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); lcp->rrp.tried[n] |= m; lcp->conns[p]++; if (pc->tries == 1 && peers->next) { pc->tries += peers->next->number; } #if (NGX_HTTP_PERSISTENCE) ngx_http_upstream_ps_set(lcp->rrp.request, lcp->rrp.current, lcp->rrp.group); #endif return NGX_OK; failed: if (peers->next) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get least conn peer, backup servers"); lcp->conns += peers->number; lcp->rrp.peers = peers->next; pc->tries = lcp->rrp.peers->number; n = (lcp->rrp.peers->number + (8 * sizeof(uintptr_t) - 1)) / (8 * sizeof(uintptr_t)); for (i = 0; i < n; i++) { lcp->rrp.tried[i] = 0; } rc = ngx_http_upstream_get_least_conn_peer(pc, lcp); if (rc != NGX_BUSY) { return rc; } } /* all peers failed, mark them as live for quick recovery */ for (i = 0; i < peers->number; i++) { peers->peer[i].fails = 0; } pc->name = peers->name; return NGX_BUSY; }