Инженерная команда Cloudflare рассказала 27 августа, чем занималась с мая по июль: переупаковкой того, как записи DNS-кэша 1.1.1.1 лежат в оперативной памяти. Новых возможностей у резолвера не прибавилось ни одной. Прибавилось свободной памяти — порядка 100 терабайт по всему парку серверов, потому что одна запись похудела с 953 байт до 420.
Само по себе это чужая инфраструктурная история. Но подход к ней применим и в масштабе одной VPS: у Unbound или dnsmasq на домашнем сервере действуют те же законы, разница лишь в количестве нулей. С одной поправкой не в вашу пользу — лимиты своего кэша вы выставляете вручную, и стоят там, как правило, значения из коробки, к которым никто не возвращался с момента установки.
ℹ️ Справка
Материал пригодится тем, у кого крутится собственный рекурсивный резолвер — Unbound, dnsmasq, AdGuard Home, CoreDNS — и особенно тем, у кого он живёт на машине со скромной памятью. Ближе к концу разобрано, как снять фактический расход и что означают полученные числа.
Байт, который стоит 250 гигабайт
Платформа Big Pineapple обслуживает 1.1.1.1, Gateway DNS, DNS Firewall и AS112. По данным компании, в кэше единовременно лежит свыше 250 миллиардов записей. Из этой цифры следует главный тезис отчёта, и он не про красивое сравнение, а про обычное умножение: каждый лишний байт в структуре записи обходится парку более чем в 250 гигабайт.
Здесь же стоит разобрать расхождение, которое иначе выглядит как ошибка в тексте. Если 533 сэкономленных байта умножить на 250 миллиардов, выйдет за 130 ТБ, тогда как в заголовке отчёта стоит около 100. Никакого противоречия: сотня терабайт получена замером резидентной памяти процессов, а не перемножением на бумаге. Расчётный потолок и то, что удалось увидеть в мониторинге, сходиться не обязаны.
Где именно пряталась лишняя память
С точки зрения логики в записи не было ничего избыточного. Ключ (CacheKey) складывался из четырёх полей — qname, qtype, authenticated, tag. Значение (CacheEntry) насчитывало восемь: timestamp, inception, ttl, hits, answers, authority, additional, errors. Избыточной была раскладка этих полей в памяти.
Пять правок в порядке, в котором их перечисляет отчёт
Первая статья расхода — контейнер Vec под списки записей: он всегда носит с собой поле capacity размером в восемь байт, и носит его даже тогда, когда запись давно собрана и меняться не будет. Вторая — разбиение ответа на три независимых списка (answer, authority, additional), каждый со своим указателем и своей длиной. Третья, самая наглядная, — перечисление типов записей: компилятор выравнивал его до 144 байт по самому объёмному варианту, хотя львиную долю трафика (свыше 80 %) составляют A и AAAA, которым нужны единицы байт.
Проволочный формат — приём с наибольшей отдачей
Больше всех дала пятая правка: записи стали храниться в проволочном формате (wire format). Типизированные структуры уступили место единственному байтовому буферу, внутри которого записи идут одна за другой, и перед каждой стоит двухбайтовый префикс длины. То есть ровно так, как эти же записи выглядят внутри DNS-пакета.
Выигрышей тут два. Накладные расходы на варианты перечисления просто исчезли — хранить стало нечего, кроме байтов. А отдача клиенту в большинстве случаев превратилась в копирование как есть: обратный разбор нужен лишь типам, содержащим доменные имена, то есть CNAME, NS, MX и SOA. Третьим эффектом идёт локальность — процессорному кэшу подряд лежащие байты обходятся дешевле, чем блуждание по указателям.
Замеры проводились на наборе, повторяющем продовое распределение типов: A — 56 %, AAAA — 25 %, TXT — 19 %. Про методику это говорит важное: там, где в трафике заметная доля SVCB или подписей DNSSEC, схема «мелкие типы держим внутри, крупные выносим в кучу» отработает иначе.
Что получилось в цифрах
Метрика
Было
Стало
Разница
Память на запись
953 Б
420 Б
−56 %
Аллокаций на запись
1,1 КБ
461 Б
−58 %
Резидентная память, p99
9,3 ГБ
5,3 ГБ
−43 %
Резидентная память, p90
6,5 ГБ
3,8 ГБ
−42 %
Компактность потянула за собой и скорость: вставка в кэш стала быстрее на 43 %, поиск — на 19 %. Выкатывали изменения не одним махом, а постепенно: старт пришёлся на 18 мая 2026 года, полное покрытие всех сервисов — на 6 июля.
❗ Главное
Из этих процентов легко вывести неверное правило вида «поменяй Vec на Box<[T]> — получишь ускорение». Ускорила не смена типа сама по себе, а компактная последовательная раскладка данных при вполне определённом характере нагрузки. Другой паттерн доступа — и тот же приём не даст ничего. Приведённые числа описывают кэш Cloudflare, а не программы вообще.
Свой резолвер: что и чем померить
Искать у себя те же 953 байта смысла нет — ваш демон написан на другом языке и устроен по-другому. Зато лимит памяти под кэш у вас задан явным числом, и с высокой вероятностью это число никто не трогал.
Unbound
Из коробки параметры msg-cache-size, rrset-cache-size и key-cache-size выставлены в 4 МБ каждый. Фактическое потребление снимается так:
unbound-control stats_noreset | grep '^mem\.'
Смотреть надо на две строки: mem.cache.message — это байты, занятые кэшем сообщений, и mem.cache.rrset — то же для кэша RRset. Когда значение подобралось вплотную к лимиту, записи вытесняются, не дожив до конца своего TTL, и часть запросов напрасно уходит к вышестоящему серверу. Форма stats_noreset выбрана намеренно: обычная stats счётчики обнуляет, эта — нет.
dnsmasq
Единица измерения здесь другая: cache-size считается в именах, а не в байтах, и по умолчанию равна 150 записям — для роутера, за которым висит десяток устройств, это уже на грани. Значение 0 выключает кэширование целиком. Запущенный в отладочном режиме (-d) демон по сигналу SIGUSR1 выдаёт полный дамп кэша — простой способ посмотреть, чем тот занят на самом деле.
AdGuard Home
В AdGuardHome.yaml ключ cache_size измеряется в байтах — логика та же, что у Unbound: это бюджет, а не счётчик имён. По соседству лежат cache_ttl_min и cache_ttl_max, которыми переопределяется TTL, пришедший от апстрима.
Сопоставить mem.cache.message с msg-cache-size, а mem.cache.rrset — с rrset-cache-size
Если оба упёрлись в потолок, а память на машине есть — увеличить лимиты кратно (скажем, до 32m и 64m) и перезапустить демон
Для dnsmasq — убедиться, что дефолтные 150 имён не остались нетронутыми
⚠️ Осторожно
Тесноту кэша не лечат растягиванием TTL. Документация dnsmasq по поводу min-cache-ttl формулирует это без обиняков: искусственное продление TTL — в общем случае затея скверная, а сам параметр там сверху ограничен часом. Кэш от этого не увеличится, зато клиенты начнут получать протухшие ответы; на доменах с часто меняющимися адресами связность отвалится именно в тот момент, когда причину искать труднее всего.
Признавайтесь: кто-нибудь после установки резолвера возвращался к размерам его кэша? Или везде так и живут дефолтные 4 МБ и 150 имён? Если снимали статистику — насколько mem.cache.message у вас далёк от лимита?
Вы можете написать сейчас и зарегистрироваться позже.
Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.
Инженерная команда Cloudflare рассказала 27 августа, чем занималась с мая по июль: переупаковкой того, как записи DNS-кэша 1.1.1.1 лежат в оперативной памяти. Новых возможностей у резолвера не прибавилось ни одной. Прибавилось свободной памяти — порядка 100 терабайт по всему парку серверов, потому что одна запись похудела с 953 байт до 420.
Само по себе это чужая инфраструктурная история. Но подход к ней применим и в масштабе одной VPS: у
Unboundилиdnsmasqна домашнем сервере действуют те же законы, разница лишь в количестве нулей. С одной поправкой не в вашу пользу — лимиты своего кэша вы выставляете вручную, и стоят там, как правило, значения из коробки, к которым никто не возвращался с момента установки.ℹ️ Справка
Материал пригодится тем, у кого крутится собственный рекурсивный резолвер — Unbound, dnsmasq, AdGuard Home, CoreDNS — и особенно тем, у кого он живёт на машине со скромной памятью. Ближе к концу разобрано, как снять фактический расход и что означают полученные числа.
Байт, который стоит 250 гигабайт
Платформа Big Pineapple обслуживает 1.1.1.1, Gateway DNS, DNS Firewall и AS112. По данным компании, в кэше единовременно лежит свыше 250 миллиардов записей. Из этой цифры следует главный тезис отчёта, и он не про красивое сравнение, а про обычное умножение: каждый лишний байт в структуре записи обходится парку более чем в 250 гигабайт.
Здесь же стоит разобрать расхождение, которое иначе выглядит как ошибка в тексте. Если 533 сэкономленных байта умножить на 250 миллиардов, выйдет за 130 ТБ, тогда как в заголовке отчёта стоит около 100. Никакого противоречия: сотня терабайт получена замером резидентной памяти процессов, а не перемножением на бумаге. Расчётный потолок и то, что удалось увидеть в мониторинге, сходиться не обязаны.
Где именно пряталась лишняя память
С точки зрения логики в записи не было ничего избыточного. Ключ (
CacheKey) складывался из четырёх полей —qname,qtype,authenticated,tag. Значение (CacheEntry) насчитывало восемь:timestamp,inception,ttl,hits,answers,authority,additional,errors. Избыточной была раскладка этих полей в памяти.Первая статья расхода — контейнер
Vecпод списки записей: он всегда носит с собой полеcapacityразмером в восемь байт, и носит его даже тогда, когда запись давно собрана и меняться не будет. Вторая — разбиение ответа на три независимых списка (answer,authority,additional), каждый со своим указателем и своей длиной. Третья, самая наглядная, — перечисление типов записей: компилятор выравнивал его до 144 байт по самому объёмному варианту, хотя львиную долю трафика (свыше 80 %) составляют A и AAAA, которым нужны единицы байт.Проволочный формат — приём с наибольшей отдачей
Больше всех дала пятая правка: записи стали храниться в проволочном формате (wire format). Типизированные структуры уступили место единственному байтовому буферу, внутри которого записи идут одна за другой, и перед каждой стоит двухбайтовый префикс длины. То есть ровно так, как эти же записи выглядят внутри DNS-пакета.
Выигрышей тут два. Накладные расходы на варианты перечисления просто исчезли — хранить стало нечего, кроме байтов. А отдача клиенту в большинстве случаев превратилась в копирование как есть: обратный разбор нужен лишь типам, содержащим доменные имена, то есть
CNAME,NS,MXиSOA. Третьим эффектом идёт локальность — процессорному кэшу подряд лежащие байты обходятся дешевле, чем блуждание по указателям.Замеры проводились на наборе, повторяющем продовое распределение типов: A — 56 %, AAAA — 25 %, TXT — 19 %. Про методику это говорит важное: там, где в трафике заметная доля SVCB или подписей DNSSEC, схема «мелкие типы держим внутри, крупные выносим в кучу» отработает иначе.
Что получилось в цифрах
Компактность потянула за собой и скорость: вставка в кэш стала быстрее на 43 %, поиск — на 19 %. Выкатывали изменения не одним махом, а постепенно: старт пришёлся на 18 мая 2026 года, полное покрытие всех сервисов — на 6 июля.
❗ Главное
Из этих процентов легко вывести неверное правило вида «поменяй
VecнаBox<[T]>— получишь ускорение». Ускорила не смена типа сама по себе, а компактная последовательная раскладка данных при вполне определённом характере нагрузки. Другой паттерн доступа — и тот же приём не даст ничего. Приведённые числа описывают кэш Cloudflare, а не программы вообще.Свой резолвер: что и чем померить
Искать у себя те же 953 байта смысла нет — ваш демон написан на другом языке и устроен по-другому. Зато лимит памяти под кэш у вас задан явным числом, и с высокой вероятностью это число никто не трогал.
Unbound
Из коробки параметры
msg-cache-size,rrset-cache-sizeиkey-cache-sizeвыставлены в 4 МБ каждый. Фактическое потребление снимается так:Смотреть надо на две строки:
mem.cache.message— это байты, занятые кэшем сообщений, иmem.cache.rrset— то же для кэша RRset. Когда значение подобралось вплотную к лимиту, записи вытесняются, не дожив до конца своего TTL, и часть запросов напрасно уходит к вышестоящему серверу. Формаstats_noresetвыбрана намеренно: обычнаяstatsсчётчики обнуляет, эта — нет.dnsmasq
Единица измерения здесь другая:
cache-sizeсчитается в именах, а не в байтах, и по умолчанию равна 150 записям — для роутера, за которым висит десяток устройств, это уже на грани. Значение0выключает кэширование целиком. Запущенный в отладочном режиме (-d) демон по сигналуSIGUSR1выдаёт полный дамп кэша — простой способ посмотреть, чем тот занят на самом деле.AdGuard Home
В
AdGuardHome.yamlключcache_sizeизмеряется в байтах — логика та же, что у Unbound: это бюджет, а не счётчик имён. По соседству лежатcache_ttl_minиcache_ttl_max, которыми переопределяется TTL, пришедший от апстрима.✅ Как правильно
unbound-control stats_noreset | grep '^mem\.'mem.cache.messageсmsg-cache-size, аmem.cache.rrset— сrrset-cache-size⚠️ Осторожно
Тесноту кэша не лечат растягиванием TTL. Документация dnsmasq по поводу
min-cache-ttlформулирует это без обиняков: искусственное продление TTL — в общем случае затея скверная, а сам параметр там сверху ограничен часом. Кэш от этого не увеличится, зато клиенты начнут получать протухшие ответы; на доменах с часто меняющимися адресами связность отвалится именно в тот момент, когда причину искать труднее всего.Источники
💬 Вопрос к сообществу
Признавайтесь: кто-нибудь после установки резолвера возвращался к размерам его кэша? Или везде так и живут дефолтные 4 МБ и 150 имён? Если снимали статистику — насколько
mem.cache.messageу вас далёк от лимита?TOP HOSTERS: KAMATERA (30 дней бесплатного теста!)
Универсальный хостер №1 - 4VPS.su (2Гб\с сервера) - 10% скидка на первый заказ или 15% бонус на первое пополнение