АрхитектураОблако и инфраструктураИнженер облачной инфраструктуры

Ситуация: множество экземпляров сервиса не может открыть новые исходящие соединения через NAT шлюз, хотя це...

Ситуация: множество экземпляров сервиса не может открыть новые исходящие соединения через NAT-шлюз, хотя целевые узлы доступны. Какой механизм может исчерпать ресурс NAT?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Исторический контекст

NAT появился прежде всего как способ экономить дефицитные IPv4-адреса и скрывать адресацию внутренних сетей. Несколько частных адресов могут выходить во внешнюю сеть через один или несколько публичных адресов.

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

Постановка проблемы

Сервис может успешно разрешать DNS-имя, отправлять пакеты к NAT-шлюзу и получать ответы на уже установленные соединения, но при этом не создавать новые соединения. Это часто ошибочно принимают за отказ целевого сервиса или сетевого ACL.

Риск особенно велик для систем с большим числом короткоживущих TCP-соединений, большим количеством реплик, широким диапазоном внешних адресатов или длительным удержанием соединений в состоянии TIME_WAIT. Повторные попытки могут усугубить ситуацию, создавая ещё больше новых соединений.

Подробное решение

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

У публичного IPv4-адреса ограничен диапазон портов. Точная модель распределения зависит от реализации облачного NAT, но практически важен общий принцип: одновременно обслуживаемое число соединений ограничено доступными портами, публичными IP-адресами и правилами уникальности трансляций.

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

Диагностика должна включать метрики NAT-шлюза: количество активных соединений, ошибки выделения портов, распределение соединений по назначениям и использование публичных адресов. Одновременно нужно проверить состояние локального пула сокетов приложения, время жизни соединений и долю соединений в TIME_WAIT.

Основные способы устранения:

  • переиспользовать соединения через пул HTTP-клиентов и keep-alive;
  • уменьшить создание короткоживущих соединений и настроить разумные тайм-ауты;
  • добавить дополнительные публичные IP-адреса или NAT-шлюзы, если это поддерживается и соответствует лимитам провайдера;
  • распределять исходящий трафик между несколькими шлюзами;
  • использовать IPv6 без NAT там, где это допустимо, сохраняя контроль доступа на уровне firewall;
  • ограничить чрезмерные повторы и применять экспоненциальную задержку с разбросом.

Добавление публичных адресов увеличивает ёмкость, но не устраняет плохое управление соединениями и может усложнить allowlist-ы внешних систем. Увеличение тайм-аутов иногда уменьшает частоту повторных подключений, но чрезмерно долго удерживает ресурсы. Переход на IPv6 убирает именно ограничение NAT для IPv6-трафика, однако требует корректной адресации и защиты периметра.

Ситуация из практики

После масштабирования сервиса с 20 до 200 реплик внешние вызовы начали периодически завершаться по тайм-ауту. Уже открытые соединения продолжали работать, а проблема возникала преимущественно во время пиковых заданий, когда каждая реплика создавала множество коротких TCP-соединений.

Рассматривались три варианта. Увеличение числа повторов было отвергнуто: оно повышало нагрузку на NAT и целевые сервисы. Добавление публичных IP-адресов быстро увеличивало доступную ёмкость, но не решало неэффективное создание соединений. Полная миграция на IPv6 требовала изменений у внешних поставщиков и не подходила как срочная мера.

Выбрали пул HTTP-соединений с ограниченным размером, корректным keep-alive, тайм-аутами и экспоненциальными повторами с разбросом, а затем добавили второй публичный IP для планового запаса ёмкости. После этого снизились число новых TCP-соединений, пиковое потребление NAT-портов и частота тайм-аутов; отдельный мониторинг исчерпания портов сохранили как защитный сигнал.

Что кандидаты часто упускают

1. Достаточно ли добавить ещё один публичный IP, чтобы гарантированно устранить проблему?

Нет. Дополнительный IP обычно расширяет пространство внешних портов, но остаются другие ограничения: лимиты конкретного NAT-сервиса, число записей трансляции, пропускная способность, локальный ephemeral-портовый пул клиентов и лимиты целевого сервиса. Кроме того, новые соединения могут неравномерно распределяться, если архитектура или настройки маршрутизации направляют их через один адрес.

2. Почему большое число коротких запросов опаснее небольшого числа долгих соединений?

Короткие запросы чаще требуют создания и закрытия TCP-соединений, поэтому быстрее расходуют операции выделения портов и создают записи состояний. После закрытия TCP-сокет может некоторое время оставаться связанным с прежним соединением, например в TIME_WAIT, что временно уменьшает доступный пул. Долгоживущий пул соединений удерживает состояния дольше, но при умеренном числе соединений обычно снижает churn и расход портов на единицу трафика.

3. Чем исчерпание NAT-портов отличается от блокировки исходящего трафика правилами безопасности?

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