Некоторый исходный контекст для этого вопроса. В настоящее время у меня есть кластер приложений, развернутый за ALB, который поддерживает постоянные соединения с приложением. Это приложение постоянно находится под большой нагрузкой и должно иметь очень долгое время безотказной работы. ALB отправил обратно 502 кода состояния неверного шлюза от этой службы. Копаем глубже и после захвата pcap и sysdig на затронутых экземплярах мы видим следующее (упорядоченное по последовательности событий):
19:51:26.881806 10.23.34.195 10.23.67.39 HTTP 1068 POST /api HTTP/1.1 (application/json)
19:51:26.881838 10.23.67.39 10.23.34.195 TCP 66 80→52026 [ACK] Seq=7201 Ack=19033 Win=67072 Len=0 TSval=240987 TSecr=1566420
19:51:27.018305861 0 node (2989) > writev fd=120(<4t>10.23.34.195:52026->172.17.0.2:3000) size=400
19:51:27.018326 10.23.67.39 10.23.34.195 HTTP 466 HTTP/1.1 200 OK (application/json)
19:51:27.018341806 0 node (2989) < writev res=400 data=HTTP/1.1 200 OK..Content-Type: application/json; charset=
19:51:27.018601 10.23.34.195 10.23.67.39 TCP 66 52026→80 [ACK] Seq=19033 Ack=7601 Win=47360 Len=0 TSval=1566454 TSecr=241021
19:51:32.042525 10.23.34.195 10.23.67.39 HTTP 1066 POST /api HTTP/1.1 (application/json)
19:51:32.042538 10.23.67.39 10.23.34.195 TCP 66 80→52026 [ACK] Seq=7601 Ack=20033 Win=69120 Len=0 TSval=242277 TSecr=1567710
19:51:32.066469320 0 node (2989) > close fd=120(<4t>10.23.34.195:52026->172.17.0.2:3000)
19:51:32.066470002 0 node (2989) < close res=0
19:51:32.066487 10.23.67.39 10.23.34.195 TCP 66 80→52026 [RST, ACK] Seq=7601 Ack=20033 Win=69120 Len=0 TSval=242283 TSecr=1567710
Как указано выше, похоже, что наше приложение nodejs достигает 5 секунд бездействия в поддерживающем соединении (период ожидания по умолчанию), затем получает сетевой запрос, затем закрывает сокет и, наконец, отвечает на поставленный в очередь сетевой запрос с помощью RST .
Таким образом, похоже, что ошибки 502 возникают из-за состояния гонки, когда новый запрос получен от балансировщика нагрузки между или во время разрыва TCP.
Наиболее очевидное решение этой проблемы - гарантировать, что балансировщик нагрузки является источником истины при разрыве этих подключений, гарантируя, что время простоя балансировщиков нагрузки меньше таймаута на сервере приложений. Это решение работает с классическими балансировщиками нагрузки AWS, но не с ALB, как указано в их документах:
Вы можете установить значение тайм-аута простоя как для балансировщиков нагрузки приложений, так и для классических балансировщиков нагрузки. Значение по умолчанию - 60 секунд. При использовании Application Load Balancer значение времени ожидания простоя применяется только к интерфейсным подключениям.
Может ли кто-нибудь предположить, почему AWS, возможно, удалил тайм-аут простоя серверной части (я предполагаю, что это бесконечность)? Я мог бы также установить для тайм-аута сохранения активности на сервере узла значение Infinity, но следует ли мне беспокоиться об утечке сокетов? Могут ли они использовать какие-либо другие серверные технологии, которые решают эту проблему более изящно, чтобы исправить эту проблему (без использования классических балансировщиков нагрузки)?
Также служба поддержки AWS заявляет, что они не будут уважать заголовок Keep-Alive, отправленный обратно из службы.
Не кажется разумным полагать, что ALB держит внутренние соединения открытыми бесконечно, а скорее, что настраиваемый Тайм-аут применяется только к интерфейсным соединениям.
Меня немного беспокоит, сколько времени прошло между приездом и ACK запроса по адресу: 32.042 и закрытие fd по адресу: 32.066. Вы отключаете соединение, которое, возможно, на самом деле не простаивает - он принял запрос на 24 мс раньше. (!?) Для меня это на удивление «долгое» время.
Как указано на той же странице в документации,
Классические балансировщики нагрузки используют предварительно открытые соединения, а балансировщики нагрузки приложений - нет.
Вам не нужно беспокоиться об утечке дескрипторов, поскольку ALB не будет открывать соединения, которые ему на самом деле не нужны для обслуживания запросов ... но вам также не нужно бесконечное время ожидания.
Вопрос, по-видимому, заключается в том, как долго ALB держит открытыми незанятые внутренние соединения - что, похоже, недокументировано, но я просмотрю свои журналы и посмотрю, смогу ли я найти доказательства того, что может быть установлен таймер, если он статичен. (Удержание внутренних соединений открытыми, конечно, предназначено для оптимизации производительности.)
Интуиция подсказывает, что вы можете попробовать 75-секундный таймер на своей стороне. Это значения по умолчанию, которые я установил на основе классического поведения балансировщика, и я не заметил никаких проблем с ALB, вставленными на их место.
Мы не можем знать причину, по которой у них этого нет. Мы не можем знать решения по дизайну / реализации AWS, которые вызывают такое поведение. Только люди, которые работают с Amazon над этой функцией, знают, и они, скорее всего, находятся под соглашением о неразглашении.
Ваш единственный шанс получить достоверный ответ - это спросить AWS.