Critical health state propagation delay in Consul DNS
0 reputation · 06 Dec 2021, 00:47 UTC
0 reputation · 06 Dec 2021, 00:47 UTC
When migrating a small application to new infrastructure using Consul for service discovery, the goal is to achieve zero downtime by leveraging health checks to steer traffic. In this architecture, the Consul DNS interface is used to resolve healthy service instances.
A potential conflict arises when a service instance is marked as critical. While the Consul catalog updates rapidly via the gossip protocol, the propagation of this state to clients relying on DNS can be inconsistent due to caching layers at the OS or application level.
If the TTL of the DNS record is not aligned with the health check frequency, clients may continue to route traffic to a failing or decommissioned node despite the service being marked critical in the Consul UI.
critical health state without introducing excessive query overhead?34275 reputation · 06 Dec 2021, 03:09 UTC
Consul does not attach a per‑record TTL to its DNS responses; the TTL is governed by the agent’s dns_config block. By default Consul returns a TTL of 0 (no caching), so a change in health state becomes visible to a client as soon as the client’s resolver performs a new query after the health‑check result has been gossiped and the DNS record updated.
The observable delay between a service being marked critical in the UI and clients stopping to receive its address is bounded by:
10s).200‑300ms per round, converging in 2‑3s for a LAN cluster).If the DNS TTL is higher than 0, the resolver may keep using the stale A/AAAA record until that TTL expires, adding latency equal to the TTL value.
200ms, achieving cluster‑wide convergence in roughly 2‑3seconds.health check: service X changed status to critical and dns: updated service record; the timestamp difference approximates the propagation delay.To make clients react quickly to a critical state without generating excessive query traffic:
interval = "5s").0 or 1s, via the agent config:dns_config {
enable_truncate = false
allow_stale = false
default_ttl = "1s"
}
With default_ttl = "0s" (the default) the resolver queries Consul on every lookup, which adds negligible overhead for low‑QPS services but can increase load under high query rates; a 1s TTL caps the query rate to roughly one request per second per resolver while still keeping stale data under a second.
-log-level=debug).dig @127.0.0.1 -p 8600 service.consul) and record when the A record disappears.< health‑check interval + ~3s).consul info or by inspecting the agent’s dns_config block.Missing diagnostic detail: The exact health‑check interval and DNS TTL currently applied to the service. Knowing these values determines whether the observed delay is expected or indicates a misconfiguration that would change the recommendation.
Use comments to ask for clarification. Post a solution as an answer.
34,275 reputation · 06 Dec 2021, 09:04 UTC
While Consul agents typically return a TTL of 0 to prevent caching, it is important to distinguish between the resolver and the application. Even if the OS resolver honors the zero-TTL, many application runtimes implement their own internal DNS cache that ignores the record's TTL entirely.
A common example is the Java Virtual Machine (JVM), which by default may cache successful DNS lookups indefinitely (or for a very long duration) depending on the security manager configuration. In such environments, a service marked as critical in Consul will still receive traffic because the JVM never re-queries the DNS interface.
To verify if this is the bottleneck, you can compare the output of dig (which queries the resolver directly) against the application's routing behavior. If dig shows the failing node has been removed but the application still hits it, you must explicitly configure the application's network cache TTL (e.g., networkaddress.cache.ttl in Java) to a low value, such as 60 seconds or less.