Операционная система UNIX - Андрей Робачевский
Шрифт:
Интервал:
Закладка:
Описанный синдром может также порождаться и принимающей стороной, которая анонсирует чересчур маленькие окна. Таким образом, для преодоления этих ситуаций, необходима модификация алгоритмов TCP как для отправления, так и для приема данных. К счастью, SWS легко избежать, обязав модули выполнять следующие правила:
1. Принимающая сторона не должна анонсировать маленькие окна. Говоря более конкретно, адресат не должен анонсировать размер окна, больший текущего (который скорее всего равен 0), пока последний не может быть увеличен либо на размер максимального сегмента (Maximum Segment Size, MSS), либо на ½ размера буфера приема, в зависимости от того, какое значение окажется меньшим.
2. Отправитель должен воздержаться от передачи, пока он не сможет передать сегмент максимального размера или сегмент, размер которого больше половины максимального размера окна, который когда-либо анонсировался принимающей стороной.
Однако как мы уже заметили, анализируя причины возникновения SWS, поспешные подтверждения полученных данных сыграли не последнюю роль в этом процессе. С одной стороны, немедленное подтверждение позволяет постоянно держать отправителя "в курсе дела", тем самым избегая ненужных повторных передач. Подтверждение также приводит к смещению окна, и таким образом, позволяет отправителю продолжить передачу данных. С другой стороны, немедленное подтверждение может привести к возникновению SWS и дополнительным накладным расходам.
Хорошим компромиссом между немедленным и отложенным подтверждением можно считать следующую схему. При получении сегмента адресат не отправляет подтверждение, если, во-первых, сегмент не содержит флага PSH (дающего основание полагать, что вслед за полученным сегментом вскоре последуют дополнительные данные), и, во-вторых, отсутствует необходимость отправки обновленного значения окна.
Тем не менее получатель должен установить таймер, который позволит послать подтверждение, если в передаче данных произошел определенный перерыв, что может быть вызвано, например, потерей сегментов.
Медленный старт
Старые реализации TCP начинали передачу, отправляя сегменты в пределах предлагаемого окна, не дожидаясь подтверждения. Это вызывало взрывообразный рост трафика в сети и могло привести к переполнению, в результате которого часть сегментов отбрасывалась и требовалась повторная передача.
Алгоритм, направленный на избежание подобной ситуации, получил название медленного старта (slow start). Основная идея, лежащая в основе этого алгоритма, заключается в том, что на начальном этапе передачи сегменты должны отправляться со скоростью, пропорциональной скорости получения подтверждений.
Реализация этого алгоритма предусматривает использование дополнительного к рассмотренным ранее окна отправителя — окна переполнения (congestion window). При установлении связи с адресатом значение этого окна cwnd устанавливается равным одному сегменту (значению MSS, анонсированному адресатом, или некоторому значению по умолчанию, обычно 536 или 512 байтов). При вычислении доступного окна отправитель использует меньшее из предлагаемого окна и окна переполнения. Каждый раз, когда отправитель получает подтверждение полученного сегмента, его окно переполнения увеличивается на величину этого сегмента.
Легко заметить, что предлагаемое окно служит для управления потоком со стороны получателя, в то время как окно переполнения служит для управления со стороны отправителя. Если первое из них связано с наличием свободного места в буфере приема адресата, то второе — с представлением о загрузке сети у отправителя данных.
Обычно предлагаемое окно больше одного сегмента, поэтому отправитель передает один сегмент и ожидает подтверждения. Когда подтверждение приходит, он увеличивает значение окна переполнения до двух сегментов, таким образом, два сегмента разрешены к передаче. После того как получение каждого из этих сегментов подтверждено, размер окна переполнения становится равным четырем сегментам. Можно показать, что по мере отправления сегментов и получения подтверждений размер окна переполнения растет экспоненциально, соответственно растет и эффективная скорость передачи.[76]
Начиная с некоторого значения скорость передачи достигнет эффективной пропускной способности виртуального канала между источником и получателем, и ее дальнейший рост приведет к потере данных. Начиная с этого момента, включается механизм устранения заторов, который будет обсужден ниже.
Устранение затора
Переполнение, или затор, может возникнуть в сети по многим причинам. Например, если данные поступают к шлюзу по высокоскоростному каналу и должны быть переданы в низкоскоростной канал. Или данные нескольких каналов мультиплексируются в один канал, пропускная способность которого меньше суммы входящих. Во всех этих случаях неизбежна потеря пакетов.
Алгоритмы, позволяющие избежать заторов, основываются на предположении, что потеря данных, вызванная ошибками передачи по физической среде, пренебрежимо мала (гораздо меньше 1%). Следовательно, потеря данных свидетельствует о заторе, произошедшем где-то на пути следования пакета. В свою очередь, о потере данных отправитель может судить по двум событиям: значительной паузе в получении подтверждения или получении дубликата(ов) подтверждения.
Хотя устранение затора и медленный старт являются независимыми механизмами, каждый из которых имеет свою цель, обычно они реализуются совместно. Для их работы необходимо два дополнительных параметра виртуального канала;[77] окно переполнения cwnd и порог медленного старта ssthresh. Работа комбинированного алгоритма определяется следующим правилам:
1. Начальные значения cwnd и ssthresh инициализируются равными размеру одного сегмента и 65535 байтов соответственно.
2. Максимальное количество данных, которое может передать отправитель, не превышает меньшего из значений окна переполнения и предлагаемого окна.
3. При возникновении затора (что определяется по тайм-ауту или получению дубликатов подтверждений) параметр ssthresh устанавливается равным половине текущего окна, но не меньше размера двух сегментов. Если же свидетельством затора является тайм-аут, то дополнительно размер cwnd устанавливается равным одному сегменту, или, другими словами, включается медленный старт.
4. Когда отправитель получает подтверждение, он увеличивает размер cwnd, однако новый размер зависит от того, выполняет ли модуль медленный старт или устранение затора.
Если значение cwnd меньше или равно ssthresh, то TCP находится в фазе медленного старта, в противном случае производится устранение затора. Таким образом, режим медленного старта продолжается до тех пор, пока эффективная скорость передачи не достигнет половины скорости, при которой был обнаружен затор.[78] После этого включается процедура устранения затора.
Как мы только что видели, медленный старт начинается с отправления одного сегмента, затем двух, затем четырех и т.д., что порождает экспоненциальный рост размера окна. В фазе устранения затора вычисление нового значения cwnd производится по следующей формуле при каждом подтверждении сегмента:[79]
cwndn+1 = cwndn + 1/cwndn
Таким образом, формула дает зависимость роста размера окна, при которой максимальная скорость приращения составит не более одного сегмента за время передачи данных туда и обратно (Round Trip Time, RTT), независимо от того, сколько подтверждений было получено. Это утверждение легко доказать. Допустим, в какой-то момент времени размер окна составлял cwndn. Тогда отправитель может передать максимум cwndn/sz сегментов размером sz, на которые он получит такое же число подтверждений. Можно показать, что
cwndn+1 ≤ cwndn + (cwndn/sz)×(1/cwndn) = cwndn + sz
На рис. 6.16 показан рост окна переполнения при медленном старте и последующем устранении затора. Заметим, что переход в фазу устранения затора происходит при превышении размером окна порогового значения ssthresh.
Рис. 6.16. Рост окна переполнения при медленном старте и устранении затора
Повторная передача
До сих пор рассматривалось получение дублированных подтверждений как свидетельство потери сегментов и затора в сети. Однако согласно RFC 1122 "Requirements for Internet Hosts — Communication Layers", модуль TCP может отправить немедленное подтверждение при получении неупорядоченных сегментов. Цель такого подтверждения — уведомить отправителя, что был получен неупорядоченный сегмент, и указать порядковый номер ожидаемых данных. Поскольку ожидаемый порядковый номер остался прежним (получение неупорядоченного сегмента не изменит его значение), данное подтверждение может явиться дубликатом уже отправленного ранее.