MAATRIX / Блог / Свой резолвер против 8.8.8.8 на сервере: что реально быстрее и на сколько

Свой резолвер против 8.8.8.8 на сервере: что реально быстрее и на сколько

MAATRIX

Кто-то однажды прописал в /etc/resolv.conf сервера 8.8.8.8 или 1.1.1.1 — «так надёжнее», — и с тех пор никто не проверял, действительно ли это быстрее, чем локальный кеширующий резолвер. Речь не про DNS для посетителей сайта — это отдельная история про авторитативные серверы, TTL и зоны домена. Речь про исходящий резолвинг: когда само приложение на сервере, cron-скрипт, пакетный менеджер или клиент внешнего API обращается к чужому домену и ему для этого нужно узнать IP. Разберёмся, что здесь реально быстрее, за счёт чего, и в каких случаях разница вообще заметна на глаз.

Что резолвит сервер сам для себя — и чем это отличается от DNS сайта

Когда речь про DNS сайта, сервер — это отвечающая сторона: у него (или у его DNS-провайдера) есть authoritative-зона, и внешние резолверы приходят спросить IP домена. Это зона ответственности из статей про PowerDNS, BIND, TTL записей и авторитативные серверы.

Здесь другая роль. Сервер выступает клиентом DNS точно так же, как браузер на ноутбуке пользователя. У него есть свой /etc/resolv.conf (или конфиг systemd-resolved, или DNS-настройки Docker-сети), и туда прописан адрес резолвера, к которому пойдёт каждый исходящий запрос на резолвинг чужого домена. Такие запросы генерирует не один процесс, а обычно сразу несколько:

  • приложение, которое ходит к внешнему API — платёжному шлюзу, S3-совместимому хранилищу, стороннему сервису геолокации или почтовому релею;
  • пакетный менеджер (apt, yum, dnf, npm, pip) при установке или обновлении зависимостей — каждый обращается к своему репозиторию по имени;
  • агент мониторинга или логирования, который периодически отправляет данные на внешний коллектор;
  • вебхуки и колбэки — сервер сам инициирует соединение к домену, который указал клиент или партнёр;
  • curl/wget в скриптах бэкапа, синхронизации, интеграций.

Каждый такой вызов, если у него в коде используется имя хоста, а не голый IP, сначала идёт в DNS. И весь вопрос статьи — где физически происходит этот резолвинг: на удалённом резолвере, до которого нужно дойти по сети, или в кеше локального процесса на этом же сервере.

Два пути: публичный резолвер и свой локальный кеширующий

Публичный резолвер — это открытый рекурсивный DNS-сервис вроде 8.8.8.8 (Google) или 1.1.1.1 (Cloudflare), доступный любому клиенту в интернете. Сервер просто указывает его адрес в /etc/resolv.conf, ничего не устанавливает и не обслуживает — вся рекурсивная логика (обход корневых, TLD и авторитативных серверов при промахе кеша) происходит на стороне этого сервиса, где-то за пределами вашей инфраструктуры.

Свой локальный кеширующий резолвер — это отдельный процесс на самом сервере (типичные варианты — Unbound или dnsmasq), который слушает 127.0.0.1 и обрабатывает DNS-запросы приложений на месте. Он либо сам выполняет полную рекурсию до авторитативных серверов, либо форвардит промахи кеша дальше — на upstream-резолвер (в том числе на тот же публичный). Ключевое отличие не в том, кто в итоге дойдёт до авторитативного сервера домена, а в том, где лежит кеш и на каком расстоянии он находится от процесса, который его спрашивает. Общая идея развёртывания такого резолвера — без привязки к конкретному конфигу — разобрана в статье про установку и настройку Unbound на VPS.

Коротко в одной таблице:

Публичный резолверСвой локальный резолвер
Где кешНа удалённом сервисе, общий на множество клиентовНа самом сервере, только для его процессов
Путь до кешаПо сети (минимум один round-trip)Loopback / память процесса
АдминистрированиеНе требуетсяНужно ставить, обновлять, следить
Зависимость от внешнего сервисаПолная — недоступность резолвера = недоступность DNS для сервераТолько на холодных запросах (промах локального кеша)
Контроль над политикамиОграничен настройками провайдера резолвераПолный — свои TTL-политики, forwarding, логирование

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Где реально теряется время: round-trip до внешнего резолвера

Здесь физика простая, и именно она определяет, кто выигрывает и насколько. Любой запрос к резолверу, который находится не на этом же хосте, — это как минимум один сетевой round-trip: пакет уходит по сети, доходит до резолвера, обрабатывается там, ответ идёт обратно. Даже если резолвер уже держит ответ в своём кеше и не идёт дальше по цепочке до authoritative-сервера — сетевую задержку между вашим сервером и этим резолвером всё равно никуда не деть. И она не всегда такая маленькая, как хочется думать: маршрут в интернете строится по договорённостям пиринга и BGP, а не по кратчайшему географическому расстоянию, и физически близкий с виду резолвер иногда оказывается в сетевом смысле дальше, чем кажется — этот эффект подробно разобран в статье про то, почему сетевой маршрут не совпадает с географией.

Локальный резолвер на 127.0.0.1 эту сетевую часть убирает полностью для всего, что уже есть в его кеше: ответ формируется в памяти процесса на этом же хосте — на порядки быстрее, чем даже самый близкий и хорошо настроенный внешний резолвер, просто потому что здесь нет сетевого сегмента вообще, только межпроцессное взаимодействие внутри одной машины. На холодный запрос (первый резолвинг домена, которого ещё нет в кеше) локальный резолвер тоже идёт в сеть — либо сам по цепочке до authoritative-сервера, либо к своему upstream, — и здесь выигрыша относительно публичного резолвера может и не быть, а иногда локальная полная рекурсия даже дольше одного прыжка до хорошо прогретого крупного публичного резолвера. Механика «первый запрос дорогой, повторные почти бесплатны» подробно разобрана в статье про вклад DNS-резолвинга во время загрузки — там это показано на примере браузера, но принцип кеша идентичен и для резолвера сервера.

Важный нюанс: TTL записи задаёт authoritative-сервер домена, а не ваш резолвер — ни локальный, ни публичный не могут отдавать закешированный ответ дольше этого времени (за редкими исключениями агрессивного кеширования просроченных записей на некоторых публичных сервисах). Поэтому если внешний API, к которому вы часто ходите, отдаёт запись с TTL в несколько секунд, выигрыш от локального кеша для этого конкретного домена будет скромнее, чем для домена с TTL в час — кеш просто будет чаще протухать вне зависимости от того, где он физически лежит.

Обратная сторона: что даёт публичный резолвер

Выбор не однозначен в пользу локального резолвера, и вот честные причины, почему администраторы продолжают полагаться на публичные сервисы даже зная про round-trip:

Ноль обслуживания. Публичный резолвер не нужно ставить, обновлять, мониторить на предмет падения процесса, разбираться с его логами при сбоях. Свой Unbound или dnsmasq — это ещё один сервис в списке того, что может упасть в 3 часа ночи, и ещё одна точка, которую нужно патчить при обнаружении уязвимостей в самом резолвере.

Инфраструктура и задержка сами по себе неплохие. У крупных публичных резолверов обычно anycast-сеть с множеством точек присутствия по миру, и запрос физически попадает на ближайший узел по BGP-анонсам — благодаря этому задержка до самого резолвера у многих пользователей и так низкая, даже без всякого локального кеша. Насколько именно низкая в вашей конкретной сети — заранее не угадать, зависит от пиринга вашего хостинг-провайдера, поэтому единственный надёжный способ узнать — измерить самостоятельно (см. раздел про тестирование ниже).

Встроенная защита от части атак. Крупные публичные резолверы обычно защищены от классических проблем рекурсивных DNS-серверов — cache poisoning, использование как открытого резолвера в DDoS-атаках через амплификацию, спуфинг ответов. У них есть ресурсы и опыт эксплуатации на масштабе, которого у одного администратора одного сервера обычно нет. Обратная сторона медали: если поднимаете свой резолвер и по ошибке открываете его наружу (слушает не только 127.0.0.1, но и внешний интерфейс без ограничения по IP), он рискует превратиться в открытый резолвер для чужой амплификации — это реальная эксплуатационная грабля, а не гипотетическая. Подробнее о том, кто вообще технически отвечает на DNS-запрос, — в статье про то, кто отвечает на ваш DNS-запрос.

Нулевая нагрузка на ресурсы сервера. Локальный резолвер — это процесс, которому нужна память под кеш и немного CPU. Для большинства серверов это несущественно, но на VPS с минимальными ресурсами каждый дополнительный процесс — это то, что нужно учитывать в бюджете памяти.

Когда выигрыш заметен: частые повторяющиеся запросы против редких разнообразных

Вот честный вывод без попытки продать один вариант как универсально правильный.

Локальный кеширующий резолвер обычно даёт заметный выигрыш, если сервер регулярно резолвит один и тот же ограниченный набор доменов — например, микросервис ходит к одному и тому же внешнему API по многу раз в минуту, агент мониторинга шлёт метрики на один и тот же коллектор, приложение постоянно проверяет один и тот же платёжный шлюз или очередь сообщений во внешнем облаке. В этом сценарии почти все запросы после первого попадают в тёплый локальный кеш и обслуживаются без выхода в сеть вообще — DNS-часть латентности для этих вызовов схлопывается почти до нуля, и разница накапливается на масштабе: чем больше таких вызовов в единицу времени, тем больше суммарной сетевой задержки убирается.

Разница может оказаться незначительной, если запросы редкие и к разным доменам — например, разовый batch-job раз в сутки обращается к десятку разных сторонних сервисов, каждый по одному разу, или сервер в принципе делает немного исходящих соединений вовне. Здесь кеш почти не успевает прогреться: большинство запросов всё равно уходят по холодному пути, будь то через локальный резолвер или напрямую через публичный, и вся разница сводится к тому единственному round-trip'у до резолвера, который решает эту холодную рекурсию — а он в обоих случаях может оказаться сопоставимым по времени, особенно если публичный резолвер отвечает быстро благодаря близкому anycast-узлу.

Отдельно стоит учитывать отрицательное кеширование (NXDOMAIN и подобные ответы) — если приложение регулярно стучится на домен, которого не существует или временно не резолвится, кеш отрицательных ответов на локальном резолвере тоже разгружает сеть, но с той же логикой TTL. И наоборот: слишком агрессивное кеширование ошибок иногда превращается в собственную проблему — известный сценарий, когда закешированный отрицательный ответ держит домен «мёртвым» для приложения куда дольше, чем реальный сбой длился на самом деле.

Как протестировать на своей нагрузке, а не гадать по общим рекомендациям

Рассуждения выше показывают направление, но не дают ответа для конкретного сервера — слишком многое зависит от того, к каким доменам и как часто он реально ходит. Вот практический план измерения, а не выбор по чужой рекомендации:

1. Посмотрите, что сервер реально резолвит. Соберите список доменов и частоту обращений за представительный период (сутки, а лучше неделя, если нагрузка не равномерная):

sudo tcpdump -i any -n 'udp port 53' -w dns-outbound.pcap

Дальше прогоните pcap через любой анализатор или просто посчитайте уникальные имена и число повторов на каждое — это и есть главный входной параметр для решения: чем сильнее запросы концентрируются на небольшом наборе доменов, тем лучше сработает кеш; чем сильнее они размазаны по уникальным именам без повторов, тем меньше от него будет пользы.

2. Замерьте текущую задержку до используемого резолвера, отдельно холодную и тёплую:

dig @<текущий_резолвер> example.com A +stats | grep "Query time"

Прогоните команду несколько раз подряд для одного и того же домена — первый запрос покажет холодную цифру (возможно, с полным обходом цепочки), последующие — уже кеш на стороне резолвера. Повторите то же самое для публичного резолвера и, если уже есть тестовый локальный резолвер, для него.

3. Разверните локальный резолвер в параллель, не переключая продакшн сразу. Поднимите Unbound или dnsmasq на 127.0.0.1 на том же сервере (или на staging-копии), но пока не меняйте /etc/resolv.conf у боевых процессов — просто указывайте локальный адрес явно в тестовых запросах:

dig @127.0.0.1 example.com A +stats | grep "Query time"
time getent hosts example.com

4. Сравните под реальной нагрузкой, а не одиночным запросом. Прогоните тот же трафик, который сервер генерирует в проде (или его копию на staging), сначала через текущий резолвер, потом через локальный, и смотрите не на среднее, а на распределение — разовый выброс не так важен, как то, что происходит в типичном случае и в доле самых медленных запросов. Средняя цифра легко врёт, если распределение задержек неровное.

5. Учитывайте Docker отдельно. У Docker обычно свой встроенный DNS на 127.0.0.11 внутри контейнерных сетей, который форвардит запросы дальше по своей логике — простое изменение /etc/resolv.conf на хосте не всегда автоматически меняет то, что видит процесс внутри контейнера. Это нужно проверять и настраивать отдельно, если резолвинг контейнеризованных приложений тоже участвует в тесте.

Только после такого прогона на своих доменах и своей сети имеет смысл принимать решение — универсальной рекомендации «всегда ставь свой резолвер» или «всегда используй публичный» здесь нет.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли совместить оба подхода — свой резолвер, который форвардит на публичный?

Да, это распространённая схема: локальный резолвер обслуживает кеш на месте (убирает round-trip для тёплых записей), а промахи кеша отправляет не по полной рекурсии, а сразу на upstream вроде публичного резолвера. Так получаете низкую задержку на повторных запросах и не тратите время на самостоятельный обход корневых и TLD-серверов при холодном промахе — но зависите от доступности и политик того upstream'а для холодных случаев.

Что будет, если публичный резолвер, на который завязан сервер, станет недоступен или начнёт тормозить?

Все исходящие соединения по доменному имени зависнут в ожидании DNS-ответа до таймаута — это может каскадом положить приложения, которые ждут ответа синхронно. Локальный кеширующий резолвер частично страхует от этого: уже закешированные записи продолжат отвечать даже при недоступности upstream'а, хотя холодные запросы всё равно упрутся в ту же проблему. Разумная практика в любом случае — прописывать не один резолвер, а несколько в порядке приоритета.

Нужно ли отдельно настраивать DNS для контейнеров, если сервер перешёл на локальный резолвер?

Обычно да. Docker по умолчанию использует свой встроенный DNS внутри пользовательских сетей и не всегда автоматически подхватывает изменения в /etc/resolv.conf хоста — стоит явно проверить, что видит процесс внутри контейнера, и при необходимости прописать резолвер в настройках Docker-сети отдельно.

Стоит ли ставить локальный резолвер, если сервер делает мало исходящих DNS-запросов?

Не обязательно даст ощутимый эффект — если запросы редкие и к разным доменам, кеш почти не успевает прогреться, и основная часть времени всё равно уйдёт на холодную рекурсию что через локальный резолвер, что через публичный. В этом случае выигрыш от собственного администрирования резолвера может не окупить сложность его обслуживания — но это тоже вывод, который стоит проверить измерением, а не принимать по умолчанию.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →