[PATCH 7 of 9] Upstream: copy upstream zone DNS valid time during config reload
Roman Arutyunyan
arut at nginx.com
Mon Jul 8 15:06:29 UTC 2024
Hi,
On Thu, Jun 13, 2024 at 03:29:02PM -0700, Aleksei Bavshin wrote:
> # HG changeset patch
> # User Mini Hawthorne <mini at f5.com>
> # Date 1689189645 25200
> # Wed Jul 12 12:20:45 2023 -0700
> # Node ID 8c8d8118c7ac0a0426f48dbfed94e279dddff992
> # Parent 621ba257aeac3017ea83b24fafa201e07c1c7756
> 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
> @@ -443,6 +443,8 @@ ngx_http_upstream_zone_copy_peer(ngx_htt
> ngx_memcpy(dst->host->service.data, src->host->service.data,
> src->host->service.len);
> }
> +
> + dst->host->valid = src->host->valid;
> }
> }
>
> @@ -547,6 +549,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;
>
> @@ -694,6 +698,8 @@ ngx_http_upstream_zone_init_worker(ngx_c
> static void
> ngx_http_upstream_zone_resolve_timer(ngx_event_t *event)
> {
> + time_t now, valid;
> + ngx_msec_t timer;
> ngx_resolver_ctx_t *ctx;
> ngx_http_upstream_host_t *host;
> ngx_http_upstream_rr_peer_t *template;
> @@ -705,6 +711,9 @@ ngx_http_upstream_zone_resolve_timer(ngx
> peers = host->peers;
> template = host->peer;
>
> + now = ngx_time();
> + valid = host->valid;
> +
> if (template->zombie) {
> (void) ngx_http_upstream_rr_peer_unref(peers, template);
>
> @@ -721,6 +730,10 @@ ngx_http_upstream_zone_resolve_timer(ngx
> return;
> }
>
> + if (valid > now) {
> + goto retry;
> + }
> +
> ctx = ngx_resolve_start(uscf->resolver, NULL);
> if (ctx == NULL) {
> goto retry;
> @@ -745,7 +758,11 @@ ngx_http_upstream_zone_resolve_timer(ngx
>
> retry:
>
> - ngx_add_timer(event, ngx_max(uscf->resolver_timeout, 1000));
> + /* don't delay zombie cleanup longer than resolver_timeout */
> + timer = (ngx_msec_t) 1000 * (valid > now ? valid - now + 1 : 1);
> + timer = ngx_min(timer, uscf->resolver_timeout);
In open source nginx we have no zombies to clean up, which means
1. the comment above should be removed
2. when valid > now, we should wait exactly (valid - now)
Probably it's easier to leave this code as is and add a separate ngx_add_timer()
to the block above.
An even better solution is to schedule the right timeout in
ngx_http_upstream_zone_init_worker() for the case when valid > now instead of 1.
> +
> + ngx_add_timer(event, ngx_max(timer, 1000));
> }
>
>
> @@ -1026,6 +1043,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
> @@ -544,6 +544,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;
>
> @@ -692,6 +694,8 @@ ngx_stream_upstream_zone_init_worker(ngx
> static void
> ngx_stream_upstream_zone_resolve_timer(ngx_event_t *event)
> {
> + time_t now, valid;
> + ngx_msec_t timer;
> ngx_resolver_ctx_t *ctx;
> ngx_stream_upstream_host_t *host;
> ngx_stream_upstream_rr_peer_t *template;
> @@ -703,6 +707,9 @@ ngx_stream_upstream_zone_resolve_timer(n
> peers = host->peers;
> template = host->peer;
>
> + now = ngx_time();
> + valid = host->valid;
> +
> if (template->zombie) {
> (void) ngx_stream_upstream_rr_peer_unref(peers, template);
>
> @@ -719,6 +726,10 @@ ngx_stream_upstream_zone_resolve_timer(n
> return;
> }
>
> + if (valid > now) {
> + goto retry;
> + }
> +
> ctx = ngx_resolve_start(uscf->resolver, NULL);
> if (ctx == NULL) {
> goto retry;
> @@ -743,7 +754,11 @@ ngx_stream_upstream_zone_resolve_timer(n
>
> retry:
>
> - ngx_add_timer(event, ngx_max(uscf->resolver_timeout, 1000));
> + /* don't delay zombie cleanup longer than resolver_timeout */
> + timer = (ngx_msec_t) 1000 * (valid > now ? valid - now + 1 : 1);
> + timer = ngx_min(timer, uscf->resolver_timeout);
> +
>Here + ngx_add_timer(event, ngx_max(timer, 1000));
Same here.
> }
>
>
> @@ -1024,6 +1039,8 @@ again:
>
> done:
>
> + host->valid = ctx->valid;
> +
> ngx_stream_upstream_rr_peers_unlock(peers);
>
> while (++i < ctx->naddrs) {
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> https://mailman.nginx.org/mailman/listinfo/nginx-devel
--
Roman Arutyunyan
More information about the nginx-devel
mailing list