Алгоритм медленного перезапуска для контроля перегрузки

Опубликовано: 16 Сентября, 2022

После установления соединения между клиентом и сервером отправитель отправляет данные получателю в виде пакетов. Если сеть перегружена, пакеты теряются. Это происходит при заполнении буфера устройств-посредников, таких как Router. Отправитель TCP должен определить, не заполнил ли он «буферы на промежуточных устройствах», и если это так, снизить скорость передачи, чтобы сеть могла выйти из «состояния перегрузки». Но есть одна проблема: никто не сообщает отправителю TCP о состоянии «буферов» на промежуточных устройствах.

Отправитель TCP сам «оценивает» состояние буферов на промежуточных устройствах и поддерживает для себя переменную, известную как окно перегрузки (cwnd). Отправитель никогда не отправляет данные, стоимость которых превышает размер окна перегрузки. Допустим, cwnd = 15 пакетов, тогда отправитель не может отправить в сеть 16 пакетов. Эта «оценка», которая выполняется отправителем TCP, учитывает «полный путь» от отправителя TCP до получателя TCP. Это не оценка заполнения буфера на «каждом промежуточном устройстве» между отправителем TCP и получателем TCP. Потому что отправитель не может знать количество промежуточных устройств. Кроме того, маршрут пакета может измениться для одного и того же соединения. Различные пакеты могут выбирать разные маршруты для достижения от отправителя к получателю.

Итак, как начинается «процесс оценки» на отправителе TCP? Каково начальное значение cwnd? Ответ — алгоритм медленного старта.

Алгоритм медленного старта:

Цель: начать процесс «оценки» cwnd и быстро получить «достойную оценку».

Алгоритм

  • Starts with an initial value of cwnd (default is 10 segments in the Linux, it was 1 segment in 1980s)
  • Initial value of cwnd is stored in a separate variable called ‘initcwnd’ in the Linux kernel and it is fixed.
  • When the algorithm begins, cwnd = initcwnd
  • Another way to look at cwnd: ‘the maximum number of segments that a TCP sender can transmit without waiting for an Acknowledgment (ACK)’
  • One more important variable is used in TCP, which is called ‘inflight’ or ‘pipe’
  • inflight/pipe = the number of packets that have been sent but an ACK is not received for those packets i.e., they are ‘inflight’ or ‘in pipe’ between the sender and receiver
  • inflight ≤ cwnd, but it is preferred than inflight = cwnd to utilize the network bandwidth

Иллюстрация :

Изначально cwnd = initcwnd = 10 сегментов. Отправитель отправляет 10 сегментов в поток, не дожидаясь получения единственного подтверждения.
При получении каждого ACK отправитель увеличивает cwnd на 1 сегмент и отправляет в сеть 2 новых сегмента.

cwnd = 10 + 1 = 11, новый cwnd равен 11, но сейчас в полете только 9 сегментов. Отправителю разрешено отправлять сегменты стоимостью cwnd во время полета. Таким образом, отправитель отправляет еще 2 сегмента в полете.

inflight = inflight – 1 + 2 // -1, потому что мы получили ACK, +2, потому что мы отправили 2 новых сегмента
в полете = 10 – 1 = 9 + 2 = 11

Таким образом, если все сегменты успешно подтверждены, cwnd «в конце концов» удвоится за один RTT. Все 10 ACK прибудут к отправителю в течение одного RTT, и к этому времени cwnd станет равным 20. Сейчас в полете 20 сегментов.

Ключ на вынос

cwnd непрерывно увеличивается каждый раз, когда приходит ACK. Отправитель не удваивает cwnd после одного RTT, а постепенно увеличивает его на 1 каждый раз, когда приходит новый ACK. Отправитель TCP не ждет подтверждения «всех 10 сегментов», чтобы увеличить cwnd. Такое поведение приведет к нерациональному использованию пропускной способности сети, поскольку новые сегменты не отправляются до тех пор, пока не будут использованы все ACK и пропускная способность.

Медленный перезапуск:

Когда cwnd достигает своего максимального значения ssthresh или когда обнаруживается потеря пакета, медленный старт прекращается и активируется другой алгоритм, который обрабатывает после этого.

Но когда TCP-соединение простаивает в течение определенного периода времени (равного RTO), отправитель делает недействительной свою оценку cwnd, поскольку она некоторое время не обновляется. Когда отправитель отправляет больше сегментов по истечении определенного периода времени после простоя, он перезапускает алгоритм медленного запуска, чтобы правильно оценить размер окна перегрузки.

AIMD (аддитивное увеличение, мультипликативное уменьшение):

Когда происходит отбрасывание пакета (т. е. отправитель TCP не получает ACK для определенного пакета) или когда алгоритм достигает порога медленного запуска, медленный запуск завершается и начинается AIMD. В начале соединения TCP ssthresh = ∞. ssthresh обновляется, когда происходит отбрасывание пакетов. Он обновляется как ssthresh = cwnd ÷ 2. AIMD уменьшает cwnd на 50 % при обнаружении потери пакетов и увеличивает cwnd на 1 за RTT (не за ACK, в отличие от Slow Start).

В чем проблема, если соединение TCP сбрасывается?

Отправитель TCP должен получить «новую оценку» cwnd, для чего требуется несколько RTT. Пример: предположим, что cwnd = 1024 сегмента, когда соединение TCP было сброшено из-за периода простоя. Теперь отправитель TCP инициализирует cwnd до 10 сегментов и использует алгоритм медленного запуска для увеличения cwnd. Потребуется 10 RTT (1000 мс, если один RTT равен 100 мс), чтобы отправитель TCP получил свой cwnd до 1024 сегментов!

Команды линукса:

Играем с SSR в ядре Linux с помощью следующих команд:

Проверка настройки SSR по умолчанию в ядре Linux

$ sysctl net.ipv4.tcp_slow_start_after_idle

Ожидаемый результат (это означает, что SSR включен):

$ net.ipv4.tcp_slow_start_after_idle = 1

Отключить медленный перезапуск (важно для серверов, но не для клиентов)

$ sudo sysctl -w net.ipv4.tcp_slow_start_after_idle=0

Ожидаемый результат:

$ net.ipv4.tcp_slow_start_after_idle = 0