dnsmasq: ошибки в AWS — «Temporary failure in name resolution», логи, дебаг и размер кеша

Автор: | 26/10/2019

При использовании AWS VPC DNS периодически сталкиваемся с ошибками вида «php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolution«.

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

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

  • локальный dnsmasq падает, все запросы начинают обрабатываться AWS VPC DNS, у которого есть хард-лимит на 1024 запросов/сек — он исчерпывается, и получаем ошибку разрешения имён
  • превышение кол-ва пакетов на интерфейсе AWS EC2, см. Packets-per-second limits in EC2 и EC2 Packets per Second: Guaranteed Throughput vs Best Effort

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

Prometheus и метрики dnsmasq

Первое, что мы сделали после того, как согласились с предположением, что dnsmasq падает — это добавили его под мониторинг Prometheus с помощью dnsmasq_exporter.

Експортер собирает такие метрики:

...
Question: []dns.Question{
  question("cachesize.bind."),
  question("insertions.bind."),
  question("evictions.bind."),
  question("misses.bind."),
  question("hits.bind."),
  question("auth.bind."),
  question("servers.bind."),
},
...

Их же можно получить запросов типа Chaos (см. DNS classes) с помощью dig.

Например — список upstream-DNS серверов, на которые пересылает запрос dnsmasq, если не находит запись о домене в своём кеше:

[simterm]

root@bttrm-production-console:/home/admin# dig @localhost +short chaos txt servers.bind
"10.0.3.2#53 9301 0" "1.1.1.1#53 402 0"

[/simterm]

Посмотрим resolv.conf:

[simterm]

root@bttrm-production-console:/home/admin# cat /etc/resolv.conf 
domain us-east-2.compute.internal
search us-east-2.compute.internal
nameserver 127.0.0.1
nameserver 10.0.3.2
nameserver 1.1.1.1

[/simterm]

Собственно их dnsmasq и возвращает: 10.0.3.2 — это VPC DNS, 1.1.1.1 — CloudFlare DNS для fallback, если VPC DNS не отвечает (впрочем — не сильно помогает, как видим).

Что они нам дают?

  • cachesize.bind: размер кеша (кол-во доменов, которые хранятся в кеше)
  • insertions.bind: кол-во добавлений записей в кеш
  • evictions.bind: кол-во удаления записей из кеша (по истечении TTL домена или при достижении лимита кеша)
  • misses.bind: кол-во запросов, которые не были найдены в кеше и были перенаправлены апстрим-серверам
  • hits.bind: кол-во запросов, на которые dnsmasq дал ответ из своего кеша
  • auth.bind: кол-во запросов к authority-зонам (dnsmasq может играть роль authority-сервера для доменов)
  • servers.bind: рассмотрели выше — список апстрим-серверов для форвардинга запросов

Используя их — можем построить графики, например — посмотреть соотношение запросов всего — и запросов, на которые dnsmasq ответил из своего кеша:

sum(increase(dnsmasq_hits[1m])) / (sum(increase(dnsmasq_hits[1m])) + sum(increase(dnsmasq_misses[1m])))

Или с выборкой по конкретному хосту:

sum(increase(dnsmasq_hits{host="bttrm-production-console"}[1m])) / (sum(increase(dnsmasq_hits{host="bttrm-production-console"}[1m])) + sum(increase(dnsmasq_misses{host="bttrm-production-console"}[1m])))

Значит — 98 из 100 запросов отданы из кеша — очень неплохо.

dnsmasq debugging

Сам dnsmasq для дебага можно запустить с опциями -d (—no-daemon) и -q (—log-queries):

[simterm]

$ sudo dnsmasq -q -d
dnsmasq: started, version 2.80 cachesize 150
dnsmasq: compile time options: IPv6 GNU-getopt DBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC loop-detect inotify dumpfile
dnsmasq: reading /etc/resolv.conf
dnsmasq: using nameserver 188.190.254.254#53
dnsmasq: using nameserver 31.43.120.254#53
dnsmasq: using nameserver 1.1.1.1#53
dnsmasq: read /etc/hosts - 2 addresses

[/simterm]

Обращаемся к нему:

[simterm]

$ dig @localhost ya.ru +short
87.250.250.242

[/simterm]

Смотрим output:

[simterm]

...
dnsmasq: query[A] ya.ru from ::1
dnsmasq: forwarded ya.ru to 188.190.254.254
dnsmasq: forwarded ya.ru to 31.43.120.254
dnsmasq: forwarded ya.ru to 1.1.1.1
dnsmasq: reply ya.ru is 87.250.250.242
...

[/simterm]

Повторяем запрос — и ещё раз STDOUT:

[simterm]

...
dnsmasq: query[A] ya.ru from ::1
dnsmasq: cached ya.ru is 87.250.250.242
...

[/simterm]

При первом запросе запись в кеше не найдена — и dnsmasq переслал запрос к апстрим-серверам.

При втором запросе — вернул уже cached значение.

Можно добавить extra, что бы добавлять серийный номер к каждой записи, относящейся к конкретному запросу — проще отслеживать запросы, если записей в аутпуте много:

[simterm]

$ sudo dnsmasq --log-queries=extra -d
dnsmasq: started, version 2.80 cachesize 150
dnsmasq: compile time options: IPv6 GNU-getopt DBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset auth DNSSEC loop-detect inotify dumpfile
dnsmasq: reading /etc/resolv.conf
dnsmasq: using nameserver 188.190.254.254#53
dnsmasq: using nameserver 31.43.120.254#53
dnsmasq: using nameserver 1.1.1.1#53
dnsmasq: read /etc/hosts - 2 addresses
dnsmasq: 1 ::1/49217 query[A] ya.ru from ::1
dnsmasq: 1 ::1/49217 forwarded ya.ru to 188.190.254.254
dnsmasq: 1 ::1/49217 forwarded ya.ru to 31.43.120.254
dnsmasq: 1 ::1/49217 forwarded ya.ru to 1.1.1.1
dnsmasq: 1 ::1/49217 reply ya.ru is 87.250.250.242
dnsmasq: 2 ::1/42356 query[A] ya.ru from ::1
dnsmasq: 2 ::1/42356 cached ya.ru is 87.250.250.242

[/simterm]

dnsmasq logging

Кроме мониторинга за самим сервисом — мы добавили сбор его логов в Loki (см. Grafana Labs: Loki — сбор и просмотр логов).

За логгирование отвечает опция log-facility, которой можно задать канал доставки в syslog — по умолчанию это DAEMON, и LOCAL0 при запуске с -d (—no-daemon), см. syslog facility.

Кроме логгирования через syslog — можно просто указать файл лога:

log-facility="/var/log/dnsmasq.log"

И при необходимости там же добавляем log-queries для логгирования ответов на запросы.

Также может пригодится опция log-async, которая включает асинхронную запись — полезно при ключенной log-queries, когда запросов к dnsmasq и записей в лог много.

resolv.conf и resolv.dnsmasq

Имеет смысл вынести апстрим-сервера из resolv.conf и в нём оставить только сам dnsmasq, что бы быть уверенным в том, что все DNS-запросы из системы будут переданы ему, плюс это позволяет иметь динамически обновляемый resolv.conf (например, если он генерируется NetworkManager).

Обновляем resolv.conf:

[simterm]

root@bttrm-production-console:/home/admin# cat /etc/resolv.conf 
domain us-east-2.compute.internal
search us-east-2.compute.internal
nameserver 127.0.0.1

[/simterm]

Далее можно создать новый файл, например resolv.dnsmasq, в котором перечислить апстримы:

[simterm]

root@bttrm-production-console:/home/admin# cat /etc/resolv.dnsmasq
nameserver 10.0.3.2
nameserver 1.1.1.1

[/simterm]

И задать в конфиге /etc/dnsmasq.conf опцию --resolv-file="/etc/resolv.dnsmasq":

...
resolv-file="/etc/resolv.dnsmasq"
...

Перед рестаром проверяем синтаксис конфига:

[simterm]

root@bttrm-production-console:/home/admin# dnsmasq --test
dnsmasq: syntax check OK.

[/simterm]

--servers

Другой вариант — вместо создания /etc/resolv.dnsmasq указать апстримы прямо в конфиге через опцию server:

server=10.0.3.2
server=1.1.1.1

Кроме того,  спомощью server можно задать конкретные апстримы для конкретных доменов.

Например, что бы выполнять разрешение имени backend-db2-slave.example.com исключительно через VPC DNS 10.0.3.2 — задаём в конфиге следующую запись:

...
server=/backend-db2-slave.example.com/10.0.3.2
...

При этом dnsmasq продолжит считывать resolv.conf. Что бы отключить это — добавьте no-resolv.

--strict-order

По умолчанию dnsmasq отпрашивает все известные ему апстрим-сервера, и первый, который ответит на запрос становится primarydnsmasq будет стараться отправить запросы через него. При этом это может быть любой DNS сервер из resolv.conf, resolv.dnsmasq или из списка server в конфиге.

Для того, что бы dnsmasq использовал сервер строго в порядке очереди — добавляем в конфиг опцию strict-order.

Размер кеша dnsmasq

И один из самых интересных вопросов — какой размер кеша стоит устанавливать для dnsmasq?

Значение по умолчанию — 150 записей, максимальное — 10000.

Задаётся с помощью опции cachesize, например:

cachesize=1000

Но как узнать — надо ли его увеличивать?

SIGUSR1

Для этого — можно сдампить всю статистику работы dnsmasq с момента его запуска с помощью сигнала SIGUSR1:

[simterm]

root@bttrm-production-console:/home/admin# pkill -USR1 dnsmasq && cat /var/log/syslog | grep dns | tail -6
Oct 26 10:53:45 localhost dnsmasq[30433]: time 1572076425
Oct 26 10:53:45 localhost dnsmasq[30433]: cache size 150, 0/45516 cache insertions re-used unexpired cache entries.
Oct 26 10:53:45 localhost dnsmasq[30433]: queries forwarded 22241, queries answered locally 633009
Oct 26 10:53:45 localhost dnsmasq[30433]: queries for authoritative zones 0
Oct 26 10:53:45 localhost dnsmasq[30433]: server 10.0.3.2#53: queries sent 11352, retried or failed 0
Oct 26 10:53:45 localhost dnsmasq[30433]: server 1.1.1.1#53: queries sent 46, retried or failed 0

[/simterm]

В котором мы видимо невероятно много полезной информации:

  • time 1572076425 — время с момента запуска сервера в UNIX epoch
  • cache size 150, 0/45516 cache insertions re-used unexpired cache entries«добавление в кеш с вытеснением записей с неистёкшим временем жизни» — как раз показатель того, что кеша не хватает: если операции добавления новых записей в кеш начинают вытеснять из него записи, у которых ещё не истёк TTL, заданный для домена его SOA (может быть переопределно в помощью --min-cache-ttl для dnmasq) — значит, места в кеше мало
  • queries forwarded 22241, queries answered locally 633009 — количество запросов, не найденных в кеше, и перенаправленных апстриму (возвращается из misses.bind), и кол-во запросов, обработанных самим dnsmasq из кеша (значение из hits.bind)
  • queries for authoritative zones — при использовании dnsmasq в роли SOA, кол-во запросов к authority-зонам
  • server 10.0.3.2#53: queries sent 11352, retried or failed 0 — та самая строка, которая теоретически поможет нам, когда случится очередной «php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolution» — можно будет увидеть, были ли ошибки от AWS VPC DNS

AWS «Temporary failure in name resolution»

Пока писал этот пост — как раз проскочило несколько ошибок.

Выглядит это так:

При этом в дампе dnsmasq всё по-прежнему отлично:

[simterm]

root@bttrm-production-console:/home/admin# pkill -USR1 dnsmasq && cat /var/log/syslog | grep dns | tail -6
Oct 26 11:12:36 localhost dnsmasq[30433]: time 1572077556
Oct 26 11:12:36 localhost dnsmasq[30433]: cache size 150, 0/49227 cache insertions re-used unexpired cache entries.
Oct 26 11:12:36 localhost dnsmasq[30433]: queries forwarded 24327, queries answered locally 724600
Oct 26 11:12:36 localhost dnsmasq[30433]: queries for authoritative zones 0
Oct 26 11:12:36 localhost dnsmasq[30433]: server 10.0.3.2#53: queries sent 12949, retried or failed 0
Oct 26 11:12:36 localhost dnsmasq[30433]: server 1.1.1.1#53: queries sent 590, retried or failed 0

[/simterm]

Ошибок от VPC DNS нет, кеша хватает — всё нормально.

Зато — явно видно проседание по кол-ву отправленных пакетов (график за день):

И полученных:

И что бы это значило? При этом все сервисы работают нормально — проблемы наблюдаются только с DNS-запросами.

Пока не ясно, но в целом — проблема, судя по всему, не с DNS вообще, и не dnsmasq в частности.

Наблюдаем дальше.

Ссылки по теме