Раздел 1 · Сети — глава 1.3

DNS: типы записей, балансировка и как этим пользоваться

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

§1Иерархия: кто вообще за что отвечает

DNS устроен как дерево с делегированием ответственности, и понимание этого объясняет почти всё остальное поведение.

Читать имя надо справа налево. В shop.example.com. самая правая точка — это корень (её обычно не пишут, но формально она есть). Дальше com — домен верхнего уровня, example — домен второго уровня, shop — поддомен.

Каждый уровень не хранит данные нижних, а лишь говорит, кто за них отвечает. Корневые серверы не знают адрес твоего сайта — они знают, какие серверы обслуживают зону com. Серверы com не знают адрес — они знают, какие серверы обслуживают example.com. И только последние, авторитативные для этой зоны, знают настоящий ответ.

Различать два типа серверов важно, потому что их путают постоянно:

  • Авторитативный сервер — хранит зону и отвечает за неё «от себя». Это тот сервер, куда ты вносишь записи: у регистратора, у облачного провайдера или свой bind/PowerDNS. Он не ходит никуда спрашивать — он и есть источник истины.
  • Рекурсивный резолвер — не хранит ничего своего, но умеет пройти всю цепочку за клиента и вернуть ответ. Это то, что прописано у тебя в настройках сети: резолвер провайдера, роутер, публичные 8.8.8.8 или 1.1.1.1, а внутри кластера — CoreDNS. Он же кеширует ответы, и это главный источник задержек при изменениях.

§2Как идёт запрос целиком

клиент спрашивает резолвер: «какой A у shop.example.com?» │ резолвер смотрит свой кеш — если есть и не протух, отдаёт сразу │ иначе идёт по цепочке: │ ├─→ корневой сервер: «не знаю, но за .com отвечают вот эти NS» ├─→ сервер .com: «не знаю, но за example.com отвечают вот эти NS» ├─→ сервер example.com: «shop.example.com = 203.0.113.10, TTL 300» │ ↑ этот ответ авторитативный (флаг aa) │ └─→ кладёт в кеш на 300 секунд и отдаёт клиенту

Ключевая деталь для собеса: рекурсию делает резолвер, а не клиент. Клиент задаёт один вопрос и получает один ответ; вся беготня по иерархии происходит на стороне резолвера. Запрос клиента называется рекурсивным (флаг «хочу рекурсию»), а запросы резолвера к серверам иерархии — итеративными: каждый отвечает «сам не знаю, спроси вот их».

Транспорт по умолчанию — UDP на порту 53. Если ответ не влезает в один пакет, сервер выставляет флаг усечения, и клиент повторяет запрос по TCP на тот же порт. Отсюда практическое правило: файрвол должен пропускать DNS и по UDP, и по TCP. Классический инцидент — открыли только UDP, всё работало годами, а потом зона подросла (или включили DNSSEC), ответы перестали влезать, и часть запросов начала таинственно отваливаться.

§3A, AAAA и CNAME — три записи, которые нужны всегда

A и AAAA

Самые базовые: имя → адрес. A отдаёт адрес IPv4, AAAA — IPv6. Никакой другой разницы между ними нет.

shop.example.com.    300   IN   A      203.0.113.10
shop.example.com.    300   IN   AAAA   2001:db8::10

Формат строки читается так: имя, TTL в секундах, класс (всегда IN — Internet), тип, значение.

На одно имя можно повесить несколько A-записей с разными адресами — это и есть примитивная балансировка, о которой в §8.

Грабли

Если у имени есть и A, и AAAA, современные клиенты запрашивают обе и предпочитают IPv6. Если IPv6-адрес прописан, но сеть по нему на самом деле не работает, получишь плавающие задержки: клиент честно пробует IPv6, ждёт таймаута и только потом переключается на IPv4. Механизм «счастливых глаз» в браузерах это сглаживает, а вот у утилит командной строки и серверных библиотек — часто нет. Поэтому AAAA-запись должна появляться только тогда, когда IPv6 действительно рабочий.

CNAME

Псевдоним: «это имя — на самом деле другое имя». Резолвер, получив CNAME, начинает резолвить указанную цель заново.

www.example.com.     300   IN   CNAME   shop.example.com.
shop.example.com.    300   IN   A       203.0.113.10

Зачем это нужно: адрес меняется в одном месте, а десяток имён следуют за ним автоматически. Именно поэтому все облачные балансировщики и CDN просят прописать CNAME на их домен, а не адрес — за их доменом стоит своя логика, которая может менять адреса когда угодно.

У CNAME есть два жёстких ограничения, и оба спрашивают:

Первое: рядом с CNAME не может быть никаких других записей для того же имени. Это следует из смысла — если имя целиком является псевдонимом другого, то у него не может быть своих собственных данных.

Второе, следующее из первого: CNAME нельзя поставить на корень домена (на example.com без поддомена, это называют apex или naked domain). Причина: у корня зоны обязательно есть записи SOA и NS — без них зона не существует, — а значит, поставить туда CNAME запрещено. Отсюда вечная проблема «хочу, чтобы example.com вёл на облачный балансировщик, а он даёт только имя». Решения три: нестандартные записи провайдера (ALIAS, ANAME, «CNAME flattening» — сервер сам резолвит цель и отдаёт клиенту готовый A), редирект с корня на www, или просто использовать провайдера, у которого такая возможность есть.

§4NS и SOA: чем вообще держится зона

NS — делегирование

Указывает, какие серверы авторитативны для зоны. Именно эти записи прописываются у регистратора домена и именно по ним строится цепочка из §2.

example.com.    172800   IN   NS   ns1.provider.net.
example.com.    172800   IN   NS   ns2.provider.net.

Тонкость, которую полезно понимать: NS-записи существуют в двух местах — в родительской зоне (у регистратора, там они и делают делегирование) и в самой зоне. Расхождение между ними — источник загадочных проблем, когда часть резолверов ходит на старые серверы, а часть на новые.

Отдельная деталь — glue records. Если серверы имён живут внутри той же зоны, которую обслуживают (скажем, ns1.example.com отвечает за example.com), возникает замкнутый круг: чтобы узнать адрес ns1.example.com, надо спросить сервер example.com, но чтобы до него дойти, нужен его адрес. Разрывается это тем, что родительская зона хранит адреса этих серверов напрямую — это и есть glue.

SOA — параметры зоны

Одна запись на зону, содержащая её служебные параметры. Полностью её знать не нужно, но два поля из неё регулярно всплывают в реальной работе.

example.com.  3600  IN  SOA  ns1.provider.net. admin.example.com. (
                  2024071501   ; serial — версия зоны
                  7200         ; refresh — как часто вторичные проверяют
                  3600         ; retry — пауза при неудаче проверки
                  1209600      ; expire — когда вторичный перестаёт отвечать
                  300 )        ; minimum — TTL отрицательных ответов

Serial — номер версии зоны. Вторичные серверы сравнивают его со своим и, если он вырос, скачивают зону заново. Забыл увеличить после правки — вторичные так и останутся со старыми данными. При ручном ведении зон это ошибка номер один.

Minimum — вопреки названию, это TTL для отрицательных ответов. То есть сколько времени резолверы будут помнить, что записи не существует. Про это отдельно в §7, потому что оно ловит людей регулярно.

§5MX и TXT

MX — куда доставлять почту

example.com.   3600   IN   MX   10  mail1.example.com.
example.com.   3600   IN   MX   20  mail2.example.com.

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

Ограничение: MX должен указывать на имя, у которого есть A или AAAA. Указывать MX на CNAME или прямо на IP-адрес нельзя — часть серверов такое просто отвергнет.

TXT — произвольный текст, ставший инфраструктурой

Изначально задумывалась как поле для заметок, а на практике на ней держится половина проверки подлинности в интернете. Три применения, которые надо знать:

ЧтоЗачем
SPFСписок серверов, которым разрешено отправлять почту от имени домена. Запись вида v=spf1 ip4:203.0.113.0/24 include:_spf.provider.com -all
DKIMПубличный ключ, которым проверяется подпись писем. Лежит в поддомене вида selector._domainkey.example.com
DMARCЧто делать с письмами, не прошедшими SPF и DKIM, и куда слать отчёты. Лежит в _dmarc.example.com
Подтверждение владенияПровайдер просит положить в TXT выданную строку, чтобы убедиться, что домен твой. Так делают Google, Let's Encrypt при выпуске wildcard-сертификатов и почти все SaaS

Про SPF стоит помнить ограничение, о котором любят спрашивать в контексте почты: цепочка include не должна требовать больше десяти обращений к DNS, иначе проверка вернёт ошибку. Добавили пятого внешнего отправителя — и почта неожиданно начала попадать в спам.

§6SRV, PTR и CAA

SRV — сервис, порт и веса

Единственный тип записи, который умеет отдавать порт, а заодно приоритеты и веса. Формат имени особый: _сервис._протокол.домен.

_ldap._tcp.example.com.  300  IN  SRV  10  60  389  ldap1.example.com.
_ldap._tcp.example.com.  300  IN  SRV  10  40  389  ldap2.example.com.
_ldap._tcp.example.com.  300  IN  SRV  20   0  389  ldap-backup.example.com.
                                       │   │   │
                                 приоритет│  порт
                                        вес

Логика такая: сначала берутся записи с наименьшим приоритетом, и между ними трафик делится пропорционально весам — здесь 60% на первый сервер, 40% на второй. Записи с бо́льшим приоритетом используются, только если все предыдущие недоступны.

Это единственная настоящая балансировка средствами DNS, с весами и резервированием. Проблема одна: клиент должен уметь работать с SRV, а обычные HTTP-клиенты и браузеры не умеют. Реально ими пользуются LDAP, Kerberos, SIP, XMPP, Consul и внутренние механизмы Kubernetes.

PTR — обратный резолв

Адрес → имя. Живёт в специальной зоне: адресу 203.0.113.10 соответствует имя 10.113.0.203.in-addr.arpa — байты в обратном порядке.

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

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

CAA — кому разрешено выпускать сертификаты

example.com.   3600   IN   CAA   0 issue "letsencrypt.org"

Говорит удостоверяющим центрам, кто из них имеет право выпускать сертификаты для этого домена. Центры обязаны проверять эту запись перед выпуском. Защита от ситуации, когда кто-то выпускает сертификат на твой домен через другой центр. Спрашивают редко, но упоминание показывает кругозор.

§7TTL: почему изменения приезжают не сразу

У каждой записи есть время жизни в секундах. Резолвер, получив ответ, держит его в кеше ровно столько и всё это время отвечает клиентам из кеша, никуда не обращаясь. Механизм простой, а последствия — источник половины вопросов «я же поменял, почему не работает».

Смена адреса планируется заранее. Правильная последовательность: за сутки-двое до переключения опустить TTL записи до 60–300 секунд и дождаться, пока старое большое значение вытечет из всех кешей. Затем менять адрес — новое значение разъедется за минуты. После того как всё устоялось, вернуть TTL обратно к нормальному, чтобы не нагружать серверы. Если поменять адрес при TTL в сутки, часть пользователей будет ходить на старый ещё сутки.

Отрицательные ответы кешируются тоже. Это ловит чаще всего. Если запросить имя до того, как запись создана, резолвер запомнит ответ «такого имени нет» — на время из поля minimum записи SOA. Потом ты создаёшь запись, проверяешь — и получаешь NXDOMAIN, хотя всё сделано верно. Отсюда правило: не проверяй имя до того, как создал запись, а если уже проверил — подожди или спроси другой резолвер.

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

§8Балансировка через DNS: что работает, а что нет

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

Round robin несколькими A-записями

shop.example.com.   60   IN   A   203.0.113.10
shop.example.com.   60   IN   A   203.0.113.11
shop.example.com.   60   IN   A   203.0.113.12

Сервер отдаёт все три адреса, обычно меняя их порядок от запроса к запросу. Идея в том, что клиент возьмёт первый и нагрузка распределится.

Почему на это нельзя опираться — четыре причины, и их надо уметь назвать:

  • Нет проверки здоровья. DNS ничего не знает о состоянии серверов. Один умер — треть клиентов продолжает получать его адрес и получать ошибки. Это главная проблема.
  • Кеширование ломает распределение. Ответ кешируется у резолвера провайдера, а за одним резолвером могут стоять тысячи пользователей — и все они получат один и тот же порядок адресов. Распределение получается не по клиентам, а по резолверам.
  • Клиенты ведут себя по-разному. Кто-то берёт первый адрес, кто-то перебирает при отказе, кто-то кеширует навсегда.
  • Нет весов. Все серверы считаются равными, хотя они могут быть разной мощности.

При этом одно полезное свойство есть: современные клиенты умеют перебирать адреса из списка при отказе. Браузеры это делают надёжно, многие библиотеки — тоже. Поэтому несколько A-записей — приемлемая отказоустойчивость последней надежды, но не механизм распределения нагрузки.

Умный DNS у провайдера

Коммерческие DNS-провайдеры добавляют то, чего в протоколе нет: они сами опрашивают твои серверы и убирают мёртвые из ответов, умеют веса, умеют отдавать разные ответы в зависимости от географии клиента или измеренной задержки.

Работает это заметно лучше, но упирается в тот же TTL: даже при health check переключение занимает время жизни кеша плюс интервал проверки. Меньше 30–60 секунд на практике не получается, а для части клиентов и больше.

Anycast — то, что часто путают с DNS-балансировкой

Здесь балансировки в DNS нет вообще: имя резолвится в один адрес. Фокус в том, что этот адрес анонсируется по BGP из десятков точек мира одновременно, и обычная маршрутизация приводит клиента в ближайшую. Так работают публичные резолверы, корневые серверы DNS и все крупные CDN.

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

Вывод, который стоит произносить

Спросят

«Можно ли балансировать нагрузку через DNS?» — «Технически да — несколько A-записей, и сервер отдаёт их по очереди. Но как балансировщик это плохо: нет проверки здоровья, поэтому мёртвый сервер продолжает получать треть клиентов; ответ кешируется у резолвера, за которым могут стоять тысячи пользователей, поэтому распределение идёт по резолверам, а не по клиентам; нет весов; и клиенты ведут себя по-разному. DNS хорошо решает другую задачу — привести клиента к ближайшей или к правильной точке входа, а дальше уже настоящий балансировщик с health check делает распределение. Настоящая балансировка средствами DNS есть только в SRV-записях с приоритетами и весами, но HTTP-клиенты их не понимают. А то, что часто называют DNS-балансировкой в CDN, — обычно anycast, где адрес один, а выбор делает маршрутизация.»

§9Как резолвит сам клиент

Прежде чем уйти в сеть, система проходит несколько локальных шагов, и знание их порядка экономит часы отладки.

1. /etc/nsswitch.conf — определяет ПОРЯДОК источников: hosts: files dns │ └→ спросить DNS └→ сначала посмотреть в /etc/hosts 2. /etc/hosts — статические записи, всегда побеждают DNS сюда лезут при отладке: «а если направить на другой адрес?» 3. /etc/resolv.conf — куда обращаться и что дописывать nameserver 10.96.0.10 search prod.svc.cluster.local svc.cluster.local options ndots:5 timeout:2 attempts:3 4. кеш системы, если он есть: systemd-resolved, nscd systemd-resolved подставляет в resolv.conf адрес 127.0.0.53 — и тогда настоящие серверы видны только через resolvectl status

Два параметра из resolv.conf заслуживают отдельного объяснения.

search — список суффиксов, которые дописываются к коротким именам. Благодаря ему внутри кластера работает обращение к postgres вместо полного имени. Он же объясняет, почему в своём namespace достаточно имени сервиса, а в чужой надо писать сервис.namespace.

ndots — сколько точек должно быть в имени, чтобы его попробовали резолвить как есть, без дописывания суффиксов. Внутри Kubernetes стоит значение 5, и для внешних адресов это оборачивается лишними запросами: api.stripe.com содержит две точки, значит, сначала будут перебраны все суффиксы из search и только потом настоящее имя. Подробнее и с лечением — в главе 3.1, §8.

Практический вывод: точка в конце имени означает «это полное имя, ничего не дописывай». Запрос api.stripe.com. уходит напрямую, минуя весь перебор. Полезный приём и в конфигурации приложений, и при отладке.

§10dig: как читать вывод

dig — основной инструмент для работы с DNS. В отличие от ping и nslookup, он показывает сырой ответ протокола: какие флаги, какие секции, сколько заняло, кто ответил. Разберём полный вывод по частям — это ровно то, что просят прокомментировать на собеседовании.

$ dig shop.example.com

; <<>> DiG 9.18.1 <<>> shop.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41823
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; QUESTION SECTION:
;shop.example.com.              IN   A          ← о чём спрашивали

;; ANSWER SECTION:
shop.example.com.       287    IN   CNAME  lb-prod.example.com.
lb-prod.example.com.    60     IN   A      203.0.113.10
                         ↑ сколько секунд осталось жить в кеше

;; Query time: 3 msec                          ← 3 мс — значит, из кеша
;; SERVER: 10.96.0.10#53(10.96.0.10) (UDP)     ← кто ответил
;; WHEN: Tue Jul 29 14:02:11 MSK 2025
;; MSG SIZE  rcvd: 96

Что смотреть в первую очередь

status — главное поле. Четыре значения, которые надо различать:

СтатусЧто означает и что делать
NOERRORОтвет получен. Но проверь секцию ANSWER: она может быть пустой — это значит, имя существует, а вот записи запрошенного типа у него нет. Например, есть A, но нет AAAA
NXDOMAINТакого имени не существует. Опечатка, запись не создана, либо отрицательный ответ ещё сидит в кеше (§7)
SERVFAILРезолвер не смог получить ответ. Причины: не отвечают авторитативные серверы, ошибка в делегировании, провалилась проверка DNSSEC. Это не «нет записи», это «сломано по дороге»
REFUSEDСервер отказался отвечать. Обычно ты спросил сервер, который для этой зоны не авторитативен и не хочет делать рекурсию для тебя

flags — четыре буквы, которые стоит понимать:

  • qr — это ответ, а не вопрос. Есть всегда.
  • rd — «recursion desired», клиент попросил рекурсию.
  • ra — «recursion available», сервер её умеет. Отсутствие ra у резолвера означает, что он не будет за тебя ходить по иерархии.
  • aa — «authoritative answer», ответ от сервера, который сам отвечает за зону. Если ты спрашиваешь авторитативный сервер напрямую, а флага aa нет — значит, ты попал не туда или зона на нём не настроена.

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

Команды, которыми реально пользуешься

# только значение — для скриптов и быстрого взгляда
$ dig +short shop.example.com
203.0.113.10

# только секция ответа, но с TTL — самый удобный повседневный вариант
$ dig +noall +answer shop.example.com

# конкретный тип записи
$ dig example.com MX
$ dig example.com TXT
$ dig _ldap._tcp.example.com SRV
$ dig example.com NS

# спросить КОНКРЕТНЫЙ сервер — обход своего резолвера и его кеша
$ dig @8.8.8.8 shop.example.com
$ dig @ns1.provider.net shop.example.com     # спросить авторитативный напрямую

# пройти всю цепочку от корня и увидеть каждый шаг делегирования
$ dig +trace shop.example.com

# обратный резолв
$ dig -x 203.0.113.10

# принудительно по TCP — проверить, что файрвол его пропускает
$ dig +tcp shop.example.com

# проверить подписи DNSSEC
$ dig +dnssec example.com

В бою

Главный приём при разборе «а почему у меня резолвится не то»: сравни ответ своего резолвера с ответом авторитативного сервера. dig shop.example.com — что видишь ты. dig @ns1.provider.net shop.example.com — что там на самом деле. Совпадают — проблема не в DNS. Различаются — это кеш, и надо ждать TTL или чистить. А dig +trace покажет, на каком именно уровне делегирования цепочка уходит не туда — незаменимо после смены серверов имён у регистратора.

§11nslookup и host: зачем они, если есть dig

nslookup — старая утилита, которая есть везде, включая Windows и урезанные образы, где dig не установлен. Это её единственное настоящее преимущество, и оно весомое: когда надо быстро проверить резолв на чужой машине, выбора часто нет.

$ nslookup shop.example.com
Server:     10.96.0.10                # кто отвечал
Address:    10.96.0.10#53

Non-authoritative answer:             # то есть из кеша резолвера
Name:   shop.example.com
Address: 203.0.113.10

# спросить конкретный сервер
$ nslookup shop.example.com 8.8.8.8

# конкретный тип
$ nslookup -type=MX example.com
$ nslookup -type=TXT example.com

# интерактивный режим — удобно, когда надо проверить десяток имён
$ nslookup
> server 8.8.8.8
> set type=A
> shop.example.com
> api.example.com
> exit

Почему dig всё-таки лучше: nslookup не показывает флаги и статус ответа, по-разному ведёт себя в разных реализациях, скрывает детали и иногда молча искажает картину. Фразу «не существует» он выдаёт и на NXDOMAIN, и на SERVFAIL, хотя это совершенно разные диагнозы. Поэтому для разбора — dig, для быстрой проверки там, где ничего больше нет, — nslookup.

host — компромисс: короткий вывод как у nslookup, но поведение честнее и синтаксис проще.

$ host shop.example.com
shop.example.com has address 203.0.113.10
$ host -t MX example.com
$ host 203.0.113.10                # обратный резолв без ключей

Отдельно про systemd-resolved: если в /etc/resolv.conf стоит 127.0.0.53, то dig спрашивает локальный кеш, а не настоящие серверы, и часть картины будет скрыта. Реальную конфигурацию и то, какие серверы используются для каких доменов, показывает resolvectl status, а сбросить кеш — resolvectl flush-caches.

§12Типовые поломки и как их узнавать

СимптомЧто почти навернякаЧем проверить
Создал запись, а её нетВ кеше сидит отрицательный ответ, потому что имя запросили раньше созданияdig @авторитативный — там запись есть; ждать minimum из SOA
У части пользователей старый адресTTL не был опущен заранееdig с разных резолверов, смотреть оставшийся TTL
SERVFAILНе отвечают авторитативные серверы, битое делегирование или провал DNSSECdig +trace, dig +dnssec
Изнутри сети имя ведёт не тудаSplit-horizon: внутренний DNS отдаёт свой ответСравнить dig и dig @8.8.8.8
Не даёт поставить CNAME на доменЭто apex, туда нельзяИспользовать ALIAS/ANAME провайдера или редирект
Работает у одних, не работает у другихРасхождение между NS у регистратора и NS в зоне; либо не все серверы обновилисьСпросить каждый NS по очереди напрямую
Приложение ходит на мёртвый адрес после переключенияПриложение кеширует резолв само и на TTL не смотритПерезапуск как проверка гипотезы; лечится настройкой кеша в рантайме
Резолв иногда занимает 5 секундТаймаут на первом сервере из resolv.conf, потом переход ко второмуdig несколько раз, смотреть Query time; проверить доступность каждого сервера
Большие ответы теряютсяФайрвол пропускает DNS только по UDPdig +tcp и dig +bufsize=4096

§13Как это звучит в ответе

«DNS — иерархия с делегированием: корневые серверы знают, кто отвечает за зоны верхнего уровня, те — кто за домены второго, и только авторитативный сервер зоны знает настоящий ответ. Рекурсию проходит резолвер, клиент задаёт один вопрос. Транспорт — UDP на 53, при большом ответе клиент переспрашивает по TCP, поэтому файрвол должен пропускать оба.

Из записей рабочие: A и AAAA — адреса; CNAME — псевдоним, который нельзя ставить на корень домена и рядом с которым не может быть других записей; NS — делегирование, SOA — параметры зоны, где важны serial и minimum, а minimum это TTL отрицательных ответов; MX с приоритетами, где меньше значит важнее; TXT, на которой держатся SPF, DKIM, DMARC и подтверждение владения доменом; SRV — единственная запись с портом, приоритетами и весами; PTR для обратного резолва, который в основном нужен почте и контролируется владельцем адресов.

Про балансировку: несколько A-записей — это не балансировка, а в лучшем случае отказоустойчивость. Нет проверки здоровья, поэтому мёртвый сервер продолжает получать свою долю клиентов; ответ кешируется у резолвера, за которым стоят тысячи пользователей, поэтому распределение получается по резолверам; нет весов. Умный DNS у провайдера добавляет health check и геопривязку, но переключение всё равно упирается в TTL. Настоящая балансировка с весами есть в SRV, но её понимают только специализированные клиенты. А то, что в CDN называют DNS-балансировкой, — обычно anycast, где адрес один и выбирает маршрутизация.

Разбираю всё это через dig: смотрю statusNOERROR, NXDOMAIN, SERVFAIL и REFUSED означают совершенно разное; смотрю флаг aa, чтобы понять, отвечает ли авторитативный сервер; смотрю оставшийся TTL, чтобы понять, из кеша ли ответ. Главный приём — сравнить свой ответ с ответом авторитативного сервера через dig @ns1...: расходятся — значит, дело в кеше. А dig +trace показывает, на каком уровне делегирования цепочка уходит не туда.»