← Все статьи

Cloudflare: 100 ТБ памяти за счёт раскладки DNS-кэша

Пять правок в Rust у Big Pineapple: Vec→Box, одна секция, wire-байты — −56% на запись и +43% к вставкам на 1.1.1.1.

Cloudflare: 100 ТБ памяти за счёт раскладки DNS-кэша
Содержание

Коротко

Платформа Big Pineapple за сервисами DNS Cloudflare (включая 1.1.1.1) держит свыше 250 млрд записей кэша. Пять последовательных правок раскладки в памяти на Rust срезали след одной записи больше чем вдвое — с 953 до 420 байт. По флоту это около 100 ТБ освобождённой оперативной памяти; вставка в кэш ускорилась на 43%, задержка чтения упала на 19%.

Что произошло

На холодном старте кэш пуст и заполняется запросами до лимита, после чего вытесняют менее популярные записи. При EDNS Client Subnet один и тот же запрос кэшируется в нескольких вариантах — и число записей, и цена байта растут.

Каждая запись — ключ (имя, тип, теги) и значение с секциями ответа плюс метаданные (TTL, счётчик попаданий). В продакшене почти не меняют уже сохранённый ответ, но типы вроде Vec<T> и String всё равно несут поле ёмкости и запас на куче. Замена на Box<[T]> / Box<str> убрала лишние восемь байт на поле и хвост аллокаций — порядка 15 ТБ на всём флоте.

Дальше три списка секций DNS свели в один с короткими смещениями u16: меньше указателей, меньше выравнивающего «воздуха». Владельца записи, совпадающего с запрошенным именем, перестали дублировать — его восстанавливают из ключа. Крупные варианты enum данных записи вынесли в кучу, затем вообще перешли к хранению полезной нагрузки сырыми байтами ответа в одном буфере: лучше локальность кэша процессора и меньше сериализации на пути ответа.

Почему это важно

На масштабе «байт на запись × сотни миллиардов» микрооптимизация структуры данных становится экономикой железа: 100 ТБ — это примерно 130 серверов поколения Gen 13 по оценке Cloudflare. При этом скорость не принесли в жертву: меньше аллокаций и плотнее память дали и экономию, и ускорение.

Для команд вне DNS урок тот же: профилируйте не только алгоритмы, но и «мёртвую» ёмкость контейнеров, выравнивание структур и размер enum по самому тяжёлому варианту. Замеры на синтетике (записи A, AAAA и TXT в долях, близких к трафику) плюс контроль резидентной памяти в продакшене после поэтапного выката — обязательная пара.

На практике

  1. Если объект после записи неизменяем — рассмотрите Box<[T]> / Box<str> вместо Vec / String.
  2. Несколько маленьких списков с одним жизненным циклом часто дешевле как один буфер со смещениями.
  3. У enum с редкими тяжёлыми вариантами проверьте, не платите ли вы размером редких крупных типов (в духе NAPTR) за каждую A-запись.
  4. Сырые байты ответа на горячем пути могут быть быстрее «красивого» разобранного дерева — если редкие типы всё ещё разбираете точечно.
  5. Катите по одной идее и смотрите 90-й и 99-й процентили резидентной памяти: на графике Cloudflare она падала ступенями с мая по июль 2026.

Итог

Cloudflare показал, как серия скучных на вид правок раскладки кэша даёт терабайты экономии без жертвы латентностью. Освобождённую память планируют вложить в больший объём кэша — меньше запросов вверх по иерархии DNS.