[PATCH 6 of 7] Upstream: copy upstream zone DNS valid time during config reload

Aleksei Bavshin a.bavshin at nginx.com
Thu Jul 18 18:20:43 UTC 2024


# HG changeset patch
# User Mini Hawthorne <mini at f5.com>
# Date 1689189645 25200
#      Wed Jul 12 12:20:45 2023 -0700
# Node ID b396d0c2c62c796c76921dcf20960f8ba2515aba
# Parent  20cc5e474a0bff2bc1fadcc73aae61384f8eefbd
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.

diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c
--- 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_ht
 
                 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_locke
 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_c
         return NGX_OK;
     }
 
+    now = ngx_time();
     umcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_module);
 
     if (umcf == NULL) {
@@ -670,7 +675,10 @@ ngx_http_upstream_zone_init_worker(ngx_c
                 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);
@@ -979,6 +987,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
--- 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
--- 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
--- 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_
 
                 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_loc
 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
         return NGX_OK;
     }
 
+    now = ngx_time();
     umcf = ngx_stream_cycle_get_module_main_conf(cycle,
                                                  ngx_stream_upstream_module);
 
@@ -668,7 +673,10 @@ ngx_stream_upstream_zone_init_worker(ngx
                 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);
@@ -977,6 +985,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