Шрифт:
Закладка:
В результате Джейкобсону удалось реализовать высокоуровневое решение, состоявшее в использовании метода AIMD для выбора окна перегрузки. Особенно интересно, что при всей сложности контроля перегрузки в TCP он смог добавить его в уже существующий протокол, не изменив ни одного формата сообщений. Благодаря этому новое решение можно было сразу применять на практике. Сначала Джейкобсон заметил, что потеря пакетов является надежным сигналом перегрузки, даже несмотря на то что эта информация приходит с небольшим опозданием (когда сеть уже перегружена). В конце концов, трудно представить себе маршрутизатор, который не удаляет пакеты при перегрузке, и в дальнейшем это вряд ли изменится. Даже когда буферная память будет исчисляться терабайтами, вероятно, мы будем использовать терабитные сети, которые будут ее заполнять.
Здесь есть одна тонкость. Дело в том, что использование потери пакетов в качестве сигнала перегрузки предполагает, что ошибки передачи происходят сравнительно редко. В случае беспроводных сетей (таких, как 802.11) это не так, поэтому в них используются собственные механизмы повторной передачи данных на канальном уровне. Из-за особенностей повторной передачи в таких сетях потеря пакетов на сетевом уровне, вызванная ошибками передачи, обычно не учитывается. Столь же редко это происходит в проводных и оптоволоконных сетях, поскольку их частота ошибок по битам обычно низкая.
Все алгоритмы TCP для интернета основаны на том предположении, что пакеты теряются из-за перегрузок. Поэтому они внимательно отслеживают тайм-ауты и пытаются обнаружить любые признаки проблемы подобно тому, как шахтеры следят за своими канарейками34. Чтобы узнавать о потере пакетов вовремя и с высокой точностью, необходим хороший таймер повторной передачи. Мы уже говорили о том, как такие таймеры в TCP учитывают среднее значение и отклонение RTT. Усовершенствование таймеров путем учета отклонений стало важным шагом в работе Джейкобсона. Если время ожидания повторной передачи выбрано правильно, TCP-отправитель может отследить количество исходящих байтов, нагружающих сеть, — достаточно сравнить порядковые номера переданных и подтвержденных пакетов.
Теперь наша задача выглядит просто. Все, что нам нужно, — это следить за размером окна перегрузки (с помощью порядковых номеров и номеров подтверждений) и менять его, следуя правилу AIMD. Но как вы уже догадались, на самом деле все гораздо сложнее. Во-первых, способ отправки пакетов в сеть (даже через короткие промежутки времени) должен соответствовать сетевому пути, иначе возникнет перегрузка. Допустим, хост с окном перегрузки 64 Кбайт подключен к коммутируемой сети Ethernet, работающей на скорости 1 Гбит/с. Если хост отправит целое окно за один раз, всплеск трафика может пройти через медленную ADSL-линию (1 Мбит/с), расположенную далее на пути. Всплеск, который длился всего половину миллисекунды на гигабитной линии, парализует медленную линию на целых полсекунды, полностью блокируя такие протоколы, как VoIP. В итоге мы получим отличный протокол для создания перегрузок, а не для борьбы с ними.
Однако отправка небольших порций пакетов может быть полезной. На илл. 6.43 показано, что произойдет, если хост-отправитель, подключенный к быстрой линии (1 Гбит/с), отправит небольшую порцию пакетов (4) получателю, находящемуся в медленной сети (1 Мбит/с), которая является узким местом пути или его самой медленной частью. Сначала эти четыре пакета перемещаются по сети с той скоростью, с которой они были отправлены. Затем маршрутизатор помещает их в очередь, так как они приходят по высокоскоростной линии быстрее, чем передаются по медленной. Это не слишком длинная очередь, поскольку число пакетов, отправленных за один раз, невелико. Обратите внимание, что на медленной линии одни и те же пакеты выглядят длиннее, чем на быстрой, так как их передача длится дольше.
Илл. 6.43. Порция пакетов, переданная отправителем, и скорость прихода подтверждений
Наконец, пакеты попадают к адресату, и он подтверждает их получение. Время отправки подтверждения зависит от времени прибытия пакета по медленному каналу. Поэтому на обратном пути расстояние между пакетами будет больше, чем в самом начале, когда исходные пакеты перемещались по быстрой линии. Оно не изменится на протяжении всего прохождения подтверждений через сеть и обратно.
Здесь особенно важно следующее: подтверждения приходят к отправителю примерно с той же скоростью, с которой пакеты могут передаваться по самому медленному каналу пути. Именно она и нужна отправителю. Если он будет передавать пакеты в сеть с такой скоростью, они будут перемещаться настолько быстро, насколько позволяет самая медленная линия, но зато не будут застревать в очередях на маршрутизаторах. Эта скорость называется скоростью прихода подтверждений (ack clock) и является неотъемлемой частью TCP. Данный параметр позволяет TCP выровнять трафик и избежать ненужных очередей на маршрутизаторах.
Вторая сложность состоит в том, что достижение хорошего рабочего режима согласно AIMD в быстрых сетях потребует очень много времени, если изначально выбрано маленькое окно перегрузки. Рассмотрим средний сетевой путь, позволяющий передавать трафик со скоростью 10 Мбит/с и RTT 100 мс. Здесь удобно использовать окно перегрузки, равное произведению пропускной способности и времени задержки, то есть 1 Мбит, или 100 пакетов по 1250 байт. Если изначально взять окно размером один пакет и увеличивать его на один пакет через интервал времени, равный времени в пути туда-обратно, соединение начнет работать с нормальной скоростью только через 100 RTT, то есть через 10 с. Это очень долго. Теоретически мы можем начать с большего окна — скажем, размером 50 пакетов. Но для медленных линий это значение будет слишком большим, и при отправке 50 пакетов за один раз возникнет перегрузка — о таком сценарии мы говорили выше.
Решение, предложенное Джейкобсоном, объединяет линейное и мультипликативное увеличение. При установлении соединения отправитель задает маленькое окно размером не более четырех сегментов. (Изначально исходный размер окна не превышал один сегмент, но впоследствии он был увеличен до четырех исходя из опыта.) Подробнее об этом рассказывается в RFC 3390. Затем отправитель передает в сеть начальное окно. Получение пакетов подтвердится через временной интервал, равный RTT. Каждый раз, когда подтверждение о получении сегмента приходит до срабатывания таймера повторной передачи, отправитель увеличивает окно перегрузки на длину одного сегмента (в байтах). К тому же если сегмент был получен, в сети становится на один сегмент меньше, и каждый подтвержденный сегмент позволяет отправить еще два. Окно перегрузки удваивается на