TECHNOLOGY / DNS CACHE
We Implemented a Cache. Then Required a Meeting Before Every Read.
We confirmed it yesterday. Today, we confirm it again.
We recorded the decision last week. This week, we start with the background.
Sometimes a fresh check is exactly what we need. But when the conditions have not changed and there is no new information, what are we checking again?

Answers need rules for reuse
I recently built tiny-dns-router, an experimental local DNS forwarding service in Python. It routes queries to configured upstream servers based on domain suffixes.
One of the questions I explored was caching.
Ask an upstream server for a domain’s IP address, receive an answer, then ask the same question a few seconds later. If that answer is still eligible for reuse, the service can use its cache rather than ask upstream again.
Of course, having an answer does not mean keeping it forever.
DNS uses a time to live, or TTL, to limit how long a cached response can be reused. That is a reuse window, not a guarantee that the data is still current or correct.
Some company org charts make the distinction easy to appreciate. Current on Friday. Historical by Monday.
Cache benefits in repeated queries
For the experiment, I compared caching enabled and disabled on native macOS loopback, using controlled upstream servers configured with a 6 ms delay.
In the repeated-query UDP workload, each trial started with an empty cache and followed a planned schedule of 120 queries, one every 3 ms. Four query keys were reused, covering both positive and negative responses.
Each mode ran three trials. Taking the median of the three per-trial p50 latencies gave:
Cache disabled: 7.33 ms.
Cache enabled: 0.69 ms.
Latency runs from the client’s actual query invocation through response validation. It excludes waiting for the scheduled invocation.
The median upstream query count also fell from 120 to 4 per trial.
For this repeated workload, reusing answers reduced upstream work and query latency. With unique queries, the benefit was limited.
The cache did not make every DNS query faster. It helped when a reusable answer was actually available.
A negative answer is different from no answer
I also implemented negative caching: temporarily retaining qualifying negative answers, such as an upstream response saying a domain does not exist.
An upstream server saying “it does not exist” and one saying nothing are different outcomes.
Confuse the two, and an unanswered call to Finance becomes proof that Finance no longer exists.
That is not negative caching. That is a reorganization.
Timeouts, transport errors and valid negative answers need different handling. Failing to obtain an answer is not a reason to manufacture a definitive one.
Measurement scope, resource limits and failures
The service also includes UDP/TCP forwarding, suffix-based routing, cache capacity limits and upstream failover on timeouts and other qualifying failures.
Answering a normal query is only part of the job. Expiration, resource limits and upstream failure are part of the behavior too.
Native macOS and Linux in Colima each passed the same 40 tests. Across both platforms, the retained results include 72 trials and 8,640 correct responses.
The scope matters. These fixed-load results do not establish maximum throughput. Loopback is not the Internet, and the Colima Linux measurements are reported separately from native macOS.
This is an experimental service, not a production resolver. It does not perform DNSSEC validation. Its cache limits bound entry count and stored response bytes, not total process RAM.
For me, the useful part was bringing routing policy, reuse rules, resource limits and failure handling together in something I could test and measure.
Teams need rules for reusing answers
There is a related question for teams:
When can we act on an answer we already have?
Changed conditions, expired information or higher decision risk may justify checking again. But we also need to know who maintains the answer, what invalidates it, when revalidation is required, and who can proceed under an existing decision when nothing material has changed.
A knowledge base gives us somewhere to keep answers. We still need clear rules for using them.
Otherwise, we write the documents, maintain the FAQ and record the decisions. Then someone asks:
“Have we dealt with this before?”
“Yes. The full record is in the knowledge base.”
“Great. Let’s schedule a meeting to confirm it.”
We have a cache. Every read just needs another meeting.
In practice, the TTL might as well be zero.
Original project code and documentation are MIT licensed. Third-party dependencies retain their own licenses.
#SystemsEngineering #Networking #DNS #Python