Компьютерные сети. 6-е изд. - Эндрю Таненбаум
Шрифт:
Интервал:
Закладка:
Еще одна проблема, способная значительно снизить производительность протокола TCP, известна под названием синдрома глупого окна (silly window syndrome) (Кларк; Clark, 1982). Ее суть в том, что данные пересылаются TCP-подсистемой крупными блоками, но принимающая сторона интерактивного приложения считывает их посимвольно. Чтобы разобраться в этом, рассмотрим илл. 6.41. Начальное состояние таково: TCP-буфер приемной стороны полон (то есть размер его окна равен нулю), и отправителю это известно. Затем интерактивное приложение читает один символ из TCP-потока. Принимающая TCP-подсистема радостно сообщает отправителю, что размер окна увеличился и что он теперь может отправить 1 байт. Отправитель повинуется и передает 1 байт. Буфер снова заполняется, о чем получатель сообщает с помощью подтверждения для 1-байтного сегмента с нулевым размером окна. И так может продолжаться вечно.
Дэвид Кларк предложил запретить принимающей стороне отправлять информацию об однобайтовом размере окна. Вместо этого получатель должен подождать, пока в буфере не накопится значительное количество свободного места. В частности, получатель не должен отправлять сведения о новом размере окна, пока не сможет принять сегмент максимального размера (который он объявлял при установке соединения) или пока его буфер не освободится хотя бы наполовину. Кроме того, увеличению эффективности передачи может способствовать сам отправитель, отказываясь от отправки слишком маленьких сегментов. Вместо этого он должен подождать, пока размер окна не станет достаточно большим для отправки полного сегмента (или хотя бы равного половине размера буфера получателя).
В задаче избавления от синдрома глупого окна алгоритм Нейгла и решение Кларка дополняют друг друга. Нейгл пытался решить проблему приложения, предоставляющего данные TCP-подсистеме посимвольно. Кларк старался разрешить проблему приложения, посимвольно получающего данные у TCP. Оба решения хороши и могут работать одновременно. Суть их заключается в том, чтобы не отправлять и не просить передавать данные слишком малыми порциями.
Для повышения производительности принимающая TCP-подсистема может делать нечто большее, чем просто обновлять информацию о размере окна крупными порциями. Как и отправляющая TCP-подсистема, она может буферизировать данные и блокировать запрос READ (чтение данных), поступающий от приложения, пока у нее не накопится значительный объем данных. Таким образом снижается количество обращений к TCP-подсистеме (и вместе с ними накладные расходы). Конечно, такой подход увеличивает время ответа, но для неинтерактивных приложений, например, при передаче файла, эффективность может быть важнее увеличения времени ответа на отдельные запросы.
Илл. 6.41. Синдром глупого окна
Еще одна проблема получателя состоит в том, что сегменты могут приходить не по порядку. Он будет хранить данные в буфере, пока не сможет передать их приложению в нужной последовательности. В принципе, нет ничего плохого в том, чтобы отвергать пакеты, прибывшие не в свою очередь, ведь они все равно будут повторно переданы отправителем, однако это неэффективно.
Подтверждение может быть выслано, только если все данные, включая подтверждаемый байт, получены. Это накопительное подтверждение. Если до получателя доходят сегменты 0, 1, 2, 4, 5, 6 и 7, он может подтвердить получение данных вплоть до последнего байта сегмента 2. Когда у отправителя истечет время ожидания, он передаст сегмент 3 еще раз. Если к прибытию сегмента 3 получатель сохранит в буфере сегменты с 4-го по 7-й, он сможет подтвердить получение всех байтов, включая последний байт сегмента 7.
6.5.9. Управление таймерами в TCP
В TCP используется множество таймеров (по крайней мере, в теории). Наиболее важным из них является таймер повторной передачи (Retransmission TimeOut, RTO), который запускается при отправке сегмента. Если подтверждение получения сегмента придет раньше окончания заданного интервала, таймер останавливается. И наоборот, если период ожидания истечет раньше, чем прибудет подтверждение, сегмент передается еще раз (а таймер запускается снова). Соответственно, возникает вопрос: насколько долгим должен быть интервал времени ожидания?
На транспортном уровне эта проблема значительно сложнее, чем в протоколах канального уровня. Например, в 802.11 величина ожидаемой задержки измеряется в микросекундах, и ее довольно легко предсказать (у нее небольшой разброс), поэтому таймер можно установить на момент чуть позднее ожидаемого прибытия подтверждения (илл. 6.42 (а)). Поскольку перегрузок нет, подтверждения на канальном уровне задерживаются редко, поэтому их отсутствие в течение установленного временного интервала с большой вероятностью означает потерю фрейма или подтверждения.
TCP вынужден работать в совершенно иных условиях. Функция плотности вероятности для времени, необходимого для доставки подтверждения TCP, выглядит скорее как график на илл. 6.42 (б), чем на илл. 6.42 (а). Она более пологая и вариативная. Поэтому предсказать, сколько времени потребуется для прохождения данных от отправителя к получателю и обратно, весьма непросто. Даже если бы мы знали, каким должно быть это время, есть еще одна сложность — выбор подходящего интервала ожидания. Если он слишком короткий (например, T1 на илл. 6.42 (б)), возникнут излишние повторные передачи, заполняющие интернет бесполезными пакетами. Если же установить слишком большое значение (T2), то из-за увеличения времени ожидания в случае потери пакета пострадает производительность. При этом среднее значение и величина дисперсии времени прибытия подтверждений могут измениться за несколько секунд при возникновении и устранении перегрузки.
Илл. 6.42. Плотность вероятности времени прибытия подтверждения: (а) на канальном уровне; (б) для TCP
Решение состоит в использовании динамического алгоритма, который постоянно меняет период ожидания, основываясь на измерениях производительности сети. Алгоритм, широко применяемый в TCP, разработан Джейкобсоном (Jacobson) в 1988 году и работает следующим образом. Для каждого соединения в TCP предусмотрена переменная SRTT (Smoothed Round-Trip Time — усредненное время в пути туда-обратно), в которой хранится текущее наилучшее ожидаемое время получения подтверждения для данного соединения. При отправке сегмента запускается таймер, который измеряет время получения подтверждения и повторяет передачу, если оно не приходит в срок. Если подтверждение успевает вернуться до истечения периода ожидания, TCP-подсистема подсчитывает время, которое понадобилось для его получения (R). Затем значение переменной SRTT обновляется по следующей формуле:
где α — весовой