Day 56 : Optimizing Unbound: Prefetch and Serve-Expired
Welcome back, fellow architects and engineers! Today, we’re peeling back another layer of Unbound, our robust DNS resolver. If you’ve been following along, you know Unbound is the bedrock of our secure home lab’s name resolution. But merely caching DNS records isn't enough when you're thinking at the scale of 100 million requests per second. At that velocity, every millisecond counts, and every potential cache miss is a tiny ripple that can become a wave of latency.
Today, we're diving deep into two Unbound directives that are absolutely critical for high-performance, resilient DNS resolution: prefetch and serve-expired. These aren't just "nice-to-haves"; they are fundamental architectural choices that separate a basic caching resolver from a production-grade, fault-tolerant workhorse.
The Unseen Challenge: Stale Caches and Upstream Failures
Imagine your application is serving millions of users. It relies on DNS to resolve microservice endpoints, database connections, and external APIs. A typical DNS cache works by storing records for a duration defined by their Time-To-Live (TTL). Once the TTL expires, the record is considered stale, and a new query must go upstream.
The Problem:
Cache Miss Spikes: If a popular record expires simultaneously across many clients or resolvers, a sudden "thundering herd" of requests can hit your upstream DNS servers. This is a common cause of performance degradation and even outages in large systems.
Upstream Unavailability: What if your authoritative DNS server or an intermediate resolver goes down? A standard caching resolver would simply fail to resolve, causing application outages until the upstream is restored.
These scenarios, while seemingly minor in a small lab, are catastrophic at scale. They lead to cascading failures, user frustration, and significant revenue loss for companies operating global services. This is where prefetch and serve-expired become your superpowers.
Core Concept: Proactive Caching with prefetch
prefetch is Unbound’s way of saying, "I see that record's TTL is running low. Before it expires and potentially causes a cache miss, I'm going to proactively refresh it in the background."
How it works:
When prefetch: yes is enabled, Unbound monitors the TTL of cached entries. As a record approaches its expiration (typically when its remaining TTL is less than 10% of its original TTL, or a configurable threshold), Unbound quietly initiates a query to refresh that record before it actually expires.
Control Flow: A client query comes in. Unbound checks its cache. If the record is found and its TTL is still valid but low, Unbound serves the existing (still fresh) record to the client immediately. Simultaneously, in the background, it dispatches a new query to the upstream server to fetch a fresh record.
Data Flow: The client gets fast, cached data. Unbound's background process updates the cache with the new data when it arrives.
State Changes: A cache entry transitions from
FRESHtoPREFETCHING(logically, though not always explicitly visible as a flag indump_cacheoutput, it's an internal state). Once the new data arrives, it reverts toFRESHwith the updated TTL.
Keep going with the full lesson
The rest of this lesson — plus its implementation guide, runnable scripts and source code — is included with the course or an All Access plan. Create a free account to start the free lessons in every course.
Already a member? Sign in