Проблема 100 терабайт, скрытая на самом видном месте
Глобальная DNS-инфраструктура Cloudflare, работающая на платформе с подходящим названием Big Pineapple, функционирует в поразительных масштабах. Она постоянно управляет более чем 250 миллиардами записей DNS-кэша, обеспечивая работу таких критически важных сервисов, как 1.1.1.1, Gateway DNS и DNS Firewall для бесчисленного множества пользователей по всему миру.
Несмотря на огромный масштаб операций, инженеры Cloudflare обнаружили повсеместную скрытую неэффективность. Типичная запись DNS-кэша объемом 953 байта содержала значительную долю избыточных затрат памяти (memory overhead), выделенных не для самих данных DNS, а для внутреннего учета структур данных. Например, стандартные типы Vec и String в Rust хранят указатель, длину и поле емкости (capacity).
Для статических кэшированных DNS-записей, которые не увеличиваются в размере, это поле емкости стало ненужным бременем, потребляющим драгоценную память. Эта, казалось бы, незначительная неэффективность значительно усугублялась в масштабах всей сети. Даже один лишний байт на запись при 250 миллиардах записей превращается в более чем 250 гигабайт избыточной оперативной памяти.
Эта колоссальная потеря памяти была эквивалентна эксплуатационным расходам целых серверов, что подчеркивает, как мелкие, упущенные из виду детали проектирования структур данных могут перерасти в огромные инфраструктурные расходы. Открытие Cloudflare подчеркнуло критическую важность тонкого управления памятью даже в высокоуровневых языках, таких как Rust.
Устранение емкости: палка о двух концах в Rust
Структуры данных в Rust часто отдают приоритет гибкости. Стандартные типы, такие как Vec и String, эффективно управляют динамическими данными, выделяя больше памяти, чем требуется немедленно, резервируя дополнительную емкость (capacity) для будущего роста. Каждый экземпляр неявно хранит три фрагмента информации: указатель на свои данные, их текущую длину и эту предварительно выделенную емкость.
Эта стратегия очень эффективна для изменяемых данных, но она является чистой тратой ресурсов для неизменяемых записей. 250 миллиардов записей DNS-кэша Cloudflare фиксируются после сохранения; они никогда не расширяются и не сокращаются. Таким образом, дополнительное поле емкости не имело функционального назначения в рамках «Big Pineapple», но при этом потребляло ценные системные ресурсы.
Осознав эту неэффективность, инженеры заменили Vec и String на boxed slices (Box<[T]>) и boxed strings (Box<str>). Эти специализированные типы Rust выделяют ровно столько памяти, сколько необходимо для данных, полностью устраняя поле емкости. Это, казалось бы, небольшое изменение сэкономило 64 байта на каждую отдельную запись в кэше.
Во всей глобальной сети Cloudflare эта оптимизация мгновенно высвободила более 15 ТБ оперативной памяти. Это демонстрирует, как глубокое понимание семантики структур данных в сочетании с конкретными требованиями приложения может обеспечить огромный прирост эффективности, превращая неиспользуемую память в активные, полезные ресурсы.
Больше, чем просто Box: искусство упаковки данных
Cloudflare отказалась от использования отдельных указателей для разделов DNS, таких как answer, authority и additional, перейдя к стратегии плотной упаковки (tightly packed) данных. Они объединили эти разделы в один непрерывный блок памяти, а затем использовали крошечные двухбайтовые смещения для точной навигации к каждой части. Это устранило накладные расходы на указатели, что внесло значительный вклад в сокращение размера записи в кэше на 56%, уменьшив его с 953 байт до всего лишь 420 байт на запись.
Дальнейшая оптимизация была направлена на устранение избыточности и структурной неэффективности кэша. Cloudflare перестали хранить имя владельца, если оно дублировало запрос, восстанавливая его из ключа кэша только при необходимости. Решая проблему размера Rust enum, который по умолчанию принимает размер самого большого варианта, они внедрили boxing для крупных и редких типов записей, таких как NAPTR. Это позволило более мелким и распространенным записям, таким как A и AAAA, занимать значительно меньше памяти.
Последнее крупное изменение заключалось в хранении данных записей в виде необработанных wire-format bytes с префиксами длины вместо полностью разобранных структур Rust. Это позволяет обойти накладные расходы памяти системы типов Rust для данных, которые не требуют постоянного парсинга, что еще больше сокращает объем памяти для 250 миллиардов записей в кэше Big Pineapple. Более подробно об этих оригинальных методах экономии памяти можно прочитать в статье How we saved 100 terabytes of memory by optimizing 1.1.1.1's DNS cache | Cloudflare Blog.
Нравится статья? Получайте такие каждое утро на почту.
одно письмо в день · отписка в два клика · без сторонних трекеров
Результат: быстрее и компактнее
Тщательная переработка данных привела к поразительному результату: Cloudflare сократили типичный размер записи DNS-кэша с 953 байт до всего 420 байт. Это означает существенное сокращение объема памяти на 56% на каждую запись. В рамках глобальной сети Cloudflare, которая управляет более чем 250 миллиардами записей в кэше, эта оптимизация позволила высвободить колоссальные 100 терабайт оперативной памяти без добавления ни одного нового сервера.
Важно отметить, что эта экономия памяти не привела к снижению производительности; напротив, операции значительно ускорились. Вставка в кэш стала быстрее на 43%, увеличившись с 625 000 до впечатляющих 893 000 записей в секунду. Аналогичным образом, время поиска улучшилось на 19%, при этом задержка снизилась с 828 наносекунд до быстрых 670 наносекунд. Этот редкий сценарий «выигрыш-выигрыш» обеспечил как значительную эффективность ресурсов, так и повышенную скорость работы, опровергая традиционные компромиссы.
Cloudflare стратегически направит высвобожденные 100 терабайт памяти на расширение емкости своего DNS-кэша. Более крупный и надежный кэш позволит платформе "Big Pineapple" разрешать еще большую долю запросов локально. Это напрямую снижает необходимость получения данных с вышестоящих серверов, что приводит к более быстрому DNS-разрешению для пользователей по всему миру и заметно улучшает общую скорость интернета для всех.
Часто задаваемые вопросы
Сколько памяти сэкономили Cloudflare благодаря этой оптимизации?
Cloudflare высвободили около 100 терабайт (ТБ) оперативной памяти во всей своей глобальной сети, что эквивалентно объему памяти примерно 130 серверов, не добавляя при этом нового оборудования.
Стал ли DNS Cloudflare медленнее из-за оптимизации памяти?
Нет, оптимизация дала обратный эффект. Вставка в кэш стала быстрее на 43%, а поиск — на 19%, что опровергает распространенный компромисс между использованием памяти и скоростью.
Какой язык программирования использовали Cloudflare для достижения этого результата?
Cloudflare использовали язык программирования Rust, воспользовавшись его функциями для тонкого управления памятью, чтобы переписать структуру записей DNS-кэша.
Какое главное изменение внесли Cloudflare для экономии памяти?
Ключевым изменением стала замена стандартных типов данных Rust, таких как Vec и String, на Box<[T]> и Box<str>. Это устранило ненужное поле 'capacity' для кэшированных данных, размер которых никогда не меняется, что позволило экономить 64 байта на каждой записи.
Как Cloudflare удалось сократить размер записи DNS-кэша на 56%?
Они внедрили пять ключевых изменений на уровне Rust: устранение полей емкости (capacity), упаковка разделов данных в один блок со смещениями, удаление избыточной информации, использование boxing для крупных вариантов enum и хранение данных в их исходном wire-формате.

