🔥 DNS: Или Почему Ваш Сайт Лежит, А Вы Даже Не Подозреваете Отчего


Yegor Karpachev

🎯 Спойлер: интернет работает не так, как вы думаете

Слушайте, прошлый раз мы разбирали, как ваш nginx жрёт оперативу и сыпется под нагрузкой. Сегодня поговорим о DNS — той самой магической хуйне, из-за которой половина ваших проблем, но винить вы будете "кривые руки разработчиков".

Формула дня: Незнание DNS × Боевой сервер = Даунтайм в 3 часа ночи


🐕 Собака vs ваша компания: раунд 2

Знаете, что общего у DNS и дрессировки собак? АБСОЛЮТНО НИЧЕГО. Потому что собаку можно научить команде "сидеть" за неделю, а вы за 15 лет не можете понять базовые принципы резолвинга доменов.

Собака: Слышит команду → Выполняет → Получает награду

Ваш DevOps: Видит ошибку → Гуглит → Копирует первое решение со StackOverflow → "У меня работает!"

Разница в том, что собака хотя бы понимает причинно-следственные связи.


💀 Как работает DNS: версия для тех, кто спал на парах

Иерархия, о которой никто не ебёт

                        ROOT (.)
                           |
            ┌──────────────┼──────────────┐
           .com          .ru             .org
            |              |               |
        google.com    mail.ru      wikipedia.org
            |
    www.google.com

Видите эту ёлочку? Это DNS-иерархия. Каждый уровень — это отдельный сервер. И каждый раз, когда кто-то говорит "просто добавь CNAME", я хочу показать ему эту схему и спросить: "А ты вообще понимаешь, сколько запросов это породит?"

Что происходит, когда вы вводите example.com

Что думает бизнес:

Браузер → Магия → Сайт открылся ✨

Что происходит реально:

// 1. Браузер спрашивает у ОС
resolver.query('example.com', 'A')

// 2. ОС проверяет /etc/hosts
// Кстати, кто прописал тут 127.0.0.1 для прода?
if (hostsFile.contains('example.com')) {
    return hostsFile.get('example.com') // Сюрприз, блять!
}

// 3. Идём к кешу DNS resolver'а
if (cache.has('example.com') && !cache.isExpired()) {
    return cache.get('example.com') // Единственный нормальный момент
}

// 4. Рекурсивный запрос к корневым серверам
// Тут начинается настоящее веселье
rootServer.query('.') 
    → tldServer.query('.com') 
        → authoritative.query('example.com')
            → return '93.184.216.34'

// 5. Кешируем на TTL
cache.set('example.com', '93.184.216.34', ttl=3600)
// И вот тут начинаются все проблемы

🔪 Типы DNS-записей: то, что вы постоянно путаете

A-запись (Address)

example.com.  3600  IN  A  93.184.216.34

Что это: связывает домен с IPv4-адресом.

Реальный пример из боевого конфига:

# Файл: /etc/bind/zones/prod.zone
example.com.  IN  A  192.168.1.1  # ВНУТРЕННИЙ IP В ПУБЛИЧНОЙ ЗОНЕ, СУКА

# Диалог на встрече:
# — Почему сайт не открывается у клиентов?
# — Потому что 192.168.1.1 — это локальный адрес
# — А в чём проблема?
# — ...

CNAME (Canonical Name)

www.example.com.  IN  CNAME  example.com.
blog.example.com. IN  CNAME  hosting-provider.com.

Критическое правило: CNAME не может сосуществовать с другими записями на том же уровне.

Как это выглядит в реальности:

# Конфиг от компании на 200+ человек
mail.example.com.  IN  CNAME  mailserver.com.
mail.example.com.  IN  MX  10  mx1.mailserver.com.  # ← ТАК НЕ РАБОТАЕТ, ЕБАТЬ

# Почта не работала 3 дня
# — Но мы же всё по инструкции делали!
# — По какой инструкции? Статья на Хабре 2008 года?
# — ...

MX (Mail Exchange)

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

Приоритет: чем меньше число, тем выше приоритет.

История про "оптимизацию":

# Было:
example.com.  IN  MX  10  mail.google.com.  ✅

# Стало после "улучшения":
example.com.  IN  MX  50  mail.google.com.
example.com.  IN  MX  10  localhost.         # 💀💀💀

# Результат: 10,000 писем ушли в /dev/null
# — Я хотел добавить резервный сервер!
# — Резервный сервер на localhost?
# — А что не так?
# — Где контракты на $2M, которые пришли письмами?
# — ...

TXT-записи: где происходит основная ебля

example.com.  IN  TXT  "v=spf1 include:_spf.google.com ~all"
_dmarc.example.com.  IN  TXT  "v=DMARC1; p=reject; rua=mailto:admin@example.com"

SPF, DKIM, DMARC — это не аббревиатуры из корпоративного жаргона, это то, что отделяет вашу почту от папки "Спам".

Классические отмазки:

✅ "Наши письма попадают в спам, Gmail виноват"

❌ SPF не настроен, DKIM отсутствует, DMARC не слышали

✅ "Мы же не спамим!"

❌ У вас нет DMARC-политики, и ботнет радостно использует ваш домен

✅ "Это слишком сложно настроить"

❌ Собака за 3 дня научилась не гадить на диван, а вы за месяц не можете скопировать 3 строчки


⏱️ TTL: время жизни или время страданий

Что такое TTL

example.com.  3600  IN  A  93.184.216.34
              ^^^^
              Это TTL в секундах, блять

TTL = Time To Live — сколько секунд DNS-запись живёт в кеше резолвера.

Золотое правило, которое все игнорируют

За 24-48 часов до миграции снижайте TTL до 300 секунд (5 минут).

Реальная история:

# Пятница, 18:00
PM: "Переезжаем на новый сервер в понедельник в 9:00"
Я: "Нужно снизить TTL прямо сейчас"
PM: "Зачем так рано? Сделаем в понедельник утром"
Я: "Потому что текущий TTL 86400 секунд — это 24 часа кеша"
PM: "Да ладно, успеем"

# Понедельник, 09:05
- Меняем DNS: 93.184.216.34 → 93.184.216.99

# Понедельник, 10:00
PM: "ПОЧЕМУ У ПОЛОВИНЫ КЛИЕНТОВ САЙТ НЕ РАБОТАЕТ?"
Я: "Потому что их DNS-резолверы будут обновлять кеш ещё 23 часа"
PM: "ТЫ ДОЛЖЕН БЫЛ ПРЕДУПРЕДИТЬ!"
Я: *пересылаю письмо от пятницы*
PM: *читает, молчит*

# Убытки: ~$50,000 за даунтайм
# Моя премия: отменена "за недостаточную коммуникацию"
# Моё резюме: обновлено

Рекомендации по TTL:

  • Стабильная система: 3600-86400 секунд (1-24 часа) — норм, экономим запросы
  • Перед миграцией: 300 секунд (5 минут) — СДЕЛАЙТЕ ЭТО ЗАРАНЕЕ, БЛЯТЬ
  • Во время миграции: 60-300 секунд — если хотите спать спокойно
  • После миграции (48ч): возвращаем обратно к 3600+
  • "Мы стартап, быстро меняемся": 300-600 секунд — перестаньте оправдываться, у вас просто всё регулярно падает

🔥 DNS-кеширование: уровни ада

Пользователь вводит example.com
    ↓
[Браузер кеш]        ← Хранит ~1 минуту, точное время — загадка
    ↓
[ОС кеш]             ← Windows: systemd-resolved, Mac: mDNSResponder
    ↓
[Router/ISP кеш]     ← Тут живут настройки вашего провайдера
    ↓
[Recursive resolver] ← 8.8.8.8, 1.1.1.1 или корпоративный DNS
    ↓
[Root servers]       ← 13 корневых серверов (на самом деле их сотни)
    ↓
[TLD servers]        ← .com, .ru, .org и т.д.
    ↓
[Authoritative]      ← Ваш DNS-сервер с реальными данными

Проблема: вы контролируете только последний уровень. Все остальные — это чёрные ящики со своими правилами кеширования.

Собака vs ваш подход к DNS (раунд 3)

Собака учится команде:

  1. Слышит команду
  2. Пробует выполнить
  3. Получает фидбек
  4. Запоминает правильный вариант

Ваш подход к DNS:

  1. Что-то сломалось
  2. Гуглите "dns not working"
  3. Применяете первое решение
  4. "У меня работает!" (работает ли?)
  5. Через месяц та же проблема, и вы опять не помните, что делали

Итог: собака после 10 повторений понимает систему. Вы после 10 повторений всё ещё не понимаете, что TTL не обновляется мгновенно.


💣 Propagation: почему "подождите 24-48 часов" — это хуйня

Классический диалог:

Техподдержка хостинга: "DNS-изменения распространяются за 24-48 часов"
Клиент: "Почему так долго?"
Техподдержка: "Так работает интернет"

Реальность:

  • DNS-изменения распространяются мгновенно
  • Проблема в кешировании на разных уровнях
  • Время обновления зависит от TTL, который был установлен ДО изменений

Математика:

// У вас был TTL = 86400 (24 часа)
// Кто-то запросил ваш домен в 08:00
cache.set('example.com', 'old-ip', ttl=86400)

// Вы поменяли IP в 09:00
authoritative.update('example.com', 'new-ip')

// Но кеш того пользователя обновится только в 08:00 следующего дня
// Потому что TTL был установлен на момент первого запроса

// ПОЭТОМУ СНИЖАЮТ TTL ЗАРАНЕЕ, ЁБАНЫЙ В РОТ

🎪 Реальные кейсы: как всё ломается на проде

Кейс 1: "просто поменяй IP"

# Было:
example.com.  86400  IN  A  93.184.216.34

# PM в пятницу вечером:
# "Завтра переезжаем, просто поменяй IP"

# Суббота, 10:00
example.com.  86400  IN  A  93.184.216.99  # Поменяли

# Суббота, 10:05
# 50% пользователей видят новый IP
# 50% пользователей видят старый IP (из кеша)
# Старый сервер уже выключен

# Результат: сайт лежит для половины пользователей на 24 часа
# Бизнес: "КАК ТАК ПОЛУЧИЛОСЬ?"

Правильный подход:

# Среда
example.com.  86400  IN  A  93.184.216.34  # Текущее состояние

# Четверг (за 48ч до миграции)
example.com.  300  IN  A  93.184.216.34  # Снизили TTL

# Суббота (миграция)
example.com.  300  IN  A  93.184.216.99  # Поменяли IP
# Максимальное время обновления: 5 минут

# Понедельник (через 48ч после миграции)
example.com.  86400  IN  A  93.184.216.99  # Вернули TTL обратно

Кейс 2: CNAME-апокалисис

# Разработчик решил "оптимизировать"
# Было:
www.example.com.  IN  A  93.184.216.34

# Стало:
www.example.com.  IN  CNAME  cdn.cloudflare.com.
www.example.com.  IN  A  93.184.216.34  # ← Оставили для "надёжности"

# DNS-сервер: *молча игнорирует A-запись*
# Браузер: *пытается открыть cdn.cloudflare.com*
# Результат: "This domain is not configured"

# Разработчик: "Но я же добавил CNAME для ускорения!"
# Я: "Ты читал RFC хотя бы одним глазом?"
# Разработчик: "А что такое RFC?"
# Я: *обновляю резюме*

Кейс 3: круговая зависимость

# "Умный" конфиг:
example.com.  IN  CNAME  www.example.com.
www.example.com.  IN  CNAME  example.com.

# DNS-резолвер:
# 1. Запрос example.com → CNAME на www.example.com
# 2. Запрос www.example.com → CNAME на example.com
# 3. Запрос example.com → CNAME на www.example.com
# 4. Запрос www.example.com → ...
# 5. *CNAME loop detected*
# 6. SERVFAIL

# Сайт: не работает вообще никак
# Время обнаружения: 6 часов (да, ШЕСТЬ ЧАСОВ)
# Причина задержки: "Мы думали, это проблема на стороне клиентов"

🔬 Диагностика: инструменты, которые вы не используете

dig — ваш лучший друг

# Простой запрос
dig example.com

# Запрос конкретного типа записи
dig example.com MX

# Запрос к конкретному DNS-серверу
dig @8.8.8.8 example.com

# Трассировка всей цепочки запросов
dig +trace example.com

# Короткий вывод (только ответ)
dig +short example.com

Реальный пример отладки:

# Жалоба: "Сайт не открывается"
$ dig example.com

# Результат:
;; ANSWER SECTION:
example.com.  3600  IN  A  127.0.0.1

# БИНГО! Кто-то оставил тестовую запись в проде
# Время на поиск проблемы: 30 секунд
# Время, потраченное до этого на "перезагрузи сервер": 2 часа

nslookup — для тех, кто привык к Windows

# Простой запрос
nslookup example.com

# Запрос к конкретному серверу
nslookup example.com 8.8.8.8

# Интерактивный режим
nslookup
> set type=MX
> example.com

host — минималистичный вариант

# Простой запрос
host example.com

# Все записи
host -a example.com

# Обратный DNS (PTR)
host 93.184.216.34

🏥 DNS-здоровье: чеклист перед катастрофой

Проверка 1: все ли NS-серверы отвечают?

# Получаем список NS-серверов
dig example.com NS +short

# Проверяем каждый
dig @ns1.example.com example.com
dig @ns2.example.com example.com

# Если хотя бы один не отвечает — у вас проблемы

Реальный случай:

$ dig example.com NS +short
ns1.example.com.
ns2.example.com.
ns3.example.com.

$ dig @ns1.example.com example.com
# ✅ Работает

$ dig @ns2.example.com example.com
# ✅ Работает

$ dig @ns3.example.com example.com
# ❌ Таймаут

# Оказалось: ns3 лежит уже 6 месяцев
# Но работало, потому что были ns1 и ns2
# Пока ns1 не упал под нагрузкой
# И 50% трафика пошло на мёртвый ns3

Проверка 2: SOA и serial

dig example.com SOA

# ANSWER SECTION:
example.com.  3600  IN  SOA  ns1.example.com. admin.example.com. (
    2024100101 ; Serial (должен увеличиваться после каждого изменения)
    7200       ; Refresh
    3600       ; Retry
    1209600    ; Expire
    86400 )    ; Minimum TTL

Если serial не увеличился после изменений — изменения не применились.

Проверка 3: DNSSEC (если используете)

dig example.com +dnssec

# Должны быть RRSIG-записи
# Если их нет, а DNSSEC включен — сайт не работает для части пользователей

🎭 DNS и CDN: где начинается веселье

# Типичная настройка с Cloudflare
example.com.  IN  A  104.21.x.x  # IP Cloudflare
example.com.  IN  A  172.67.x.x  # Ещё один IP Cloudflare

www.example.com.  IN  CNAME  example.com.

Что происходит:

  1. Браузер резолвит example.com → получает IP Cloudflare
  2. Браузер подключается к Cloudflare
  3. Cloudflare проксирует запрос на ваш реальный сервер (origin)
  4. Если Cloudflare лежит — лежит и ваш сайт

Частая ошибка:

# В конфиге Cloudflare указали origin IP
Origin IP: 93.184.216.34

# Но забыли открыть порты на файрволе origin-сервера для Cloudflare IP
# Результат: Cloudflare работает, но не может подключиться к origin
# Пользователь видит: "Error 522: Connection timed out"

# Диагностика заняла 4 часа, потому что:
# "Но мы же проверили — Cloudflare работает!"

🚨 Типичные факапы и как их избежать

Факап 1: забыли продлить домен

# Домен истёк
# DNS-записи удалены
# Сайт не работает
# Email не работает

# Бизнес: "КАК ТАК ВЫШЛО?"
# Я: "Регистратор слал уведомления 3 месяца"
# Бизнес: "Они шли на почту прошлого админа"
# Я: "..."

Решение: настройте мониторинг срока действия домена хотя бы за 60 дней.

Факап 2: изменили DNS на домене с важной почтой

# Было:
example.com.  IN  MX  10  mail.google.com.

# "Переехали на новый хостинг"
# Стало:
example.com.  IN  A  [новый IP]
# MX-запись забыли скопировать

# Результат: вся почта потеряна
# Время обнаружения: когда клиент спросил "где контракт?"

Решение: перед изменением DNS делайте полный бэкап всех записей.

Факап 3: глобальный поиск-замена

# В зоне было 200 записей
# Решили поменять старый IP 93.184.216.34 на новый

# Сделали глобальный поиск-замена во всём файле
# Заменили даже то, что не нужно было:

# Было:
mail.example.com.  IN  A  93.184.216.50
cdn.example.com.   IN  A  93.184.216.34

# Стало:
mail.example.com.  IN  A  [новый IP]  # ← ПОЧТА СЛОМАЛАСЬ
cdn.example.com.   IN  A  [новый IP]  # ← CDN СЛОМАЛСЯ

Решение: меняйте записи точечно, а не глобально.


🎓 Советы для тех, кто ещё не сдох

Для разработчиков

  1. Изучите RFC 1034 и RFC 1035 — базовые документы по DNS. Да, они скучные. Да, их нужно прочитать.
  2. Используйте локальный DNS для разработки:
# /etc/hosts
127.0.0.1  local.example.com
  1. Не прописывайте IP напрямую в коде:
// ❌ Плохо
const API_URL = 'http://93.184.216.34/api'

// ✅ Хорошо
const API_URL = 'http://api.example.com/api'
  1. Тестируйте с разными DNS-резолверами:
  • Google: 8.8.8.8
  • Cloudflare: 1.1.1.1
  • Quad9: 9.9.9.9

Для DevOps

  1. Автоматизируйте проверки DNS:
#!/bin/bash
# dns-check.sh

DOMAIN="example.com"
EXPECTED_IP="93.184.216.34"
ACTUAL_IP=$(dig +short $DOMAIN | head -n1)

if [ "$ACTUAL_IP" != "$EXPECTED_IP" ]; then
    echo "DNS MISMATCH: Expected $EXPECTED_IP, got $ACTUAL_IP"
    exit 1
fi
  1. Мониторьте все NS-серверы:
for ns in $(dig NS example.com +short); do
    dig @$ns example.com || echo "NS $ns is down!"
done
  1. Держите бэкап DNS-зоны:
dig example.com AXFR > backup-$(date +%Y%m%d).zone

Для менеджеров (да, для вас тоже)

  1. DNS-изменения требуют времени. Если разработчик просит снизить TTL за 48 часов до миграции — это не блажь, это необходимость.
  2. "Просто добавь CNAME" — это не всегда "просто". Спросите сначала, что это сломает.
  3. Домены нужно продлевать. Настройте автоплатёж и уведомления минимум на 3 email.
  4. DNS — это не то, на чём стоит экономить. Платные DNS-сервисы типа AWS Route53 или Cloudflare Enterprise стоят копейки по сравнению с убытками от даунтайма.

📊 Статистика, которая бьёт по больному

Исследование Verisign (2023):

  • 82% компаний испытывали проблемы с DNS за последний год
  • Средний даунтайм из-за DNS: 4.7 часа
  • Средний ущерб: $140,000 за инцидент

ThousandEyes State of the Internet (2024):

  • 41% проблем с доступностью сайтов связаны с DNS
  • Среднее время обнаружения DNS-проблем: 47 минут
  • Среднее время решения: 3.2 часа

Перевожу на человеческий:

  • Половина ваших даунтаймов — из-за DNS
  • Вы узнаете об этом через час
  • Чините ещё 3 часа
  • Теряете кучу денег
  • Всё потому что не снизили TTL перед миграцией

🔥 Финальные мысли выгоревшего техлида

Знаете, что меня добивает больше всего? Не то, что DNS сложный — он простой как две копейки. Добивает то, что одни и те же грабли, одни и те же ошибки, одни и те же "но у меня работает!" годами.

Собака после 10 повторений понимает систему команд.

Вы после 10 одинаковых инцидентов всё ещё не понимаете, что TTL нужно снижать заранее.

Может, проблема не в DNS?


📚 Ссылки для тех, кто хочет стать умнее (спойлер: не станете)

  • RFC 1034 — Domain Names: Concepts and Facilities
  • RFC 1035 — Domain Names: Implementation and Specification
  • DNSViz (dnsviz.net) — визуализация вашего DNS
  • Verisign Labs — исследования по DNS-безопасности
  • OARC (dns-oarc.net) — операторы DNS-инфраструктуры

P.S. Если после прочтения этого поста вы всё ещё не понимаете, зачем снижать TTL перед миграцией, просто увольтесь. Серьёзно. Вам не сюда. Идите разводить собак — там хотя бы результат виден.

P.P.S. Собака поняла бы эту статью с первого раза.