Мы начали с инструментальной диагностики DNS-резолвинга на проблемных серверах. Первый инструмент — strace для анализа системных вызовов при запросе curl:
# Трассировка DNS-резолвинга curl
$ strace -e trace=network,write curl -o /dev/null -s https://api.external-service.com
# Вывод (ключевые строки):
connect(7, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 7
connect(7, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.0.0.2")}, 16) = 0
sendmmsg(7, ...) = 2 # Отправляем A и AAAA запросы
poll([{fd=7, events=POLLIN}], 1, 5000) = 1
recvfrom(7, ..., 2048, 0, ...) = 56 # Получаем ответ
recvfrom(7, ..., 65536, 0, ...) = 114 # Дополнительные записи
connect(8, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("203.0.113.45")}, 16) = 0
Здесь видно полный процесс: попытка подключения к NSCD (кэширующий демон, отсутствует), создание UDP-сокета, отправка запросов, получение ответов. Задержка на этапе poll() показывала время ожидания ответа от DNS-сервера.
Важнейший момент, который не понимала команда клиента: утилиты dig и nslookup используют функцию res_query() напрямую, минуя NSS. А curl, ping и большинство приложений используют getaddrinfo(), который проходит через NSS.
# dig использует res_query() — отправляет запрос напрямую DNS-серверу
$ dig api.internal.cloudsoft.local
;; Query time: 2 msec # Быстро!
# curl использует getaddrinfo() → NSS → dns → resolv.conf
$ time curl -o /dev/null -s https://api.internal.cloudsoft.local
real 0m0.487s # Медленно!
# Разница в 240 раз!
Команда клиента тестировала DNS через dig и получала ответы за 2 мс. Поэтому DNS не рассматривался как причина проблемы. Но реальные приложения шли другим путём, где накапливались задержки.
Оставить комментарий