Cloudflare объявила о результатах серии низкоуровневых оптимизаций DNS-хранилища на платформе Big Pineapple — платформе, на которой работают 1.1.1.1, Gateway DNS, DNS Firewall, AS112 и ряд других DNS-сервисов. Платформа одновременно хранит более 250 миллиардов записей DNS, поэтому устранение одного байта на запись экономит более 250 гигабайт памяти во всём парке.
Пять последовательных изменений в структуре данных, написанной на Rust, сократили размер одной записи с 953 до 420 байт, то есть на 56%. После внедрения изменений резидентная память, используемая во всём парке Cloudflare, сократилась примерно на 100 ТБ, при этом производительность выросла, а не снизилась: скорость вставки записей увеличилась на 43%, а время поиска в хранилище уменьшилось на 19%.
Почему размер записи DNS имел значение?
Big Pineapple запускается с пустым хранилищем, которое затем заполняется по мере поступления запросов, пока не достигает максимального размера; после этого удаляются самые старые или наименее используемые записи. Размер хранилища различается между центрами обработки данных, а использование EDNS Client Subnet может приводить к хранению нескольких ответов на один и тот же запрос, поскольку авторитетные серверы могут выдавать разные ответы в зависимости от сети клиента.
Каждая запись состоит из ключа, определяющего имя домена, тип записи и некоторые атрибуты, а также значения, содержащего ответ DNS, разделы authority и additional и метаданные, такие как время создания, счётчик использований и значение TTL. При таком масштабе лишние поля или зарезервированное пространство перестают быть мелкими внутренними деталями и превращаются в огромные эксплуатационные затраты.
Откуда взялась экономия?
Cloudflare заменила структуры Vec и String, допускающие расширение, на структуры фиксированного размера Box<[T]> и Box<str> после сохранения ответа, поскольку данные впоследствии не изменяются. Это изменение устранило поле ёмкости, которое хранят расширяемые структуры, а также ограничило объём неиспользуемого зарезервированного пространства. Поскольку каждая запись содержит восемь полей такого типа, экономия составила 64 байта на запись и более 15 ТБ во всём хранилище.
Кроме того, списки разделов answer, authority и additional были объединены в один список с использованием смещений типа u16 вместо более крупных указателей и длин. Это позволило сэкономить 28 байт на запись. Структура также использовала упаковку нескольких логических полей в один bitflag, что уменьшило потери пространства из-за выравнивания памяти, которое Rust применяет внутри структур.
В большинстве записей DNS владелец записи совпадает с доменом, для которого выполнялся запрос. Поэтому Cloudflare перестала хранить полное имя владельца в таких случаях и восстанавливает его из ключа хранилища при формировании ответа. Если имя отличается, как в случае записей CNAME, хранится полное имя. Благодаря этому для большинства имён владельцев исключены операции выделения памяти, при этом случаи, действительно требующие имени, сохранены.
Снижение стоимости крупных типов записей
Структура RecordData использовала enum размером с самый крупный тип записи — NAPTR, занимавший 144 байта после учёта тега и выравнивания. В результате записи A, которым требуется всего 4 байта, и записи AAAA, которым требуется 16 байт, занимали намного больше пространства, чем необходимо, хотя A и AAAA составляли более 80% тестового трафика.
Было опробовано размещение крупных типов в отдельном Box, что уменьшало потери для записей A и AAAA, но добавляло отдельные выделения памяти и проблемы с locality памяти. Окончательным решением стало хранение самих данных записей в виде расположенных подряд необработанных байтов внутри Box<[u8]> с двухбайтовым префиксом длины для каждой записи. Это устранило стоимость enum и множественных выделений, а также улучшило использование процессором кэш-памяти.
Такой выбор означает, что записи больше нельзя индексировать произвольно: их необходимо обрабатывать последовательно. Cloudflare считает затраты ограниченными, поскольку количество записей в одной записи хранилища невелико. Кроме того, большинство типов, включая A, AAAA, TXT и записи DNSSEC, можно напрямую копировать в исходящее DNS-сообщение, тогда как типы, содержащие доменные имена, например CNAME, NS, MX и SOA, по-прежнему требуют разбора для применения сжатия имён DNS.
Что изменилось на практике?
Производственные измерения показали снижение резидентной памяти на 99-м процентиле с 9,3 до 5,3 ГБ, то есть на 43%, и с 6,5 до 3,8 ГБ на 90-м процентиле, то есть на 42%. Количество выделений на запись уменьшилось с 1,1 КБ до 461 байта, скорость вставки выросла с 625 тысяч записей в секунду до 893 тысяч, а время поиска сократилось с 828 до 670 наносекунд.
Развёртывание изменений началось 18 мая 2026 года и завершилось во всех сервисах 6 июля 2026 года. Cloudflare отмечает, что резидентная память в рабочей среде включает и другие данные помимо хранилища, поэтому фактическое снижение на уровне процесса оказалось меньше результата изолированного измерения для одной записи. Компания также планирует повторно инвестировать освобождённую память в увеличение ёмкости хранилища без роста потребления памяти, чтобы повысить коэффициент попаданий в кэш и сократить количество запросов, отправляемых вышестоящим серверам.
Важность этого случая заключается в том, что он показывает: оптимизация структуры данных — например, удаление ненужной ёмкости, объединение выделений и улучшение locality — может дать больший эффект, чем непосредственное добавление аппаратных ресурсов, когда сервис работает с сотнями миллиардов элементов. Однако некоторые компромиссы сохраняются: необработанное хранение усложняет работу с записями, для восстановления имён владельцев требуется извлечение данных из ключа хранилища, а результаты тестов зависят от конкретного сочетания трафика, которое не полностью совпадает с производственной нагрузкой. Поэтому производственные измерения, а не только теоретические цифры, остаются главным ориентиром при оценке подобных оптимизаций.