From 4fbe4b62746f67d4348212c089b745bd10082964 Mon Sep 17 00:00:00 2001 From: Roman Semenov Date: Mon, 23 Mar 2026 11:03:26 -0700 Subject: Upstream: enabled keepalive by default for explicit upstreams. Keepalive is now automatically enabled in the "local" mode for upstreams defined in configuration files. Cached keepalive connections are no longer shared between different locations referencing the same explicit upstream unless keepalive is explicitly configured without the "local" parameter. To disable keepalive entirely, use keepalive 0; inside the upstream block. To allow sharing cached connections between locations, configure keepalive ; without the "local" parameter. --- .../modules/ngx_http_upstream_keepalive_module.c | 130 +++++++++++---------- 1 file changed, 67 insertions(+), 63 deletions(-) (limited to 'src/http/modules') diff --git a/src/http/modules/ngx_http_upstream_keepalive_module.c b/src/http/modules/ngx_http_upstream_keepalive_module.c index 11875ded8..121023e30 100644 --- a/src/http/modules/ngx_http_upstream_keepalive_module.c +++ b/src/http/modules/ngx_http_upstream_keepalive_module.c @@ -19,7 +19,6 @@ typedef struct { ngx_queue_t cache; ngx_queue_t free; - ngx_http_upstream_init_pt original_init_upstream; ngx_http_upstream_init_peer_pt original_init_peer; ngx_uint_t local; /* unsigned local:1; */ @@ -83,6 +82,8 @@ static void ngx_http_upstream_notify_keepalive_peer(ngx_peer_connection_t *pc, void *data, ngx_uint_t type); static void *ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf); +static char *ngx_http_upstream_keepalive_init_main_conf(ngx_conf_t *cf, + void *conf); static char *ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -126,7 +127,7 @@ static ngx_http_module_t ngx_http_upstream_keepalive_module_ctx = { NULL, /* postconfiguration */ NULL, /* create main configuration */ - NULL, /* init main configuration */ + ngx_http_upstream_keepalive_init_main_conf, /* init main configuration */ ngx_http_upstream_keepalive_create_conf, /* create server configuration */ NULL, /* merge server configuration */ @@ -152,52 +153,6 @@ ngx_module_t ngx_http_upstream_keepalive_module = { }; -static ngx_int_t -ngx_http_upstream_init_keepalive(ngx_conf_t *cf, - ngx_http_upstream_srv_conf_t *us) -{ - ngx_uint_t i; - ngx_http_upstream_keepalive_srv_conf_t *kcf; - ngx_http_upstream_keepalive_cache_t *cached; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, - "init keepalive"); - - kcf = ngx_http_conf_upstream_srv_conf(us, - ngx_http_upstream_keepalive_module); - - ngx_conf_init_msec_value(kcf->time, 3600000); - ngx_conf_init_msec_value(kcf->timeout, 60000); - ngx_conf_init_uint_value(kcf->requests, 1000); - - if (kcf->original_init_upstream(cf, us) != NGX_OK) { - return NGX_ERROR; - } - - kcf->original_init_peer = us->peer.init; - - us->peer.init = ngx_http_upstream_init_keepalive_peer; - - /* allocate cache items and add to free queue */ - - cached = ngx_pcalloc(cf->pool, - sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached); - if (cached == NULL) { - return NGX_ERROR; - } - - ngx_queue_init(&kcf->cache); - ngx_queue_init(&kcf->free); - - for (i = 0; i < kcf->max_cached; i++) { - ngx_queue_insert_head(&kcf->free, &cached[i].queue); - cached[i].conf = kcf; - } - - return NGX_OK; -} - - static ngx_int_t ngx_http_upstream_init_keepalive_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us) @@ -550,30 +505,89 @@ ngx_http_upstream_keepalive_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * - * conf->original_init_upstream = NULL; * conf->original_init_peer = NULL; - * conf->max_cached = 0; * conf->local = 0; */ conf->time = NGX_CONF_UNSET_MSEC; conf->timeout = NGX_CONF_UNSET_MSEC; conf->requests = NGX_CONF_UNSET_UINT; + conf->max_cached = NGX_CONF_UNSET_UINT; return conf; } +static char * +ngx_http_upstream_keepalive_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_uint_t i, j; + ngx_http_upstream_srv_conf_t **uscfp; + ngx_http_upstream_main_conf_t *umcf; + ngx_http_upstream_keepalive_cache_t *cached; + ngx_http_upstream_keepalive_srv_conf_t *kcf; + + umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + /* skip implicit upstreams */ + if (uscfp[i]->srv_conf == NULL) { + continue; + } + + kcf = ngx_http_conf_upstream_srv_conf(uscfp[i], + ngx_http_upstream_keepalive_module); + + if (kcf->max_cached == 0) { + continue; + } + + ngx_conf_init_msec_value(kcf->time, 3600000); + ngx_conf_init_msec_value(kcf->timeout, 60000); + ngx_conf_init_uint_value(kcf->requests, 1000); + + if (kcf->max_cached == NGX_CONF_UNSET_UINT) { + kcf->local = 1; + kcf->max_cached = 32; + } + + kcf->original_init_peer = uscfp[i]->peer.init; + + uscfp[i]->peer.init = ngx_http_upstream_init_keepalive_peer; + + /* allocate cache items and add to free queue */ + + cached = ngx_pcalloc(cf->pool, + sizeof(ngx_http_upstream_keepalive_cache_t) * kcf->max_cached); + if (cached == NULL) { + return NGX_CONF_ERROR; + } + + ngx_queue_init(&kcf->cache); + ngx_queue_init(&kcf->free); + + for (j = 0; j < kcf->max_cached; j++) { + ngx_queue_insert_head(&kcf->free, &cached[j].queue); + cached[j].conf = kcf; + } + } + + return NGX_CONF_OK; +} + + static char * ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_upstream_srv_conf_t *uscf; ngx_http_upstream_keepalive_srv_conf_t *kcf = conf; ngx_int_t n; ngx_str_t *value; - if (kcf->max_cached) { + if (kcf->max_cached != NGX_CONF_UNSET_UINT) { return "is duplicate"; } @@ -583,7 +597,7 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) n = ngx_atoi(value[1].data, value[1].len); - if (n == NGX_ERROR || n == 0) { + if (n == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\" in \"%V\" directive", &value[1], &cmd->name); @@ -603,15 +617,5 @@ ngx_http_upstream_keepalive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - /* init upstream handler */ - - uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); - - kcf->original_init_upstream = uscf->peer.init_upstream - ? uscf->peer.init_upstream - : ngx_http_upstream_init_round_robin; - - uscf->peer.init_upstream = ngx_http_upstream_init_keepalive; - return NGX_CONF_OK; } -- cgit