Задержка в сетях TCP/IP-over-Ethernet

Задержка в сетях TCP/IP-over-Ethernet

Какие ресурсы (книги, веб-страницы и т. д.) вы бы порекомендовали:

  • объяснить причины задержек в сетях TCP/IP-over-Ethernet;
  • укажите инструменты для поиска вещей, вызывающих задержку (например, определенные записи в netstat -s);
  • предложить способы настройки стека TCP в Linux для уменьшения задержки TCP (Nagle, буферы сокетов и т. д.).

Самое близкое, что я знаю, этоэтот документ, но он довольно краткий.

Вы также можете ответить на приведенные выше вопросы напрямую.

редактироватьЧтобы было ясно, вопрос не только о "ненормальной" задержке, а о задержке вообще. Кроме того, речь идет именно о TCP/IP-over-Ethernet, а не о других протоколах (даже если у них лучшие характеристики задержки).

решение1

Что касается настроек ядра для задержки, то на ум приходит одна:

echo 1 > /proc/sys/net/ipv4/tcp_low_latency

Издокументация:

Если установлено, стек TCP принимает решения, которые предпочитают меньшую задержку, а не большую пропускную способность. По умолчанию эта опция не установлена, что означает, что предпочтительна большая пропускная способность. Примером приложения, где это значение по умолчанию должно быть изменено, может служить вычислительный кластер Beowulf. По умолчанию: 0

Вы также можете отключить алгоритм Нагля в своем приложении (который будет буферизировать выходные данные TCP до максимального размера сегмента) с помощью чего-то вроде:

#include <sys/types.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <linux/tcp.h>

int optval = 1;
int mysock;

void main() {
    void errmsg(char *msg) {perror(msg);exit(1);}

    if((mysock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
        errmsg("setsock failed");
    }

    if((setsockopt(mysock, SOL_SOCKET, TCP_NODELAY, &optval, sizeof(optval))) < 0) {
        errmsg("setsock failed");
    }

    /* Some more code here ... */

    close(mysock);
}

«Противоположность» этой опции — TCP_CORK, которая «перенаглит» пакеты. Однако будьте осторожны, так как TCP_NODELAYможет не всегда делать то, что вы ожидаете, а в некоторых случаях может ухудшить производительность. Например, если вы отправляете большие объемы данных, вам нужно будет максимизировать пропускную способность на пакет, поэтому установите TCP_CORK. Если у вас есть приложение, требующее немедленной интерактивности (или когда ответ намного больше запроса, что сводит на нет накладные расходы), используйте TCP _NODELAY. С другой стороны, это поведение специфично для Linux, а BSD, скорее всего, отличается, поэтомупредостережение администратора.

Обязательно проведите тщательное тестирование своего приложения и инфраструктуры.

решение2

По моему опыту, самая главная причинааномальныйзадержка в других здоровых высокоскоростных сетях — это TCP Windowing (RFC1323, раздел 2) сбоев, с тесно связанным вторым сбоями, связанными с задержкой подтверждения TCP (RFC1122 раздел 4.2.3.2). Оба эти метода являются усовершенствованиями TCP для лучшей обработки высокоскоростных сетей. Когда они ломаются, скорость падает до очень низкого уровня. Сбои в этих случаях влияют на большие передачи (например, резервные потоки), тогда как чрезвычайно транзакционный небольшой трафик (средняя передача данных меньше размера MTU и есть МНОГО пересылок туда-сюда) будет меньше затронут ими.

Опять же, я видел самые большие проблемы с этими двумя проблемами, когда общались два разных стека TCP/IP. Например, Windows/Linux, 2.4-Linux/2.6-Linux, Windows/NetWare, Linux/BSD. Подобное к подобному работает очень, очень хорошо. Microsoft переписала стек Windows TCP/IP в Server 2008, что привело к проблемам взаимодействия Linux, которых не было в Server 2003 (я считаю, что они исправлены, но я не уверен в этом на 100%).

Разногласия относительно точного метода отложенных или выборочных подтверждений могут привести к таким случаям:

192.168.128.5 -> 192.168.128.20: полезная нагрузка 1500b, SEQ 1562
192.168.128.5 -> 192.168.128.20: полезная нагрузка 1500b, SEQ 9524
[200 мс проходит]
192.168.128.20 -> 192.168.128.5: ACK 1562
192.168.128.5 -> 192.168.128.20: полезная нагрузка 1500b, SEQ 12025
192.168.128.5 -> 192.168.128.20: полезная нагрузка 1500b, SEQ 13824
[200 мс проходит]
192.168.128.20 -> 192.168.128.5: ACK 12025

Пропускная способность падает ниже плинтуса из-за всех этих 200-мс тайм-аутов (по умолчанию Windows устанавливает таймер отложенного подтверждения на 200 мс). В этом случае обе стороны разговора не смогли обработать TCP Delayed Ack.

Ошибки TCP Windowing заметить сложнее, поскольку их влияние может быть менее очевидным. В крайних случаях Windowing полностью терпит неудачу, и вы получаете пакет->ack->packet->ack->pack->ack, что очень медленно при передаче чего-либо значительно большего, чем 10 КБ, и увеличит любойфундаментальная задержкана канале. Более сложный для обнаружения режим — когда обе стороны постоянно пересматривают размер своего окна, и одна сторона (отправитель) не соблюдает согласование, что требует обработки нескольких пакетов, прежде чем данные смогут продолжить передаваться. Этот тип неисправности отображается красным мигающим светом в трассировках Wireshark, но проявляется как более низкая, чем ожидалось, пропускная способность.


Как я уже упоминал, вышеперечисленное, как правило, мешает большим передачам. Трафик, такой как потоковое видео или потоки резервного копирования, может быть действительно заблокирован ими, как и простая загрузка очень больших файлов (например, файлов ISO дистрибутивов Linux). Как оказалось, TCP Windowing был разработан как способ обойти фундаментальные проблемы с задержкой, поскольку он позволяет конвейеризировать данные; вам не нужно ждать время приема-передачи для каждого отправленного пакета, вы можете просто отправить большой блок и дождаться одного ACK перед отправкой следующего.

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

решение3

На этот вопрос существует множество ответов.

Помните, как работает TCP. Клиент отправляет SYN, сервер отвечает SYN/ACK, а клиент отвечает ACK. Как только сервер получил ACK, он может отправлять данные. Это означает, что вам придется ждать в 2 раза больше времени на круговую передачу (RTT), чтобы отправить первый бит значимых данных. Если у вас 500 мс RTT, вы получите задержку в 1 секунду прямо с самого начала. Если сеансы короткие, но многочисленные, это создаст большую задержку.

После установления сеанса сервер отправляет блоки данных, которые должны быть подтверждены клиентом. Сервер может отправить только определенное количество данных в дикой природе, прежде чем ему потребуется подтверждение первого блока данных. Это также может создать задержку. Если блок данных теряется, вам придется продолжить передачу оттуда и, следовательно, создать дополнительную задержку.

На уровне IP у вас есть фрагментация (хотя сегодня это встречается довольно редко). Если вы отправляете кадры размером 1501 байт, а другая сторона поддерживает только MTU в 1500, вы отправите дополнительный пакет IP только для этого последнего бита данных. Это можно преодолеть, используя кадры Jumbo.

Лучший способ увеличить пропускную способность TCP/IP — максимально уменьшить задержку и максимально избегать ошибок передачи. Я не знаю ни о каких настройках ядра, но уверен, что кто-то знает.

решение4

Вероятно, это не тот ответ, который вы ищете: главная причина задержек в WAN — это скорость света (она слишком медленная!). Кроме того, насыщенные соединения с большим буфером на пути, как правило, приобретают впечатляющую задержку.

Связанный контент