Назад | Перейти на главную страницу

Как настроить TCP для высокочастотных соединений между двумя узлами

Последние несколько дней я чешу затылок, пытаясь найти решение следующей проблемы:

В нашем центре обработки данных у нас есть F5, работающий на оборудовании BigIP, который действует как единая точка входа для HTTPS-запросов от клиентских машин в различных офисах по всей стране. F5 завершает TLS, а затем перенаправляет все запросы на два балансировщика нагрузки Traefik, которые направляют запросы на различные экземпляры службы (узлы Traefik работают в Docker в Red Hat Enterprise, но я считаю, что это не имеет отношения к моей проблеме). С точки зрения пропускной способности, ЦП и памяти, эти три сетевых компонента более чем способны обрабатывать количество запросов и трафика с большой емкостью.

Однако мы заметили частые задержки в 1000 мс в запросах HTTP (S), которые делают клиенты, особенно во время высокой нагрузки. Мы отследили проблему до следующей основной причины:

Очевидно, что задержки в 1000 мс абсолютно неприемлемы. Итак, мы рассмотрели следующие решения:

  1. Уменьшите RTO в F5 для более быстрой повторной передачи, например до 200 мс.
  2. Уменьшите net.ipv4.tcp_fin_timeout, чтобы закрыть заброшенный ВРЕМЯ ЖДЕТ соединения быстрее.
    Обновить: Это применимо только к соединениям, разорванным другой стороной, когда FIN не возвращается. Это не влияет на соединения в состоянии TIME_WAIT.
  3. Включить net.ipv4.tcp_tw_reuse: бесполезен для входящих подключений.
  4. Включить net.ipv4.tcp_tw_recycle: AFAIK противопоказано, если клиент отправляет случайные временные метки TCP. Противоречивая информация (включая эмпирические данные), была ли эта функция удалена из Linux или нет. Кроме того, обычно рекомендуется НЕ связываться.
  5. Добавьте больше исходных IP-адресов и / или заставьте Traefik прослушивать несколько портов, чтобы увеличить количество перестановок в кортежах IP / портов.

Я откажусь от №1, потому что это просто пластырь. Задержки все еще случаются, только чуть менее заметные. №3 в любом случае не будет иметь никакого эффекта, №4, скорее всего, сделает систему нефункциональной. Что оставляет # 2 и №5.

Но исходя из того, что я узнал после прочтения десятков сообщений и технических статей, в конечном итоге оба они уменьшить шанс этих "столкновений". Потому что то, что в конечном итоге мешает отправляющей стороне, F5, (псевдо) случайным образом выбирать комбинацию эфемерного порта, исходного IP-адреса и целевого порта, которая все еще существует в состоянии TIME_WAIT на целевом хосте Traefik, независимо от того, насколько коротка настройка fin_timeout (которая все равно должен оставаться в многосекундном диапазоне)? Мы только уменьшим вероятность столкновений, но не устраним их.

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

Случайные мысли и моменты:

Обновить: Per Звездный эксперимент, настройка net.ipv4.tcp_fin_timeout НЕ влияет на состояние TIME_WAIT, только на состояние FIN_WAIT_2. И за Самир Джафферали, в системах Linux (включая нашу Red Hat Linux) период TIME_WAIT жестко задан в исходном коде и не может быть настроен. В BSD, согласно источнику, это настраивается, но я этого не проверял.

В нашем центре обработки данных есть F5, работающий на оборудовании BigIP, который действует так как не замужем точка входа для запросов HTTPS с клиентских машин в наших офисах по всей стране.

Если эта единственная точка (интерфейсная часть) остается единственной, когда она передает соединения на сервер, почему вы задаетесь вопросом об икоте? Особенно, если интенсивность подключений «возможно 100+ в секунду».

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

в конечном итоге только уменьшают вероятность этих "столкновений"

Это положено в основу работы сетей с коммутацией пакетов. Скажем, на уровне Ethernet тоже есть коллизии. Случайность неизбежна, и TCP / IP борется с ней. Сам IP-протокол был построен не для локальных сетей (но и там тоже отлично работает).

Так что да, «Добавить больше исходных IP-адресов и / или заставить Traefik прослушивать несколько портов» - довольно разумный способ следовать.

Хотя я также считаю, что добавление дополнительных IP-адресов - это самый простой способ продвижения вперед, рассматривали ли вы возможность повторного использования TCP-соединений между узлами F5 и Traefik вместо создания нового для каждого внешнего запроса?

Я не уверен, как F5 поддерживает это, но, возможно, это так же просто, как переключение на http2 между узлами F5 и Traefik. Видеть https://developers.google.com/web/fundamentals/performance/http2#one_connection_per_origin

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

Короче говоря: все экземпляры Traefik настроены как контейнеры с ограничениями по хосту (т. Е. Привязаны к определенным хостам), работающие в кластере Docker Swarm. Экземпляры Traefik должны предоставлять порт на уровне хоста, чтобы они стали доступными из F5, который, очевидно, не является участником Docker Swarm. Эти открытые порты были настроены в входить режим, который был не только ненужным (не нужно было маршрутизировать трафик через входную сеть Docker Swarm), но также был причиной отброшенных / проигнорированных пакетов SYN. Как только мы переключили режим порта на хозяин, пропали задержки.

Перед:

  ports:
  - target: 8080
    published: 8080
    protocol: tcp
    mode: ingress

После:

  ports:
  - target: 8080
    published: 8080
    protocol: tcp
    mode: host