]> git.kaiwu.me - nginx.git/commitdiff
Upstream: enabled keepalive by default for explicit upstreams.
authorRoman Semenov <r.semenov@f5.com>
Mon, 23 Mar 2026 18:03:26 +0000 (11:03 -0700)
committerRoman Arutyunyan <arutyunyan.roman@gmail.com>
Tue, 24 Mar 2026 10:28:52 +0000 (14:28 +0400)
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 <max_cached>; without the "local" parameter.

src/http/modules/ngx_http_upstream_keepalive_module.c

index 11875ded811080362982197fac842daab2c1b10d..121023e30be3112debc7876d047070104cbd2c73 100644 (file)
@@ -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;
 }