Исходящие соединения серверов из частной подсети во внешний мир (авторизация на платформе, платежи, внешние API) проходят через NAT-шлюз, который подменяет адрес и порт. Если одновременных соединений к одной цели больше, чем позволяет лимит портов шлюза, новые соединения не устанавливаются.
Почему Серверы открывают много коротких соединений к одному внешнему адресу, например к авторизации на платформе или платёжному сервису, или долго держат соединения открытыми → Следствие NAT-шлюз не может выделить для этой цели ещё один исходный порт, и новое соединение не устанавливается → На экране В самой игре всё нормально, но функции, которые обращаются наружу (вход, платежи, выдача наград), не работают или тормозят (ошибка входа / бесконечная загрузка, съеденные действия / роллбэк)
Сразу после входа или техработ, Вечерний пик, При наплыве игроков
Ответственные
Основной ответственный Команда инфраструктуры · Сетевая инфраструктура · Совместно Команда разработки · Разработка сервера
Команда разработки: задачи
Переиспользовать соединения к внешним API (HTTP keep-alive, пул соединений) и не открывать новое соединение на каждый запрос, для неактивных соединений в пуле слать keepalive чаще таймаута простоя NAT (350 с у AWS) или закрывать их первыми, при ошибках повторять с растущим интервалом и случайным разбросом, записывать долю ошибок и задержку по каждому внешнему вызову.
Команда инфраструктуры: задачи
Добавить IP-адреса на NAT-шлюз (к публичному NAT-шлюзу AWS по умолчанию можно привязать только 2 Elastic IP, для большего нужно запросить повышение квоты), разделить шлюзы по зонам доступности и подсетям, поставить алерты на метрики ошибок выделения портов (AWS ErrorPortAllocation, Failed в Azure SNAT Connection Count, OUT_OF_RESOURCES в Google Cloud dropped_sent_packets_count), в Google Cloud NAT увеличить минимум портов на VM или включить динамическое выделение портов.
Цифры для ориентира
AWS NAT Gateway с одного IP-адреса открывает до 55 000 одновременных соединений к одной цели (IP, порт, протокол), а добавляя IP (до 8), этот предел можно поднять. Соединение, молчавшее 350 с, удаляется, и на последующие пакеты по нему возвращается RST. У Azure NAT Gateway на один публичный IP приходится 64 512 портов SNAT (не больше 16 IP). Google Cloud NAT делит 64 512 портов одного NAT IP между VM, а минимум портов на VM по умолчанию 64 (статическое выделение), поэтому при настройках по умолчанию одна VM обычно может держать к одной цели не больше 64 одновременных соединений.
На графике
Упор в лимит (плато) · число одновременных соединений NAT-шлюза, число ошибок выделения портов
Где смотреть
Сопоставить с моментами ошибок внешних вызовов на игровых серверах метрики NAT-шлюза в CloudWatch для AWS: ErrorPortAllocation, ActiveConnectionCount, PacketsDropCount (в Azure SNAT Connection Count с фильтром по состоянию Failed и Dropped Packets, в Google Cloud dropped_sent_packets_count с reason OUT_OF_RESOURCES)
Подтверждает
В моменты ошибок внешних вызовов ErrorPortAllocation (в Azure SNAT Connection Count в состоянии Failed, в Google Cloud отбрасывания OUT_OF_RESOURCES) больше 0, а ошибки сосредоточены на вызовах к одной-двум целям с большим числом соединений, например к серверам авторизации или платежей
Опровергает
Если ошибок выделения портов 0, а connect на игровом сервере завершается с EADDRNOTAVAIL и число TIME_WAIT близко к размеру диапазона эфемерных портов, это «Исчерпание эфемерных портов в межсерверных соединениях». Если соединение устанавливается, но ответ медленный, это «Зависимость от внешних сервисов»
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Подробнее
Причина «Исчерпание эфемерных портов в межсерверных соединениях» описывает нехватку портов на одном сервере, а здесь лимит действует на NAT-шлюзе и делится между всеми серверами за ним (Google Cloud NAT распределяет порты по VM). Если на серверах TIME_WAIT и диапазон эфемерных портов в порядке, а сбоят только внешние вызовы, причина здесь. Порт закрытого соединения тоже не сразу снова используется для той же цели (у Azure период охлаждения, у Google Cloud порт недоступен на время TIME_WAIT), поэтому чем чаще открываются короткие соединения, тем быстрее достигается лимит.
Источники
NAT gateway basicsAWS 55 000 одновременных соединений к одной цели (IP, порт и протокол назначения) на один IPv4-адрес, предел поднимается добавлением IP до 8 (у публичного NAT-шлюза по умолчанию 2 Elastic IP, больше по запросу на повышение квоты); полоса автоматически растёт с 5 до 100 Gbps, а производительность с 1 до 10 млн пакетов в секунду, сверх этого предела пакеты отбрасываются
NAT gateway metrics and dimensionsAWS ErrorPortAllocation: сколько раз не удалось выделить исходный порт (больше 0 означает слишком много одновременных соединений), ActiveConnectionCount, IdleTimeoutCount (соединения, закрытые после 350 с простоя), PacketsDropCount
Troubleshoot NAT gatewaysAWS После 350 с простоя соединение истекает, и на последующую отправку возвращается RST, рекомендуется keepalive чаще 350 с, при достижении лимита соединений добавить шлюзы по зонам доступности и IP или сократить число соединений
Source Network Address Translation (SNAT) with Azure NAT GatewayMicrosoft Azure 64 512 портов SNAT на один публичный IP (не больше 16 IP), каждому соединению к одной цели нужен отдельный порт, закрытый порт проходит период охлаждения перед повторным использованием для той же цели
Metrics and alerts for Azure NAT GatewayMicrosoft Azure Если SNAT Connection Count с фильтром по состоянию Failed больше 0, вероятно исчерпание портов SNAT, Dropped Packets
IP addresses and portsGoogle Cloud На один NAT IP по 64 512 портов для TCP и для UDP, минимум портов на VM по умолчанию 64 (статическое выделение) и 32 (динамическое), число зарезервированных за VM портов ограничивает число одновременных соединений к одной цели, порт закрытого соединения нельзя использовать на время TIME_WAIT
Logs and metricsGoogle Cloud dropped_sent_packets_count с reason OUT_OF_RESOURCES: пакеты, отброшенные из-за нехватки NAT IP или портов