Cached vs Non-Cached DNS: A Lazy Experiment That Got Interesting

Search for a command to run...

No comments yet. Be the first to comment.
For those who don't know, Wayle is a project from the same creator as Hyprpanel, which is apparently going to be deprecated soon. Probably because of that, I couldn't find a proper theming guide anywh

Once you've spent years on an operating system, things soon start becoming stagnant. I hit that wall recently. I realized I'm spending most of my time at a full-time job, so I have very little time le

If you just want Thunar to work properly without digging into details, run: sudo pacman -S thunar gvfs tumbler ffmpegthumbnailer thunar-archive-plugin Optional (but useful): sudo pacman -S thunar-vol

What really happens when you run docker ps: from CLI to Kernel Internals

I was bored and just wanted to code something to spark the life, of course.
And, to fight it, my brain thought, "how fast really is my DNS provider?"
No architecture diagram. No benchmarking framework. No “this is how DNS testing should be done.” In fact, I didn’t even check how DNS benchmarking is usually done in the real world.
So, I casually started coding and end up with two scripts, and honestly, the results were way more interesting than I expected.
Before you even read further, I’d actually recommend:
👉 Go through the scripts
👉 Run them yourself
👉 Then come back
Repo: https://github.com/FlareXes/fastest-dns
Because, the results depend a lot on your network, your routing, your ISP… everything.
The idea was simple:
Take a few popular public DNS resolvers:
Cloudflare (1.1.1.1)
Google (8.8.8.8)
Quad9 (9.9.9.9)
Test them in two scenarios:
Cached DNS
Non-cached DNS
And measure:
Average latency
Median latency
P95 latency
No fancy tooling. Just Python + dig.
Before you get excited and hit run, a few things that can completely ruin your results:
First - Make Sure Nothing Is Overriding Your DNS
If you’re using tools like: VPNs, Custom DNS clients like Portmaster, or OS-level DNS overrides.
Then there’s a good chance your DNS queries are being intercepted or rerouted.
Even if your script says:
dig @1.1.1.1 example.com
Your system might still ignore that and use something else. If that happens, your results are basically fake. You’ll think you’re benchmarking Cloudflare but you’re not.
Second - Don’t Abuse Public DNS Servers (Seriously)
Don’t go wild with queries. These are public DNS services. Don’t hammer them with insane request rates.
The script already behaves nicely:
time.sleep(random.uniform(0.5, 1.0))
Keep it reasonable. Respect the service.
Third - You Can Tweak Everything
This isn’t a rigid benchmark. It’s more like a playground. You can change pretty much everything:
SERVERS = {
"Cloudflare": "1.1.1.1",
"Google": "8.8.8.8",
"Quad9": "9.9.9.9"
}
RUNS = 20
Want to:
Add your ISP’s DNS? Go ahead.
Increase runs to 100? Sure.
Change delays between queries? Do it.
Swap domains? Totally fine.
This is meant to be explored, not followed blindly.
Both scripts revolve around one simple idea, run dig, extract the query time.
Here’s the core piece:
def query_dns(server, domain):
result = subprocess.run(
["dig", f"@{server}", domain],
capture_output=True,
text=True
)
match = re.search(r"Query time: (\d+)", result.stdout)
return int(match.group(1)) if match else None
Second, I tracked Metrics that actually matters
Average (Looks Useful, Lies Sometimes)
Add everything and divide by number of runs
But here’s the problem:
If one or two queries spike hard (which happens in DNS), they can pull the average up significantly. So you might think: “This DNS is slow”.
When actually: 90% of queries were fast and 2 were just unlucky.
Median (What You Actually Experience Most of the Time)
It ignores extreme spikes. So if you want to know, what users usually experience how stable the resolver is.
P95 (Worst Case)
It tells you: “What do the slowest 5% of queries look like?”
I started with cached DNS.
The idea here is simple: query the same domain repeatedly and let the resolver cache do its job.
Here’s the key part of the script :
# Warm-up queries
for _ in range(3):
query_dns(ip, DOMAIN)
This primes the cache.
Without it:
First few queries would be slower (cold start)
Results would be inconsistent
After warm-up, every query hits cached data.
You cannot force public DNS resolvers to skip cache. So, I forced DNS resolver to miss the cache by generates a new long domain every time.
def random_domain():
name = ''.join(random.choices(string.ascii_lowercase + string.digits, k=12))
return f"{name}.com"
These domains are almost guaranteed to not exist
no cached answer exists
The resolver has to do full DNS resolution
It’s a bit hacky but it works surprisingly well.
Now the resolver has to actually do its job:
Ask root servers
Ask .com TLD servers
Ask authoritative servers
Each step adds: Network hops, Latency, Variability.
One thing I almost ignored, I added random delays between queries to:
prevent artificial bursts
avoid hammering servers
time.sleep(random.uniform(0.5, 1.0))
I don't any for this one, thanks for the reading.