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.
This commit is contained in:
Mini Hawthorne 2023-07-12 12:20:45 -07:00 committed by Aleksei Bavshin
parent ea4654550a
commit 29aec5720f
4 changed files with 24 additions and 2 deletions

View File

@ -545,6 +545,8 @@ ngx_http_upstream_zone_preresolve(ngx_http_upstream_rr_peer_t *resolve,
peer->host = template->host; peer->host = template->host;
template->host->valid = host->valid;
server = template->host->service.len ? &opeer->server server = template->host->service.len ? &opeer->server
: &template->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 static ngx_int_t
ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle) ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
{ {
time_t now;
ngx_msec_t timer;
ngx_uint_t i; ngx_uint_t i;
ngx_event_t *event; ngx_event_t *event;
ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peer_t *peer;
@ -639,6 +643,7 @@ ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
return NGX_OK; return NGX_OK;
} }
now = ngx_time();
umcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_module); umcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_module);
if (umcf == NULL) { if (umcf == NULL) {
@ -674,7 +679,10 @@ ngx_http_upstream_zone_init_worker(ngx_cycle_t *cycle)
event->log = cycle->log; event->log = cycle->log;
event->cancelable = 1; 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); ngx_http_upstream_rr_peers_unlock(peers);
@ -983,6 +991,8 @@ again:
done: done:
host->valid = ctx->valid;
ngx_http_upstream_rr_peers_unlock(peers); ngx_http_upstream_rr_peers_unlock(peers);
while (++i < ctx->naddrs) { while (++i < ctx->naddrs) {

View File

@ -25,6 +25,7 @@ typedef struct {
ngx_uint_t worker; ngx_uint_t worker;
ngx_str_t name; ngx_str_t name;
ngx_str_t service; ngx_str_t service;
time_t valid;
ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_rr_peers_t *peers;
ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peer_t *peer;
} ngx_http_upstream_host_t; } ngx_http_upstream_host_t;

View File

@ -25,6 +25,7 @@ typedef struct {
ngx_uint_t worker; ngx_uint_t worker;
ngx_str_t name; ngx_str_t name;
ngx_str_t service; ngx_str_t service;
time_t valid;
ngx_stream_upstream_rr_peers_t *peers; ngx_stream_upstream_rr_peers_t *peers;
ngx_stream_upstream_rr_peer_t *peer; ngx_stream_upstream_rr_peer_t *peer;
} ngx_stream_upstream_host_t; } ngx_stream_upstream_host_t;

View File

@ -542,6 +542,8 @@ ngx_stream_upstream_zone_preresolve(ngx_stream_upstream_rr_peer_t *resolve,
peer->host = template->host; peer->host = template->host;
template->host->valid = host->valid;
server = template->host->service.len ? &opeer->server server = template->host->service.len ? &opeer->server
: &template->server; : &template->server;
@ -623,6 +625,8 @@ ngx_stream_upstream_zone_remove_peer_locked(
static ngx_int_t static ngx_int_t
ngx_stream_upstream_zone_init_worker(ngx_cycle_t *cycle) ngx_stream_upstream_zone_init_worker(ngx_cycle_t *cycle)
{ {
time_t now;
ngx_msec_t timer;
ngx_uint_t i; ngx_uint_t i;
ngx_event_t *event; ngx_event_t *event;
ngx_stream_upstream_rr_peer_t *peer; ngx_stream_upstream_rr_peer_t *peer;
@ -636,6 +640,7 @@ ngx_stream_upstream_zone_init_worker(ngx_cycle_t *cycle)
return NGX_OK; return NGX_OK;
} }
now = ngx_time();
umcf = ngx_stream_cycle_get_module_main_conf(cycle, umcf = ngx_stream_cycle_get_module_main_conf(cycle,
ngx_stream_upstream_module); ngx_stream_upstream_module);
@ -672,7 +677,10 @@ ngx_stream_upstream_zone_init_worker(ngx_cycle_t *cycle)
event->log = cycle->log; event->log = cycle->log;
event->cancelable = 1; 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); ngx_stream_upstream_rr_peers_unlock(peers);
@ -981,6 +989,8 @@ again:
done: done:
host->valid = ctx->valid;
ngx_stream_upstream_rr_peers_unlock(peers); ngx_stream_upstream_rr_peers_unlock(peers);
while (++i < ctx->naddrs) { while (++i < ctx->naddrs) {