Upstream: limited next_upstream time and tries (ticket #544).

The new directives {proxy,fastcgi,scgi,uwsgi,memcached}_next_upstream_tries
and {proxy,fastcgi,scgi,uwsgi,memcached}_next_upstream_timeout limit
the number of upstreams tried and the maximum time spent for these tries
when searching for a valid upstream.
This commit is contained in:
Roman Arutyunyan 2014-09-12 18:50:47 +04:00
parent cfc3db1972
commit 02ce6c415f
8 changed files with 127 additions and 2 deletions

View File

@ -42,6 +42,7 @@ struct ngx_peer_connection_s {
ngx_str_t *name;
ngx_uint_t tries;
ngx_msec_t start_time;
ngx_event_get_peer_pt get;
ngx_event_free_peer_pt free;

View File

@ -442,6 +442,20 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
&ngx_http_fastcgi_next_upstream_masks },
{ ngx_string("fastcgi_next_upstream_tries"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_tries),
NULL },
{ ngx_string("fastcgi_next_upstream_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_timeout),
NULL },
{ ngx_string("fastcgi_param"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
ngx_http_upstream_param_set_slot,
@ -2314,6 +2328,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store = NGX_CONF_UNSET;
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
@ -2322,6 +2337,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
@ -2387,6 +2403,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->upstream.store_access,
prev->upstream.store_access, 0600);
ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
prev->upstream.next_upstream_tries, 0);
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
@ -2405,6 +2424,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.read_timeout,
prev->upstream.read_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
prev->upstream.next_upstream_timeout, 0);
ngx_conf_merge_size_value(conf->upstream.send_lowat,
prev->upstream.send_lowat, 0);

View File

@ -102,6 +102,20 @@ static ngx_command_t ngx_http_memcached_commands[] = {
offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
&ngx_http_memcached_next_upstream_masks },
{ ngx_string("memcached_next_upstream_tries"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream_tries),
NULL },
{ ngx_string("memcached_next_upstream_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream_timeout),
NULL },
{ ngx_string("memcached_gzip_flag"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
@ -583,9 +597,11 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
*/
conf->upstream.local = NGX_CONF_UNSET_PTR;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
@ -619,6 +635,9 @@ ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_ptr_value(conf->upstream.local,
prev->upstream.local, NULL);
ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
prev->upstream.next_upstream_tries, 0);
ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
prev->upstream.connect_timeout, 60000);
@ -628,6 +647,9 @@ ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.read_timeout,
prev->upstream.read_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
prev->upstream.next_upstream_timeout, 0);
ngx_conf_merge_size_value(conf->upstream.buffer_size,
prev->upstream.buffer_size,
(size_t) ngx_pagesize);

View File

@ -505,6 +505,20 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
&ngx_http_proxy_next_upstream_masks },
{ ngx_string("proxy_next_upstream_tries"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries),
NULL },
{ ngx_string("proxy_next_upstream_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout),
NULL },
{ ngx_string("proxy_pass_header"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_array_slot,
@ -2455,6 +2469,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store = NGX_CONF_UNSET;
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
@ -2463,6 +2478,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
@ -2543,6 +2559,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->upstream.store_access,
prev->upstream.store_access, 0600);
ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
prev->upstream.next_upstream_tries, 0);
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
@ -2561,6 +2580,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.read_timeout,
prev->upstream.read_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
prev->upstream.next_upstream_timeout, 0);
ngx_conf_merge_size_value(conf->upstream.send_lowat,
prev->upstream.send_lowat, 0);

View File

@ -299,6 +299,20 @@ static ngx_command_t ngx_http_scgi_commands[] = {
offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream),
&ngx_http_scgi_next_upstream_masks },
{ ngx_string("scgi_next_upstream_tries"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_tries),
NULL },
{ ngx_string("scgi_next_upstream_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_timeout),
NULL },
{ ngx_string("scgi_param"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
ngx_http_upstream_param_set_slot,
@ -1074,6 +1088,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store = NGX_CONF_UNSET;
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
@ -1082,6 +1097,7 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
@ -1142,6 +1158,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->upstream.store_access,
prev->upstream.store_access, 0600);
ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
prev->upstream.next_upstream_tries, 0);
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
@ -1160,6 +1179,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.read_timeout,
prev->upstream.read_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
prev->upstream.next_upstream_timeout, 0);
ngx_conf_merge_size_value(conf->upstream.send_lowat,
prev->upstream.send_lowat, 0);

View File

@ -354,6 +354,20 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream),
&ngx_http_uwsgi_next_upstream_masks },
{ ngx_string("uwsgi_next_upstream_tries"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream_tries),
NULL },
{ ngx_string("uwsgi_next_upstream_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream_timeout),
NULL },
{ ngx_string("uwsgi_param"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
ngx_http_upstream_param_set_slot,
@ -1254,6 +1268,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.store = NGX_CONF_UNSET;
conf->upstream.store_access = NGX_CONF_UNSET_UINT;
conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
@ -1262,6 +1277,7 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
@ -1329,6 +1345,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->upstream.store_access,
prev->upstream.store_access, 0600);
ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
prev->upstream.next_upstream_tries, 0);
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
@ -1347,6 +1366,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->upstream.read_timeout,
prev->upstream.read_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
prev->upstream.next_upstream_timeout, 0);
ngx_conf_merge_size_value(conf->upstream.send_lowat,
prev->upstream.send_lowat, 0);

View File

@ -698,6 +698,14 @@ found:
return;
}
u->peer.start_time = ngx_current_msec;
if (u->conf->next_upstream_tries
&& u->peer.tries > u->conf->next_upstream_tries)
{
u->peer.tries = u->conf->next_upstream_tries;
}
ngx_http_upstream_connect(r, u);
}
@ -3421,6 +3429,7 @@ static void
ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
ngx_uint_t ft_type)
{
ngx_msec_t timeout;
ngx_uint_t status, state;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@ -3490,9 +3499,12 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
if (status) {
u->state->status = status;
timeout = u->conf->next_upstream_timeout;
if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {
if (u->peer.tries == 0
|| !(u->conf->next_upstream & ft_type)
|| (timeout && ngx_current_msec - u->peer.start_time >= timeout))
{
#if (NGX_HTTP_CACHE)
if (u->cache_status == NGX_HTTP_CACHE_EXPIRED

View File

@ -136,6 +136,7 @@ typedef struct {
ngx_msec_t send_timeout;
ngx_msec_t read_timeout;
ngx_msec_t timeout;
ngx_msec_t next_upstream_timeout;
size_t send_lowat;
size_t buffer_size;
@ -153,6 +154,7 @@ typedef struct {
ngx_uint_t ignore_headers;
ngx_uint_t next_upstream;
ngx_uint_t store_access;
ngx_uint_t next_upstream_tries;
ngx_flag_t buffering;
ngx_flag_t pass_request_headers;
ngx_flag_t pass_request_body;