From af4bcd8f94a6af1288cfd8887a7cdc3412d03dc0 Mon Sep 17 00:00:00 2001 From: Kirill A. Korinskiy Date: Sun, 15 Feb 2009 21:48:51 +0300 Subject: [PATCH 1/1] Implement `upstream_count_limit limiting' for normal servers only Cc: catap@catap.ru If set `upstream_count_limit' to two and have 3 servers (two normal and one marked as backup) the request has been sent only to first two server. I do not sure about necessity limiting count of backup servers to send one request. Now send request to no more `upstream_count_limit' servers and all backup servers. --- .../modules/ngx_http_upstream_ip_hash_module.c | 3 + src/http/ngx_http_upstream.c | 57 +++++++++++++++++++- src/http/ngx_http_upstream.h | 3 + src/http/ngx_http_upstream_round_robin.c | 17 ++++++ src/http/ngx_http_upstream_round_robin.h | 2 + 5 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c index dffbf22b28f2970533ca465a09631433974cbbe1..f33390bcb4f278a695b79259041cec9436cafaa3 100644 --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -101,6 +101,9 @@ ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r, return NGX_ERROR; } + iphp->rrp.u = r->upstream; + iphp->rrp.peers_is_backup = 0; + r->upstream->peer.data = &iphp->rrp; if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 5458a58166415a3c9a60ab865648b988c3660bf1..490b5bc63c8836cbaeb1a1aa0079d8acbdc3ce2a 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -9,6 +9,11 @@ #include +typedef struct { + ngx_uint_t count_limit; +} ngx_http_upstream_local_conf_t; + + static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx); static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r); static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); @@ -106,6 +111,10 @@ static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf); static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf); +static void *ngx_http_upstream_create_local_conf(ngx_conf_t *cf); +static char *ngx_http_upstream_merge_local_conf(ngx_conf_t *cf, + void *parent, void *child); + #if (NGX_HTTP_SSL) static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *, ngx_http_upstream_t *u, ngx_connection_t *c); @@ -249,6 +258,14 @@ static ngx_command_t ngx_http_upstream_commands[] = { 0, NULL }, + { ngx_string("upstream_count_limit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_FLAG, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_upstream_local_conf_t, count_limit), + NULL }, + ngx_null_command }; @@ -263,8 +280,8 @@ static ngx_http_module_t ngx_http_upstream_module_ctx = { NULL, /* create server configuration */ NULL, /* merge server configuration */ - NULL, /* create location configuration */ - NULL /* merge location configuration */ + ngx_http_upstream_create_local_conf, /* create location configuration */ + ngx_http_upstream_merge_local_conf /* merge location configuration */ }; @@ -327,6 +344,9 @@ ngx_http_upstream_init(ngx_http_request_t *r) ngx_http_core_loc_conf_t *clcf; ngx_http_upstream_srv_conf_t *uscf, **uscfp; ngx_http_upstream_main_conf_t *umcf; + ngx_http_upstream_local_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_upstream_module); c = r->connection; @@ -344,6 +364,11 @@ ngx_http_upstream_init(ngx_http_request_t *r) r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; } + if (conf->count_limit) { + u->count_limit = conf->count_limit; + u->count_limit_origin = conf->count_limit; + } + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { if (!c->write->active) { @@ -3782,3 +3807,31 @@ ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf) return NGX_CONF_OK; } + + +static void * +ngx_http_upstream_create_local_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_local_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_local_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->count_limit = NGX_CONF_UNSET_UINT; + + return conf; +} + +static char * +ngx_http_upstream_merge_local_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_upstream_local_conf_t *prev = parent; + ngx_http_upstream_local_conf_t *conf = child; + + ngx_conf_merge_uint_value(conf->count_limit, + prev->count_limit, 0); + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 3c141276da12bc3a7e139f6803aa384755eb3bd8..c2faeadc99155e7aa93ec15b32b58059d9126233 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -273,6 +273,9 @@ struct ngx_http_upstream_s { ngx_http_cleanup_pt *cleanup; + ngx_flag_t count_limit; + ngx_uint_t count_limit_origin; + unsigned store:1; unsigned cacheable:1; unsigned accel:1; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c index 52bd80858d172156330b148af14bba3779a5bbf9..088d3f10ea26af586ed2cee70a3fb92f4bd691f4 100644 --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -214,6 +214,8 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, } r->upstream->peer.data = rrp; + rrp->u = r->upstream; + rrp->peers_is_backup = 0; } rrp->peers = us->peer.data; @@ -267,6 +269,8 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, } r->upstream->peer.data = rrp; + rrp->u = r->upstream; + rrp->peers_is_backup = 0; } peers = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_rr_peers_t) @@ -371,6 +375,17 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) now = ngx_time(); + if (!rrp->peers_is_backup && + rrp->u->count_limit_origin && + rrp->u->count_limit == 0) { + ngx_log_error(NGX_LOG_INFO, pc->log, 0, + "http next upstream limited by upstream_count_limit %d ", + rrp->u->count_limit_origin); + goto failed; + } else if (rrp->u->count_limit) { + rrp->u->count_limit--; + } + /* ngx_lock_mutex(rrp->peers->mutex); */ if (rrp->peers->last_cached) { @@ -547,6 +562,8 @@ failed: rrp->peers = peers->next; pc->tries = rrp->peers->number; + rrp->peers_is_backup = 1; + n = rrp->peers->number / (8 * sizeof(uintptr_t)) + 1; for (i = 0; i < n; i++) { rrp->tried[i] = 0; diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h index 221315491e3d9a063015055ac84682c1b5f5468e..0546ef23553b2f7d57b0ba79ada6bc0340f8f1aa 100644 --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -58,6 +58,8 @@ typedef struct { ngx_uint_t current; uintptr_t *tried; uintptr_t data; + ngx_http_upstream_t *u; + ngx_uint_t peers_is_backup; } ngx_http_upstream_rr_peer_data_t; -- 1.5.6.5