Сетевое взаимодействие в реальном времени

Сетевое взаимодействие в реальном времени #

Почему сетевое взаимодействие так важно в коммуникации в реальном времени? #

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

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

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

Какие атрибуты сети делают ее сложной? #

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

Пропускная способность #

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

Время передачи и время круглого пути #

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

transmission_time = receive_time - send_time

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

Измерение времени круглого пути - это обходной путь для несовершенной синхронизации часов.

Вместо работы с распределенными часами WebRTC-пир отправляет специальный пакет со своей собственной меткой времени sendertime1. Сотрудничающий пир получает пакет и отражает метку времени обратно отправителю. Как только первоначальный отправитель получает отраженное время, он вычитает метку времени sendertime1 из текущего времени sendertime2. Эта временная дельта называется “задержкой распространения круглого пути” или, чаще, временем круглого пути.

rtt = sendertime2 - sendertime1

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

transmission_time = rtt/2

Технические подробности измерения времени круглого пути описаны более подробно в главе о Sender и Receiver Reports RTCP.

Джиттер #

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

Потеря пакетов #

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

Максимальный блок передачи #

Максимальный блок передачи (Maximum Transmission Unit) - это ограничение на размер одного пакета. Сети не позволяют отправлять одно гигантское сообщение. На уровне протокола сообщения могут быть разделены на несколько более мелких пакетов.

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

Перегрузка #

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

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

Динамичность #

Сети крайне динамичны, и условия могут быстро меняться. Во время вызова вы можете отправить и получить сотни тысяч пакетов. Эти пакеты будут проходить через несколько транзитных узлов. Эти узлы будут совместно использоваться миллионами других пользователей. Даже в вашей локальной сети может загружаться HD-фильм или устройство может решить скачать обновление программного обеспечения.

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

Решение проблемы потери пакетов #

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

Допустим, вы отправляете 10 пакетов, и пакеты 5 и 6 теряются. Вот способы решения этой проблемы.

Подтверждения #

Подтверждения - это когда получатель уведомляет отправителя о каждом полученном пакете. Отправитель узнает о потере пакетов, когда получает подтверждение для пакета дважды, который не является окончательным. Когда отправитель получает ACK для пакета 4 дважды, он знает, что пакет 5 еще не был виден.

Избирательные подтверждения #

Избирательные подтверждения - это улучшение обычных подтверждений. Получатель может отправить SACK, который подтверждает несколько пакетов и уведомляет отправителя о пропусках. Теперь отправитель может получить SACK для пакетов 4 и 7. Он знает, что ему нужно повторно отправить пакеты 5 и 6.

Отрицательные подтверждения #

Отрицательные подтверждения решают проблему противоположным образом. Вместо уведомления отправителя о том, что он получил, получатель уведомляет отправителя о том, что было потеряно. В нашем случае NACK будет отправлен для пакетов 5 и 6. Отправитель знает только пакеты, которые получатель хочет, чтобы были отправлены снова.

Упреждающая коррекция ошибок #

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

Это уменьшает задержку/сложность отправки и обработки подтверждений. Упреждающая коррекция ошибок - это напрасная трата пропускной способности, если в сети, в которой вы находитесь, нет потерь.

Решение джиттера #

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

Чтобы решить джиттер, клиенты используют JitterBuffer. JitterBuffer обеспечивает стабильное время доставки пакетов. Недостаток заключается в том, что JitterBuffer добавляет некоторую задержку к пакетам, которые прибывают рано. Преимущество в том, что поздние пакеты не вызывают джиттера. Представьте, что во время вызова вы видите следующие времена прибытия пакетов:

* time=1.46 ms
* time=1.93 ms
* time=1.57 ms
* time=1.55 ms
* time=1.54 ms
* time=1.72 ms
* time=1.45 ms
* time=1.73 ms
* time=1.80 ms

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

Работа JitterBuffer #

JitterBuffer

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

Подробнее о том, как видеокадры преобразуются в RTP-пакеты и почему необходима реконструкция, читайте в главе о медиа-коммуникации.

jitterBufferDelay предоставляет отличное представление о производительности вашей сети и ее влиянии на плавность воспроизведения. Это часть API статистики WebRTC, относящаяся к входящему потоку получателя. Задержка определяет время, которое видеокадры проводят в буфере джиттера перед выдачей для декодирования. Длинная задержка буфера джиттера означает, что ваша сеть сильно перегружена.

Обнаружение перегрузки #

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

  • Потеря пакетов - Пакеты сбрасываются по мере перегрузки сети.
  • Джиттер - По мере перегрузки сетевого оборудования, постановка пакетов в очередь вызывает их нерегулярность.
  • Время круглого пути - При перегрузке пакеты дольше прибывают. В отличие от джиттера, время круглого пути просто продолжает увеличиваться.
  • Явное уведомление о перегрузке - Новые сети могут помечать пакеты как подверженные риску сброса для облегчения перегрузки.

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

Разрешение перегрузки #

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

Отправка медленнее #

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

Этот метод используется для большинства коммуникаций с данными. С такими протоколами, как TCP, это все делается операционной системой и полностью прозрачно для пользователей и разработчиков.

Отправка меньшего количества #

В некоторых случаях мы можем отправлять меньше информации, чтобы удовлетворить наши ограничения. У нас также есть жесткие сроки доставки наших данных, поэтому мы не можем отправлять медленнее. Это ограничения, которые относятся к медиа в реальном времени.

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