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

Сервер Socket TCP с высоким RTT и повторными передачами

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

И есть клиент, который запрашивает данные с сервера каждые 50 мс. В ответ клиент получает сообщение OK, если на сервере нет данных или фактически требуемых данных.

Каждый раз, когда клиент делает запрос к серверу, он отправляет фрейм из 5 байтов (не считая 40 дополнительных байтов, поступающих от IP и TCP). С другой стороны, сервер отвечает либо кадром размером 5 байтов (в большинстве случаев), либо кадром размером> 70 байтов (обычно каждую секунду).

С двух сторон розетки ставятся так:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # this line is excluded in client's case
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 8192)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.settimeout(0.5)

В локальной сети все работает нормально (без задержек), но всякий раз, когда я подключаюсь к серверу с общедоступного IP-адреса (я перенаправляю порт), он сильно тормозит. Задержка может доходить до 15 секунд (в этот момент время истекает), что невероятно много. Большую часть времени RTT остается на уровне 200–210 мс. В WireShark я вижу много (ложных) повторных передач и дублирующих ACK.

Что я могу сделать? Я уже отключил алгоритм Нэгла, но пока безуспешно.

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

Захват на стороне клиента

  • У вашего клиента серьезные проблемы с подключением к различным веб-сайтам. Веб-сайты HTTPS (www.bing.com, wdcp.microsoft.com и т. Д.) Не получают ответа после этапа Client Hello, что приводит к повторной передаче и возможному тайм-ауту с вашего устройства. Другой набор HTTP-запросов к веб-сайту, размещенному на Akamai (104.90.152.18), приводит к тайм-ауту запроса 408.
  • Если посмотреть конкретно на трафик от клиента к серверу, подавляющее большинство сеансов начинается нормально, но затем происходит потеря пакетов, что приводит к повторным передачам от клиента и тайм-аутам. Например, проверьте номер пакета 161–207. В пакете 161 клиент отправляет пакет данных на сервер, но не получает ответа, в результате чего клиент повторяет передачу в течение примерно 15 секунд, прежде чем соединение будет разорвано.

    Большинство TCP-потоков демонстрируют такое поведение, поэтому можно сделать вывод, что либо пакеты данных от клиента не достигают сервера, либо ответ сервера не достигает клиента.

  • Что касается задержки, то между ответами SYN и SYN / ACK от сервера существует значительная (и непостоянная) задержка в диапазоне от 168 мс до 770 мс.

Захват на стороне сервера

  • К сожалению, захват на стороне сервера не захватывает те же события, что и захват на стороне клиента. Я также не уверен, где именно в сети это было зафиксировано, поскольку оно включает трафик клиента и сервера. Также отправляются перенаправления ICMP, что указывает на неоптимальную маршрутизацию. Однако я не считаю, что это вызывает проблему.
  • Если вы примените фильтр отображения wirehark для tcp.stream eq 1 || tcp.stream eq 2 вы можете видеть обе стороны общения. В частности, Клиент> Брандмауэр, а затем Брандмауэр> Сервер (и наоборот). Опять же, все начинается нормально, а затем вокруг пакета 407 все становится интересным.

    Пакет № 407 отмечает момент, когда клиент отправляет на сервер порцию новых данных. Маршрутизатор получает это и пересылает на сервер. Сервер отправляет обратно пакет подтверждения (пакет № 410), а также другой небольшой пакет данных (№ 411). Однако мы не видим, что маршрутизатор передает эти пакеты обратно клиенту. - это лучшее доказательство, которое я нашел, что это проблема маршрутизатора.

Сравните это с одним из многих успешных обменов немного дальше по трассировке - например, пакеты с 394 по 406:

  1. (# 394) Клиент отправляет пакет данных на публичный IP-адрес сервера
  2. (# 396) Маршрутизатор получает это и пересылает на локальный IP-адрес сервера
  3. (# 397) Сервер отправляет подтверждение обратно на NAT-IP клиента
  4. (# 398) Сервер отправляет небольшой пакет данных обратно на IP-адрес клиента с NAT.
  5. (# 401) Маршрутизатор отправляет подтверждение обратно на локальный IP-адрес клиента
  6. (# 402) Маршрутизатор отправляет небольшой пакет данных обратно на локальный IP-адрес клиента.
  7. (# 403) Клиент отправляет подтверждение обратно на общедоступный IP-адрес сервера, чтобы подтвердить, что он получил данные, отправленные сервером
  8. (# 406) Маршрутизатор пересылает подтверждение на локальный IP-адрес сервера.

Когда что-то выходит из строя, все останавливается после этапа 4 - два пакета, отправленные с сервера, кажутся отброшенными на маршрутизаторе.

Последние мысли

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