[nginx] Upstream: copy upstream zone DNS valid time during config reload.

noreply at nginx.com noreply at nginx.com
Thu Nov 7 15:58:03 UTC 2024


details:   https://github.com/nginx/nginx/commit/29aec5720fdfc74dca8d99d5cf6dc0fcb4e4ce2f
branches:  master
commit:    29aec5720fdfc74dca8d99d5cf6dc0fcb4e4ce2f
user:      Mini Hawthorne <mini at f5.com>
date:      Wed, 12 Jul 2023 12:20:45 -0700
description:
Upstream: copy upstream zone DNS valid time during config reload.

Previously, all upstream DNS entries would be immediately re-resolved
on config reload.  With a large number of upstreams, this creates
a spike of DNS resolution requests.  These spikes can overwhelm the
DNS server or cause drops on the network.

This patch retains the TTL of previous resolutions across reloads
by copying each upstream's name's expiry time across configuration
cycles.  As a result, no additional resolutions are needed.
---
 src/http/modules/ngx_http_upstream_zone_module.c | 12 +++++++++++-
 src/http/ngx_http_upstream_round_robin.h         |  1 +
 src/stream/ngx_stream_upstream_round_robin.h     |  1 +
 src/stream/ngx_stream_upstream_zone_module.c     | 12 +++++++++++-
 4 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c
index c1931a8bb..2ce8a7b5b 100644
--- a/src/http/modules/ngx_http_upstream_zone_module.c
+++ b/src/http/modules/ngx_http_upstream_zone_module.c
@@ -545,6 +545,8 @@ ngx_http_upstream_zone_preresolve(ngx_http_upstream_rr_peer_t *resolve,
 
                 peer->host = template->host;
 
+                template->host->valid = host->valid;
+
                 server = template->host->service.len ? &opeer->server
                                                      : &template->server;
 
@@ -626,6 +628,8 @@ ngx_http_upstream_zone_remove_peer_locked(ngx_http_upstream_rr_peers_t *peers,
 static ngx_int_t
 ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
 {
+    time_t                          now;
+    ngx_msec_t                      timer;
     ngx_uint_t                      i;
     ngx_event_t                    *event;
     ngx_http_upstream_rr_peer_t    *peer;
@@ -639,6 +643,7 @@ ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
         return NGX_OK;
     }
 
+    now = ngx_time();
     umcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_module);
 
     if (umcf == NULL) {
@@ -674,7 +679,10 @@ ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
                 event->log = cycle->log;
                 event->cancelable = 1;
 
-                ngx_add_timer(event, 1);
+                timer = (peer->host->valid > now)
+                        ? (ngx_msec_t) 1000 * (peer->host->valid - now) : 1;
+
+                ngx_add_timer(event, timer);
             }
 
             ngx_http_upstream_rr_peers_unlock(peers);
@@ -983,6 +991,8 @@ again:
 
 done:
 
+    host->valid = ctx->valid;
+
     ngx_http_upstream_rr_peers_unlock(peers);
 
     while (++i < ctx->naddrs) {
diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
index 084b0b886..2f0a51cdf 100644
--- a/src/http/ngx_http_upstream_round_robin.h
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -25,6 +25,7 @@ typedef struct {
     ngx_uint_t                      worker;
     ngx_str_t                       name;
     ngx_str_t                       service;
+    time_t                          valid;
     ngx_http_upstream_rr_peers_t   *peers;
     ngx_http_upstream_rr_peer_t    *peer;
 } ngx_http_upstream_host_t;
diff --git a/src/stream/ngx_stream_upstream_round_robin.h b/src/stream/ngx_stream_upstream_round_robin.h
index 707a9889d..c168bfe80 100644
--- a/src/stream/ngx_stream_upstream_round_robin.h
+++ b/src/stream/ngx_stream_upstream_round_robin.h
@@ -25,6 +25,7 @@ typedef struct {
     ngx_uint_t                       worker;
     ngx_str_t                        name;
     ngx_str_t                        service;
+    time_t                           valid;
     ngx_stream_upstream_rr_peers_t  *peers;
     ngx_stream_upstream_rr_peer_t   *peer;
 } ngx_stream_upstream_host_t;
diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c
index d92609feb..a6874dc33 100644
--- a/src/stream/ngx_stream_upstream_zone_module.c
+++ b/src/stream/ngx_stream_upstream_zone_module.c
@@ -542,6 +542,8 @@ ngx_stream_upstream_zone_preresolve(ngx_stream_upstream_rr_peer_t *resolve,
 
                 peer->host = template->host;
 
+                template->host->valid = host->valid;
+
                 server = template->host->service.len ? &opeer->server
                                                      : &template->server;
 
@@ -623,6 +625,8 @@ ngx_stream_upstream_zone_remove_peer_locked(
 static ngx_int_t
 ngx_stream_upstream_zone_init_worker(ngx_cycle_t *cycle)
 {
+    time_t                            now;
+    ngx_msec_t                        timer;
     ngx_uint_t                        i;
     ngx_event_t                      *event;
     ngx_stream_upstream_rr_peer_t    *peer;
@@ -636,6 +640,7 @@ ngx_stream_upstream_zone_init_worker(ngx_cycle_t *cycle)
         return NGX_OK;
     }
 
+    now = ngx_time();
     umcf = ngx_stream_cycle_get_module_main_conf(cycle,
                                                  ngx_stream_upstream_module);
 
@@ -672,7 +677,10 @@ ngx_stream_upstream_zone_init_worker(ngx_cycle_t *cycle)
                 event->log = cycle->log;
                 event->cancelable = 1;
 
-                ngx_add_timer(event, 1);
+                timer = (peer->host->valid > now)
+                        ? (ngx_msec_t) 1000 * (peer->host->valid - now) : 1;
+
+                ngx_add_timer(event, timer);
             }
 
             ngx_stream_upstream_rr_peers_unlock(peers);
@@ -981,6 +989,8 @@ again:
 
 done:
 
+    host->valid = ctx->valid;
+
     ngx_stream_upstream_rr_peers_unlock(peers);
 
     while (++i < ctx->naddrs) {


More information about the nginx-devel mailing list