6.7. Вопросы производительности

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

К сожалению, понимание производительности сетей — это скорее искусство, чем наука. Теоретическая база, допускающая хоть какое-то практическое применение, крайне скудна. Лучшее, что мы можем сделать, это представить практические методы, полученные в результате долгих экспериментов, и привести несколько реальных примеров. Мы отложили эту дискуссию до того момента, когда уже изучен транспортный уровень, поскольку производительность, доступная приложениям, зависит от общей производительности транспортного, сетевого и канального уровней. К тому же мы сможем приводить TCP в качестве примера.

В следующих разделах мы обсудим основные вопросы производительности сети:


1. Проблемы производительности.

2. Оценка производительности сети.

3. Оценка пропускной способности сетей доступа.

4. Оценка QoE.

5. Проектирование хостов для быстрых сетей.

6. Быстрая обработка сегментов.

7. Сжатие заголовка.

8. Протоколы для протяженных сетей с высокой пропускной способностью.

Таким образом, мы рассмотрим производительность с точки зрения операций, выполняемых на хостах и при перемещении данных по сети, а также с точки зрения размера и быстродействия сети.


6.7.1. Проблемы производительности компьютерных сетей

Некоторые проблемы производительности вызваны временным отсутствием свободных ресурсов. Если на маршрутизатор внезапно прибывает больше трафика, чем он способен обработать, возникает перегрузка, и производительность резко падает. Мы подробно изучали перегрузку в этой и предыдущей главах.

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

Перегрузка может быть синхронной. Например, если сегмент содержит неверный параметр (например, номер порта назначения), как правило, получатель заботливо отсылает обратно сообщение об ошибке. Теперь представьте, что случится, если неверный сегмент будет разослан широковещательным способом на 10 000 компьютеров. Каждый из них может ответить сообщением об ошибке. Образовавшийся в результате широковещательный шторм (broadcast storm) может парализовать сеть.

UDP часто сталкивался с подобной проблемой, но затем протокол ICMP был изменен таким образом, чтобы хосты воздерживались от отправки сообщений об ошибке в ответ на широковещательные сегменты UDP. Беспроводным сетям особенно важно не отвечать на непроверенные широковещательные пакеты, поскольку их пропускная способность ограниченна.

Синхронная перегрузка может возникнуть после сбоя электроснабжения. Когда питание восстанавливается, все компьютеры начинают перезагружаться. Типичная последовательность перезапуска может потребовать обращения к какому-нибудь DHCP-серверу, чтобы узнать свой истинный адрес, а затем к файловому серверу, чтобы получить копию операционной системы. Если сотни компьютеров центра обработки данных обратятся к серверу одновременно, он, скорее всего, не справится с нагрузкой.

Даже в отсутствие синхронной перегрузки и при достаточном количестве ресурсов производительность может снижаться из-за неправильных системных настроек. Допустим, у компьютера мощный процессор и много памяти, но недостаточно ресурса выделено под буфер. В таком случае управление потоком данных замедлит получение сегментов и ограничит производительность. Это было проблемой для многих TCP-соединений, поскольку интернет становился быстрее, а окно управления потоком оставалось фиксированным (64 Кбайт).

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

Еще одна проблема касается приложений, работающих в реальном времени (например, воспроизводящих аудио и видео), — джиттер. В этом случае для хорошей производительности недостаточно оптимальной средней пропускной способности. Таким приложениям нужна низкая задержка. Для этого требуется эффективное распределение нагрузки на сеть, а также поддержка QoS на канальном и сетевом уровнях.


6.7.2. Оценка производительности сети

Производительность сетей оценивают все — и сетевые операторы, и пользователи. Чаще всего измеряется пропускная способность (или просто «скорость») сетей доступа. Многие интернет-пользователи проверяют производительность своих сетей доступа с помощью таких инструментов, как Speedtest (www.speedtest.net). Традиционная проверка сводилась к попытке отправить в сеть как можно больше трафика с максимально возможной скоростью (тем самым полностью заполнив канал связи). Но по мере увеличения скорости сетей задача оценки скорости канала доступа становится все более сложной. Теперь для полного заполнения канала требуется гораздо больше данных, а узкие места на тестируемом пути между клиентом и сервером могут смещаться в другие области сети. Пожалуй, важнее всего то, что скорость становится менее актуальным параметром производительности сети. На передний план выходят качество пользовательского опыта и производительность приложения. Как следствие, методы оценки производительности сетей продолжают развиваться, особенно в отношении гигабитных сетей доступа.


6.7.3. Оценка пропускной способности сетей доступа

Традиционный подход к оценке пропускной способности сети состоит в следующем. По сетевому пути передается максимально допустимое количество данных в течение заданного периода времени. Затем объем отправленных данных делится на время, затраченное на их передачу, и выводится среднее значение пропускной способности. Будучи простым и пригодным для большинства случаев, данный подход все же имеет ряд недостатков. Главным минусом является то, что одно TCP-соединение часто не может исчерпать емкость сетевого канала, особенно с учетом того, что скорость каналов доступа продолжает расти. Кроме того, когда тест охватывает начальную стадию процесса передачи, он может отражать скорость до перехода в установившийся режим (например, при медленном старте TCP). В итоге это может привести к занижению пропускной способности. Наконец, проверки на стороне клиента (такие, как speedtest.net или любой другой тест пропускной способности, который можно запустить с клиентского устройства) очень часто выявляют другие проблемы производительности, помимо ограничений сетей доступа (например, ограничения канала радиосвязи устройства или беспроводной сети).

Эти проблемы проявляются все более остро по мере того, как скорость сетей доступа начинает преодолевать гигабитный рубеж. Для их решения был разработан ряд практических рекомендаций по оценке пропускной способности сетей доступа (Фимстер и др.; Feamster et al., 2020). Первая рекомендация состоит в том, чтобы использовать несколько параллельных TCP-подключений для заполнения емкости канала доступа. Проверка первых версий тестов скорости показала, что для заполнения емкости сети обычно достаточно четырех TCP-соединений (Сундаресан и др.; Sundaresan et al., 2011). В большинстве современных клиентских инструментов, включая Speedtest, а также тест пропускной способности, используемый Федеральной комиссией по связи в США, для оценки емкости сети применяется минимум четыре параллельных соединения. Некоторые из этих инструментов даже позволяют увеличивать число параллельных подключений для проверки каналов с высокой емкостью.

Пропускная способность канала доступа интернет-провайдера начинает превышать емкость домашней сети (и других компонентов сквозного пути), поэтому становится все более актуальной вторая практическая рекомендация. Она сводится к оценке пропускной способности сети доступа непосредственно из домашнего маршрутизатора. Это минимизирует риск искажения результатов теста из-за внешних ограничивающих факторов (например, ограничений клиентского устройства или беспроводной сети пользователя).

По мере дальнейшего роста скоростей могут появиться дополнительные рекомендации, к примеру оценивать скорость соединения сразу с несколькими хостами в интернете, используя один канал доступа. Такой подход особенно актуален, когда проблемы на стороне сервера могут приводить к появлению в сети новых узких мест. Постоянный рост скорости также породил повышенный интерес к разработке так называемых пассивных тестов пропускной способности, которые не вводят в сеть большие объемы дополнительного трафика, а просто отслеживают движение данных по сети и пытаются оценить ее емкость просто на основе наблюдений. На данный момент еще не существует надежного пассивного метода оценки пропускной способности сетей доступа, но со временем этот подход, вероятно, позволит оценивать пропускную способность узких мест примерно так же, как алгоритм BBR оценивает величину задержки и скорость доставки.


6.7.4. Оценка QoE

Рано или поздно с увеличением скорости сетей самым важным показателем производительности, вероятно, станет не их скорость (то есть пропускная способность), а соответствие работы приложений ожиданиям пользователя. Как правило, в случае видео пользовательский опыт в какой-то момент перестает зависеть от пропускной способности (Рамачандран и др.; Ramachandran et al., 2019). При потоковой видеопередаче он в основном определяется тем, как быстро начинается воспроизведение (то есть насколько велика задержка запуска), требует ли видео повторной буферизации и каково его разрешение. При этом если скорость превышает 50 Мбит/с, все эти факторы главным образом зависят не от пропускной способности канала доступа, а от других свойств сети (задержка, джиттер и т.д.).

Соответственно, современные средства оценки производительности сети выходят за рамки простого тестирования скорости. Их задача — оценить качество пользовательского опыта, QoE; обычно это происходит путем пассивного наблюдения за сетевым трафиком. Подобные средства оценки находят все более широкое распространение в случае потокового видео (Ахмед и др.; Ahmed et al., 2017; Кришнамурти и др; Krishnamoorthy et al., 2017; Мангла и др.; Mangla et al., 2018; Бронзино и др; Bronzino et al., 2020). Проблемой пока является распространение такой оптимизации на большее число видеосервисов, а в конечном итоге и на более широкий круг приложений (включая игры, виртуальную реальность и т.д.).

Очевидно, что QoE является критерием того, насколько человек доволен предоставляемым ему сервисом. В конечном счете этот показатель носит субъективный характер и часто требует обратной связи от пользователя (это могут быть опросы в реальном времени или иные методы). Интернет-провайдеры по-прежнему заинтересованы в механизмах, способных вывести логическим путем или спрогнозировать QoE и степень вовлеченности пользователей на основе параметров, которые измеряются напрямую (пропускная способность приложения, частота потери пакетов, интервал между поступлениями пакетов и т.д.).

Методы автоматической оценки QoE на основе пассивного измерения параметров сетевого трафика появятся не скоро, однако эта область является благодатной почвой для исследований на стыке машинного обучения и сетевых технологий. Рано или поздно приложения могут выйти за рамки сетевых технологий, и транспортные протоколы (а также сетевые операторы) тоже будут оптимизировать использование ресурсов для пользователей, нуждающихся в более высоком качестве. Например, человека, который запустил потоковое видео и ушел в другую комнату, гораздо меньше волнует качество потока по сравнению с тем, кто поглощен просмотром фильма. Конечно, при этом возникает вопрос, как определить, просматривает ли пользователь видео со всем вниманием или вышел на кухню за стаканом воды, не удосужившись нажать на паузу.


6.7.5. Проектирование хостов для быстрых сетей

Измерение и настройка могут значительно улучшить производительность, но это не заменит качественного дизайна сети. Плохо спроектированная сеть может быть усовершенствована только до определенного уровня. Для дальнейшего увеличения производительности ее придется переделать.

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

Уменьшение накладных расходов из-за программного обеспечения улучшает производительность за счет повышения пропускной способности и снижения задержки. Оно также позволяет снизить затраты энергии, необходимые для передачи данных по сети, что актуально для портативных компьютеров. Большинство этих идей известны разработчикам сетей уже много лет. Впервые они были четко сформулированы Могулом (Mogul, 1993), и мы во многом опираемся на его работу. Другой источник по этой теме — книга Меткалфа (Metcalfe, 1993).


Скорость центрального процессора важнее скорости сети

Многолетний опыт показывает, что почти во всех быстрых сетях накладные расходы операционной системы и протокола составляют основное время задержки. Например, теоретически минимальное время удаленного вызова процедур в сети Ethernet мощностью 1 Гбит/с составляет 1 мкс, что соответствует минимальному запросу (64 байта), на который приходит минимальный (64-байтный) ответ. На практике значительным достижением считается даже небольшое снижение накладных расходов программного обеспечения при вызове удаленной про­цедуры (что происходит редко).

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


Уменьшайте число пакетов, чтобы снизить накладные расходы

Каждый сегмент содержит определенный объем накладных расходов (например, заголовок) и некоторое количество данных (например, пользовательские данные). Оба этих компонента требуют пропускной способности. Также каждому из них требуется обработка (например, обработка заголовка и вычисление контрольной суммы). При отправке 1 млн байт побайтовые затраты времени процессора на обработку не зависят от размера сегмента. Однако при использовании 128-байтных сегментов затраты на обработку заголовков будут в 32 раза выше, чем для сегментов размером 4 Кбайт. И эти затраты растут очень быстро.

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

Можно сказать, что компьютер, как и человек, плохо справляется с многозадачностью. Это объясняет стремление отправлять MTU-пакеты максимального размера и обходиться без фрагментации. Алгоритм Нейгла и метод Кларка также являются попытками избежать отправки маленьких пакетов.


Минимизируйте число операций с данными

Самый простой способ реализовать многоуровневый стек протоколов — использовать один модуль для каждого уровня. К сожалению, это приводит к многократному копированию данных (или, по крайней мере, многократному доступу к ним). К примеру, после того как пакет принимается сетевой картой, он обычно копируется в системный буфер ядра. Затем он должен быть обработан на сетевом и на транспортном уровнях. Поэтому он поочередно копируется в буферы этих уровней и, наконец, передается получающему приложению. Часто входящий пакет копируется три или четыре раза, прежде чем содержащийся в нем сегмент доставляется по назначению.

Такое копирование может сильно снизить производительность, поскольку операции с памятью обычно в десятки раз медленнее, чем операции с использованием только внутренних регистров. К примеру, если 20 % инструкций действительно связаны с обращением к памяти (то есть данных нет в кэше), — а это вполне вероятная цифра при обработке входящих пакетов, — среднее время выполнения инструкции снизится в 2,8 раза (0,8 × 1 + 0,2 × 10). Аппаратные улучшения здесь не помогут — проблема в слишком большом числе операций копирования, выполняемых операционной системой.

Продуманная операционная система постарается уменьшить число операций копирования, объединяя процессы обработки на разных уровнях. К примеру, TCP и IP обычно работают вместе («TCP/IP»), поэтому когда обработка переходит от сетевого уровня к транспортному, копировать пользовательские данные пакета не нужно. Еще один популярный прием состоит в том, чтобы выполнять несколько операций на уровне за один проход. Например, контрольные суммы часто вычисляются во время копирования данных (когда это действительно необходимо), и новое значение добавляется в конец.


Минимизируйте число переключений контекста

Схожее правило заключается в том, чтобы по возможности избегать переключений контекста (например, из режима ядра в режим пользователя), поскольку они объединяют в себе негативные свойства прерываний и копирования. Именно во избежание этих затрат транспортные протоколы часто реализуются в ядре. Как и число пакетов, количество переключений контекста можно снизить с помощью библиотечной процедуры, передающей данные во внутренний буфер до тех пор, пока их не наберется достаточное количество. Аналогично на стороне получателя небольшие сегменты следует собирать вместе и передавать пользователю за один раз, минимизируя число переключений контекста.

В идеале входящий пакет вызывает одно переключение контекста из текущего пользовательского процесса в режим ядра, а затем еще одно — при передаче управления принимающему процессу и предоставлении ему прибывших данных. К сожалению, во многих операционных системах происходит еще одно переключение. Например, если диспетчер сети работает в виде отдельного процесса в пространстве пользователя, поступление пакета вызывает передачу управления от процесса пользователя ядру, затем от ядра диспетчеру сети, затем снова ядру и, наконец, от ядра получающему процессу. Эта последовательность переключений контекста показана на илл. 6.51. Все эти переключения для каждого пакета сильно расходуют время центрального процессора и существенно снижают производительность сети.

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


Лучше избегать перегрузки, чем восстанавливаться после нее

Старая пословица, гласящая, что профилактика лучше лечения, справедлива и в деле борьбы с перегрузками в сетях. Когда сеть перегружена, пакеты теряются, пропускная способность растрачивается впустую, увеличивается задержка и т.п. Все эти издержки нежелательны, а процесс восстановления после перегрузки требует времени и терпения. Гораздо более эффективной стратегией является предотвращение перегрузки, напоминающее прививку от болезни, — неприятно, зато избавляет от более крупных неприятностей.


Избегайте тайм-аутов

Таймеры в сетях необходимы, но их следует применять умеренно и стремиться минимизировать количество тайм-аутов. Когда срабатывает таймер, обычно повторяется какое-то действие. Если его повтор необходим, так и следует поступить, однако повторение действия без особой необходимости является расточительным.

Чтобы избегжать излишней работы, следует устанавливать период ожидания с небольшим запасом. Таймер, срабатывающий слишком поздно, несколько увеличивает задержку в случае (маловероятном) потери сегмента. Преждевременно срабатывающий таймер впустую тратит время процессора и пропускную способность, а также напрасно увеличивает нагрузку на, возможно, десятки маршрутизаторов.


6.7.6. Быстрая обработка сегментов

Теперь, когда мы поговорили об общих правилах, рассмотрим несколько методов, позволяющих ускорить обработку сегментов. Дополнительные сведения по этой теме можно найти в следующих источниках: Кларк и др. (Clark et al., 1989); Чейз и др. (Chase et al., 2001).

Накладные расходы по обработке сегментов состоят из двух компонентов: затраты на сегмент и на каждый байт. Нужно действовать сразу на обоих направлениях. Ключ к быстрой обработке сегментов — отделить стандартный, успешный случай (одностороннюю передачу данных) и разобраться с ним. Многие протоколы придают особое значение действиям в нештатной ситуации (например, при потере пакета). Но для быстрой работы протокола разработчик должен пытаться минимизировать время обработки данных в нормальном режиме. Снижение времени обработки при возникновении ошибок является второстепенной задачей.

Для перехода в состояние ESTABLISHED требуется передача последовательности специальных сегментов, но как только оно достигнуто, обработка сегментов не вызывает затруднений (пока одна из сторон не начнет закрывать соединение). Допустим, отправитель находится в состоянии ESTABLISHED и у него есть данные для передачи. Для простоты мы предположим, что транспортная подсистема расположена в ядре, хотя тот же принцип действует, если это процесс в пространстве пользователя или библиотека в передающем процессе. На илл. 6.52 передающий процесс вклинивается в процессы ядра, выполняя примитив SEND. Прежде всего транспортная подсистема проверяет, является ли этот случай нормальным: установлено состояние ESTABLISHED, ни одна сторона не пытается закрыть соединение, передается стандартный полный сегмент (без флага URGENT) и у получателя достаточный размер окна. Если все эти условия выполнены, то никаких дополнительных проверок не требуется, и алгоритм транспортной подсистемы может выбрать быстрый путь. В большинстве случаев именно так и происходит.

В стандартной ситуации заголовки соседних сегментов почти одинаковы. Чтобы извлечь из этого пользу, транспортная подсистема сохраняет в своем буфере прототип заголовка. В начале быстрого пути он как можно скорее пословно копируется в буфер нового заголовка. Затем поверх перезаписываются все отличающиеся поля. Часто они легко выводятся из переменных состояния — например, следующий порядковый номер сегмента. Затем указатель на заполненный заголовок сегмента и указатель на данные пользователя передаются сетевому уровню. Здесь можно применить ту же стратегию (на илл. 6.52 этого нет). Наконец, сетевой уровень передает полученный в результате пакет канальному уровню для отправки.

Илл. 6.52. Быстрый путь от отправителя к получателю обозначен жирной линией. Серым цветом выделены прямоугольники, обозначающие шаги обработки вдоль этого пути

Чтобы увидеть, как работает этот принцип на практике, рассмотрим случай TCP/IP. На илл. 6.53 (а) изображен TCP-заголовок. Поля, одинаковые для заголовков последующих сегментов в однонаправленном потоке, выделены серым цветом. Все, что нужно сделать передающей транспортной подсистеме, — это скопировать пять слов заголовка-прототипа в выходной буфер, заполнить поле порядкового номера (скопировав одно слово), сосчитать контрольную сумму и увеличить на единицу значение переменной, хранящей текущий порядковый номер. Затем она передает заголовок и данные специальной IP-процедуре, предназначенной для отправки стандартного максимального сегмента. Затем IP-процедура копирует свой заголовок-прототип из пяти слов (илл. 6.53 (б)) в буфер, заполняет поле Identification и вычисляет контрольную сумму заголовка. Теперь пакет готов к передаче.

Илл. 6.53. (а) TCP-заголовок. (б) IP-заголовок. Серым цветом выделены поля, взятые из прототипа без изменений

Теперь рассмотрим быстрый путь обработки пакета получающей стороной на илл. 6.52. Первый шаг состоит в поиске записи соединения для входящего сегмента. В TCP запись соединения может храниться в хеш-таблице, ключом к которой является какая-нибудь простая функция двух IP-адресов и двух портов. После ее обнаружения следует проверить адреса и номера портов, чтобы убедиться, что найдена нужная запись.

Процесс поиска требуемой записи можно дополнительно ускорить, если установить указатель на последнюю использовавшуюся запись и сначала проверить ее. Кларк и его соавторы (Clark et al.,1989) исследовали этот вопрос и пришли к выводу, что в этом случае доля успешных обращений превысит 90 %.

Затем сегмент проверяется на соответствие стандарту: соединение в состоянии ESTABLISHED, ни одна сторона не пытается его разорвать, сегмент является полным, специальные флаги не установлены, и порядковый номер именно тот, который ожидался. Такие проверки включают всего несколько условий. Если все эти условия удовлетворяются, вызывается специальная процедура быстрого пути TCP-уровня.

Процедура быстрого пути обновляет запись соединения и копирует данные для пользователя. Во время копирования она подсчитывает контрольную сумму, что уменьшает количество циклов обработки. Если контрольная сумма верна, запись соединения обновляется и отправляется подтверждение. Метод, реализованный в виде отдельной процедуры, которая сначала быстро проверяет заголовок на предмет его соответствия ожиданиям, называется прогнозированием заголовков (header prediction). Он применяется в большинстве реализаций TCP. Использование этого метода оптимизации вместе с остальными, описанными в данном разделе, позволяет протоколу TCP достичь 90 % от скорости копирования в локальной памяти, при условии, что сама сеть достаточно быстрая.

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

В программе таймеры обычно реализуются в виде связанного списка таймеров, отсортированного по времени срабатывания. Начальная запись содержит счетчик минимальных интервалов времени (тактовых импульсов — ticks), оставшихся до истечения периода ожидания. В каждой последующей записи находится счетчик, указывающий, сколько тактовых импульсов остается с учетом предыдущей ­записи. Например, если таймеры сработают через 3, 10 и 12 импульсов, счетчики списка будут содержать значения 3, 7 и 2 соответственно.

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

Если максимальное значение таймера ограничено и известно заранее, можно применить более эффективный метод — использовать массив под названием циклическое расписание (timing wheel) (илл. 6.54). Каждый слот соответствует одному тактовому импульсу. Текущее время, показанное на рисунке, — T = 4. Таймеры должны сработать через 3, 10 и 12 импульсов. Если новый таймер должен сработать через 7 импульсов, требуется сделать запись в слоте 11. Аналогично, если нужно отключить таймер, установленный на T + 10, нужно проверить список, начинающийся в слоте 14, и удалить соответствующую запись. Следует отметить, что массив на илл. 6.54 не может поддерживать таймеры за пределами T + 15.

Илл. 6.54. Циклическое расписание

Когда работает таймер, указатель текущего времени перемещается по циклическому расписанию вперед на один слот. Если запись, на которую он указывает, не нулевая, обрабатываются все таймеры этого списка. Многочисленные варианты этой концепции обсуждаются у Варгезе и Лаука (Varghese and Lauck, 1987).


6.7.7. Сжатие заголовков

Перейдем к вопросу о производительности беспроводных сетей и сетей других типов, где пропускная способность ограниченна. При уменьшении издержек, возникающих из-за программного обеспечения, портативные компьютеры будут работать эффективнее, но это не поможет улучшить производительность в тех случаях, когда проблемой являются сетевые каналы.

Чтобы эффективно использовать пропускную способность, заголовок протокола и пользовательские данные должны занимать как можно меньше битов. В случае пользовательских данных этого можно достичь путем компактного кодирования информации: к примеру, изображения лучше передавать в формате JPEG, а не в растровых форматах, а документы — в форматах со сжатием, таких как PDF. Также для этого необходимы механизмы кэширования прикладного уровня (например, кэш веб-страниц), уменьшающие число передач.

А что делать с заголовками протоколов? В беспроводных сетях на канальном уровне заголовки обычно занимают мало места, поскольку изначально рассчитаны на низкую пропускную способность. В сетях, ориентированных на установление соединения, пакеты имеют короткие идентификаторы соединения вместо длинных адресов. Но протоколы более высоких уровней (IP, TCP или UDP) универсальны для всех типов сетей, поэтому в них не используются компактные заголовки. На самом деле потоковая обработка, уменьшающая затраты на программное обеспечение, часто приводит к еще большему увеличению длины заголовка (например, в IPv6 используются более разреженные заголовки, чем в IPv4).

Заголовки более высоких уровней могут сильно влиять на производительность. Например, рассмотрим процесс передачи VoIP-данных через IP, UDP и RTP. Этим протоколам требуется заголовок длиной 40 байт (20 байт для IPv4, 8 — для UDP, 12 — для RTP). В случае IPv6 ситуация еще хуже: 60 байт, включая 40-байтный заголовок IPv6. Эти заголовки могут становиться еще длиннее, потребляя более половины пропускной способности.

Чтобы уменьшить пропускную способность, потребляемую заголовками высоких уровней, применяется сжатие заголовков (header compression). При этом используются не универсальные, а специально разработанные методы. Дело в том, что по отдельности заголовки сжимаются плохо (поскольку они и так короткие), а для декомпрессии требуется, чтобы исходные данные пришли на место назначения. Последнее может и не произойти из-за потери пакетов.

Сжатие заголовков можно эффективно реализовать, если учитывать формат протокола. Одна из первых схем была разработана Ван Джейкобсоном (1990) и применялась для сжатия TCP/IP-заголовков при передаче по медленным последовательным каналам. Она позволяет уменьшить обычный 40-байтный TCP/IP-заголовок в среднем до 3 байт. Если посмотреть на илл. 6.53, можно догадаться, на чем основан этот метод. Дело в том, что многие поля заголовка не меняются от пакета к пакету. К примеру, совсем не обязательно каждый раз передавать одно и то же значение времени жизни пакета или одинаковый номер TCP-порта. Эти поля можно пропустить при передаче пакета и заполнить при получении.

Остальные поля меняются по предсказуемому сценарию. К примеру, если нет потерь, порядковые номера TCP увеличиваются по мере отправки данных. Следовательно, получатель может предсказать наиболее вероятное значение. Номер необходимо указывать, только если он отличается от ожидаемого. Но даже тогда можно передавать разность между данным номером и предыдущим (как в случае с номером подтверждения, который увеличивается, когда новые данные приходят в обратном направлении).

С помощью сжатия заголовков можно добиться, чтобы в протоколах высоких уровней заголовки были простыми, а при передаче пакета по каналам с низкой пропускной способностью применялось компактное кодирование. Надежное сжатие заголовков (Robust Header Compression, ROHC) — современный вариант сжатия, который определен в RFC 5795 как фреймворк. По замыслу разработчиков, он не реагирует на потерю пакетов в беспроводных каналах. Для каждого набора протоколов, например IP/UDP/RTP, существует отдельный профиль. Сжатые заголовки передаются с помощью отсылки к контексту, то есть фактически к соединению; значения полей можно легко предсказать для пакетов данного соединения, но не для пакетов других соединений. При нормальной работе ROHC размер заголовков для IP/UDP/RTP снижается с 40 байт до 1–3 байт.

Основная цель сжатия заголовков — уменьшить потребляемую пропускную способность. Но с помощью этого механизма можно также снизить задержку, которая складывается из задержки распространения (фиксированной для данного сетевого пути) и задержки передачи (она зависит от пропускной способности и объема передаваемых данных). Например, канал мощностью 1 Мбит/с отправляет 1 бит за 1 мкс. Если мы имеем дело с передачей мультимедиа по беспроводной сети, такой канал считается достаточно медленным, поэтому задержка передачи составляет существенную часть общей задержки, и стабильно низкая задержка важна для QoS.

При сжатии заголовков объем передаваемых данных уменьшается, и вместе с ним снижается задержка передачи. Того же эффекта можно добиться, отправляя пакеты меньшего размера. Так мы фактически меняем повышенные издержки программного обеспечения на сниженную задержку передачи. Стоит отметить, что еще одним источником задержки является время ожидания в очереди для доступа к беспроводному каналу. Это может стать важным фактором, так как беспроводные сети обычно сильно загружены. В таком случае канал должен включать механизмы QoS, обеспечивающие низкую задержку для пакетов в реальном времени. Одного сжатия заголовков будет недостаточно.


6.7.8. Протоколы для протяженных сетей с высокой пропускной способностью

В начале 1990-х годов появились гигабитные сети, передающие данные на большие расстояния. Их также называют протяженными сетями с высокой пропускной способностью (long fat networks). Сначала к ним пытались применить старые протоколы, но из-за этого возникло множество трудностей. В данном разделе мы обсудим некоторые из этих проблем с увеличением скорости и задержки сетевых протоколов.

Первая проблема состоит в том, что многие протоколы используют 32-разрядные порядковые номера пакетов. На заре интернета стандартная скорость выделенных линий между маршрутизаторами равнялась 56 Кбит/с. В этих условиях хосту, который постоянно выдавал бы данные в сеть на полной скорости, потребовалось бы больше недели на то, чтобы пройти по всем порядковым номерам. С точки зрения разработчиков TCP, 232 считалось неплохим приближением к бесконечности, поскольку вероятность блуждания пакетов по сети в течение недели практически равна нулю. При 10-мегабитном Ethernet время обхода всех порядковых номеров пакетов снизилось с одной недели до 57 минут — гораздо меньше, но все еще приемлемо. Однако когда Ethernet выдает в интернет данные со скоростью 1 Гбит/с, порядковые номера могут закончиться примерно через 34 с, при этом максимальное время жизни пакета в интернете равно 120 с. Оказалось, что 232 совершенно не подходит в качестве значения, приближенного к бесконечности: быстрый отправитель может циклически проходить по пространству последовательностей в то время, как старые пакеты все еще будут блуждать по сети.

К сожалению, многие разработчики протоколов предполагали, что время цикла пространства порядковых номеров значительно превосходит максимальное время жизни пакетов. Следовательно, сама возможность того, что старые пакеты еще могут находиться где-то в сети, когда порядковые номера опишут полный круг, даже не рассматривалась. Но для гигабитных сетей это предположение оказалось неверным. Однако решение нашлось: было предложено расширить эффективный порядковый номер, взяв в качестве старших битов метку времени. Она добавляется в TCP-заголовок пакета как дополнительный параметр. Как уже упоминалось, данный механизм называется PAWS.

Вторая проблема заключается в необходимости существенного увеличения окна управления потоком. Например, рассмотрим, процесс отправки 64 Кбайт данных из Сан-Диего в Бостон при размере буфера получателя в 64 Кбайт. Пусть скорость передачи данных по линии составляет 1 Гбит/с, а время прохождения сигнала в одну сторону, ограниченное скоростью света в стекле оптоволокна, равно 20 мс. Вначале, при t = 0, канал пуст (илл. 6.55 (а)). Только 500 мкс спустя все сегменты попадут в канал (илл. 6.55 (б)). Первый сегмент оказывается где-то в окрестностях Броли, все еще в Южной Калифорнии. Тем не менее отправитель должен остановиться, пока не получит новую информацию об окне.

Через 20 мс первый сегмент, как показано на илл. 6.55 (в), достигнет Бостона, и в ответ будет передано подтверждение. Наконец, через 40 мс после начала операции первое подтверждение возвращается к отправителю, после чего передается следующая порция данных. Поскольку линия передачи использовалась в течение всего 0,5 мс из 40 мс, производительность составит около 1,25 %. Такая ситуация типична для старых протоколов, работающих на гигабитных линиях.

Илл. 6.55. Передача половины мегабита из Сан-Диего в Бостон. (а) В момент времени t = 0. (б) Через 500 мкс. (в) Через 20 мс. (г) Через 40 мс

При анализе производительности сетей полезно обращать внимание на произведение пропускной способности на задержку (bandwidth-delay product). Пропускная способность канала (в битах в секунду) умножается на время прохождения сигнала в оба конца (в секундах). В результате получается емкость канала в битах.

На илл. 6.55 произведение пропускной способности на задержку равно 40 млн бит. Другими словами, отправитель к моменту получения ответа успеет переслать 40 млн бит, если будет работать на максимальной скорости. Столько битов потребуется, чтобы заполнить канал в обоих направлениях. Вот почему порция данных в полмиллиона битов достигает всего 1,25 % эффективности: это лишь 1,25 % емкости канала.

Отсюда следует, что для эффективного использования канала размер окна получателя должен быть по меньшей мере равен произведению пропускной способности и времени задержки, а лучше — превосходить его, так как получатель может ответить не сразу. Для трансконтинентальной гигабитной линии каждому соединению потребуется минимум по 5 Мбайт.

Третья проблема, связанная с предыдущей, состоит в том, что простые схемы повторной передачи, например протокол с возвращением на N блоков, плохо работают на линиях с большим значением произведения пропускной способности на задержку.

Рассмотрим трансконтинентальную гигабитную линию. Время прохождения сигнала в обе стороны равно 40 мс, за которые отправитель успевает передать 5 Мбайт. Если обнаруживается ошибка, требуется 40 мс, чтобы оповестить об этом отправителя. При использовании протокола с возвращением на N блоков отправителю потребуется повторять передачу не только поврежденного пакета, но также и до 5 Мбайт пакетов, переданных после поврежденного. Очевидно, что этот протокол использует ресурсы очень неэффективно. Поэтому необходимы более сложные механизмы, такие как метод выборочного повтора.

Суть четвертой проблемы заключается в принципиальном различии между гигабитными и мегабитными линиями: в длинных гигабитных каналах главным ограничивающим фактором является не пропускная способность, а задержка. На илл. 6.56 изображена зависимость времени, необходимого для передачи файла размером 1 Мбит по линии длиной в 4000 км, от скорости передачи. На скорости до 1 Мбит/с время передачи в основном зависит от скорости передачи данных. При скорости 1 Гбит/с задержка в 40 мс значительно превосходит 1 мс (время, требующееся для передачи битов по оптоволоконному кабелю). Дальнейшее увеличение скорости не оказывает на время передачи файла почти никакого воздействия.

Илл. 6.56. Время передачи и подтверждения файла размером 1 Мбит по линии длиной 4000 км

Изображенная на илл. 6.56 зависимость демонстрирует ограничения сетевых протоколов. Она показывает, что протоколы с ожиданием подтверждений (например, удаленный вызов процедур) имеют врожденное ограничение на производительность. Оно связано со скоростью света. Никакие технологические прорывы в области оптики здесь не помогут (хотя могли бы помочь новые законы физики). Если в периоды времени, пока хост ждет ответа, гигабитная линия будет простаивать, она будет ничем не лучше простой мегабитной линии (и при этом дороже).

Пятая проблема заключается в том, что скорости передачи данных растут гораздо быстрее, чем скорости обработки данных. (Обращение к разработчикам компьютеров: вы должны поставить этих разработчиков средств связи на место! Мы рассчитываем на вас.) В 1970-е годы объединенная сеть ARPANET работала на скорости 56 Кбит/с и состояла из компьютеров с производительностью около 1 MIPS (1 млн инструкций/с). Сравните эти цифры с современными показателями (производительность 1000 MIPS при скорости 1 Гбит/с). Число инструкций на один байт уменьшилось более чем в десять раз. Точные цифры зависят от времени и конкретной ситуации, но вывод такой: у протоколов стало меньше времени на обработку пакетов, поэтому они должны стать проще.

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

Проектируя, стремись увеличить скорость, а не оптимизировать пропускную способность.

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

Возникает соблазн создать быстрый сетевой интерфейс на аппаратном уровне. Сложность в том, что если протокол не является совсем простым, аппаратный интерфейс представляет собой дополнительную плату с отдельным процессором и своей программой. Чтобы сетевой сопроцессор не был столь же дорогим, как и центральный CPU, он часто представляет собой медленную микросхему. В результате центральный CPU ждет, пока сопроцессор выполнит свою работу. Было бы ошибкой полагать, что у центрального CPU обязательно найдется другая задача на время ожидания. Кроме того, для общения двух процессоров общего назначения потребуются тщательно продуманные протоколы, обес­печивающие их корректную синхронизацию. Как правило, наилучший метод заключается в создании простых протоколов, чтобы всю работу мог выполнять центральный процессор.

Для гигабитных сетей крайне важна структура пакета. В заголовок следует включить как можно меньше полей — это позволит снизить время его обработки. Сами поля должны быть достаточно большими, чтобы справляться с задачей, при этом они не должны пересекать границы слов; тогда их будет проще обработать. Под «достаточно большим» подразумевается размер, который исключает зацикливание порядковых номеров при существовании в сети старых пакетов, неспособность получателя сообщить доступный размер окна из-за мелкого служебного поля и другие проблемы.

Максимальный объем данных должен быть большим, чтобы снизить программные накладные расходы и обеспечить эффективную работу сети. 1500 байт — недостаточный размер пакета для высокоскоростных сетей, поэтому гигабитная сеть Ethernet позволяет передавать сверхдлинные фреймы размером до 9 Кбайт, а IPv6 поддерживает джамбограммы, превышающие 64 Кбайт.

Далее мы обсудим вопрос обратной связи в высокоскоростных протоколах. Из-за относительно длинного цикла задержки желательно отказаться от обратной связи: на оповещение отправителя уходит слишком много времени. Пример обратной связи — управление скоростью передачи с помощью протокола раздвижного окна. Чтобы избежать задержек (которые могут быть долгими), связанных с передачей сведений о состоянии окна от получателя отправителю, лучше использовать протокол, основанный на скорости. В этом случае отправитель будет передавать данные на той скорости, с которой получатель заранее согласился (но не быстрее).

Еще один пример обратной связи — алгоритм медленного старта, разработанный Джейкобсоном. Этот алгоритм проводит многочисленные проверки, пытаясь узнать пропускную способность сети. В высокоскоростных сетях на проведение пяти-шести тестов для определения отклика сети тратится огромное количество сетевых ресурсов. Более эффективная схема состоит в резервировании ресурсов отправителем, получателем и сетью в момент установления соединения. Кроме того, заблаговременное резервирование ресурсов позволяет несколько снизить джиттер. Иными словами, рост скоростей передачи неумолимо подталкивает разработчиков к использованию сетей, ориентированных на установление соединения.

Еще одно полезное свойство для протокола — возможность отправлять нормальное количество данных вместе с запросом соединения. Благодаря этому можно сэкономить один RTT.

Загрузка...