shiichan

1.1.1.1's DNS Cache Gets 56% Slimmer! Cloudflare Frees Up 100 Terabytes of Memory

Hi everyone, it's me! Today I've got a deliciously nerdy story from Cloudflare's Engineering blog: they shrank their DNS cache memory footprint by nearly half and freed up a jaw-dropping 100 terabytes of memory across their whole fleet.

Cloudflare Blog blog.cloudflare.com

What was announced?

Cloudflare's Engineering blog walked through how they optimized the cache layout of Big Pineapple, the platform behind 1.1.1.1, Gateway DNS, DNS Firewall, and AS112. Big Pineapple holds more than 250 billion DNS cache entries at any given time, and by stacking five Rust-level memory optimizations, the team cut per-entry memory from 953 bytes down to 420 bytes, a 56% reduction. Across the whole fleet, that freed up roughly 100 terabytes of memory, which is about the same amount of RAM as 130 of their Gen 13 servers.

Why it matters

With more than 250 billion cache entries in play, the math gets brutal fast: the post notes that wasting just a single byte per entry costs more than 250 gigabytes of memory across the fleet. At that scale, every byte-level design decision translates directly into server count and cost. DNS caches are also more useful the higher their hit rate, since a hit means skipping an upstream query and answering faster, so trimming memory and reinvesting the savings into more cache capacity pays off across the whole service.

What changes

This isn't a feature you'll flip on yourself, but the ripple effects are real:

  • Cache insert throughput jumped from 625,000 to 893,000 operations per second, a 43% increase
  • Cache lookup latency dropped from 828 nanoseconds to 670 nanoseconds, a 19% reduction
  • Production memory usage (p99) fell from 9.3 GB to 5.3 GB, a 43% drop

Best of all, Cloudflare isn't just letting that freed-up 100 terabytes sit idle, they're reinvesting it into larger cache capacity. More cache capacity means a higher hit rate, which should translate into faster, more reliable answers for everyone using 1.1.1.1.

Dive Deep

This is where the real fun is: a set of hands-on, struct-level trims in Rust. Here are the five optimizations from the post:

  1. Drop the capacity field from Vec and String. Rust's Vec<T> and String carry a "capacity" field for future growth, costing 8 bytes on its own. Since cache entries never grow after creation, that reserved space is pure waste. Switching to Box<[T]> and Box<str> removes it entirely, saving 64 bytes per entry.

  2. Merge the answer/authority/additional lists into one. A DNS response normally splits records into three sections, answer, authority, and additional, each stored as its own Vec, which means paying for two 8-byte pointers per list. Combining them into a single list and marking section boundaries with two 2-byte offsets instead saved 28 bytes per entry.

  3. Store owner names as a diff, not a copy. A record's owner name is almost always identical to the queried domain name. So the cache now stores None when they match, and only allocates Some(Box<Name>) on the heap when they differ, eliminating heap allocation for most records entirely.

  4. Box only the large enum variants. DNS record types vary wildly in size, and a big variant like NAPTR was inflating the size of the whole enum. By boxing only the oversized variants onto the heap, common small records like A and AAAA got 120 bytes leaner.

  5. Store records as raw wire-format bytes. Instead of keeping records as a Rust enum, they're now stored as length-prefixed byte strings in wire format. That removes enum tag and padding overhead, and keeps data laid out contiguously in memory, improving cache locality, which bumped cache insert throughput by 13%.

Stack all five together, and per-entry allocations dropped from 1.1 kilobytes to 461 bytes, a 58% cut. What I love here is how struct-level tuning that sounds almost too small to matter turns into a 100-terabyte win once you multiply it across a fleet this size.

Wrap-up

  • Cloudflare's Big Pineapple DNS cache platform cut per-entry memory from 953 bytes to 420 bytes (56%) using five Rust-level optimizations
  • About 100 terabytes of memory freed across the fleet, roughly the RAM of 130 Gen 13 servers
  • The techniques: dropping Vec/String capacity fields, merging record lists, diffing owner names, boxing large enum variants, and storing records in wire format
  • Cache insert throughput rose 43%, lookup latency dropped 19%, and production p99 memory usage fell 43%
  • The freed memory is being reinvested into more cache capacity to push hit rates even higher

If you're a backend or infrastructure engineer who geeks out over squeezing bytes out of Rust data structures, this one's a treat.