vk_logo twitter_logo facebook_logo googleplus_logo youtube_logo telegram_logo telegram_logo

От udpxy к GigA+: путь развития ПО доставки видеопотоков 7

Дата публикации: 02.10.2017
Количество просмотров: 2047
Автор:

Начало udpxy

В середине 2008 года началась разработка udpxy - утилиты для преобразования потока данных из протокола UDP в TCP. Заказчиком был человек, вступивший в "борьбу" с IP телевидением в московской квартире. Не желая прокладывать за собой провода, он положился на роутер (ASUS WL500g), обеспечивающий Wi-fi сеть. Видео смотреть было можно, но периодически вклинивались помехи. Содружество энтузиастов IPTV на интернет-форумах помогло выяснить, что суть проблемы - в потере пакетов, передающихся по протоколу UDP. Провайдер IPTV транслировал каналы в локальную сеть (здания) посредством мультикаста. Существовавшая в тот момент утилита под Windows, исправляла ситуацию, транслируя мультикаст поток в индивидуальное TCP соединение, но требовала настольный ПК. Роутер же обеспечивался, кроме фабричной, альтернативной прошивкой (известной как "прошивка от Олега"), и задача была сформулирована просто: создать аналог Windows-утилиты, работающий на прошивке роутера.

Прошивка представляла собой набор программ поверх Linux 2.4. При наличии полноценной среды разработки, можно было воспользоваться любым поддерживаемым данной средой языком программирования. Ограничения были в мощности устройства и наличии ресурсов: 32-битный микропроцессор архитектуры MIPS и 32 Мб памяти ОЗУ. В качестве языка был выбран ANSI C - по причине крайней простоты задачи и того факта, что ни один другой язык не обеспечивал более прямолинейного доступа к сетевым протоколам. Утилита была названа udpxy ("ю-ди-пикси") как соединение слов "UDP" и "proxy", и каламбуром с английским словом "pixie" (фея).

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

Архитектура udpxy была подчинена принципу крайней простоты. Это был простейший вариант "forked server" (по имени системного вызова fork(2)) для выполнения задач на маломощном процессоре с небольшим количеством памяти. Изначально встроенной оптимизацией было отсутствие двойного копирования: данные, прибывшие из сети (памяти ядра) в память процесса по адресу А, отбывали в сеть (память ядра) из того же адреса A.

Чем обосновывался выбор "forked server" как архитектуры приложения? Прежде всего, уверенностью в простоте задачи, для которой не требуются сложные средства. Нагрузка от переключения между (максимум) 16-ю процессами не была существенной и не оправдывала усложнения.


Новые игроки, наращивание функций

Первым изменением была отмена ограничения на количество клиентов (те самые 16). Отменить лимит просили не домашние пользователи, раздающие IPTV каналы родным и гостям, а предприятия - IPTV провайдеры. Провайдеры "перенесли" udpxy из домена домашних роутеров на серверную аппаратуру с мощными процессорами и значительным объёмом оперативной памяти.

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

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

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

Несмотря на то, что udpxy работал стабильно, пройдя длительный период "беты", внештатные ситуации время от времени всё же случались. Анализ этих ситуаций показал, что менее стабильным (и наиболее сложным) является не код передачи данных клиенту, а код обработки входящего запроса, создания процесса-клиента и т.п. Ситуация естественная, поскольку логика обработки запросов была сложней простой схемы "перебрасывания" пакетов из одного сокета в другой. Усложнение же, в любом его виде, неизбежно вело к понижению стабильности.

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


Gigapxy - переход на новые рельсы

У нового продукта был вдохновитель, категорически отсоветовавший выпускать что-то под "старым" именем. Задумка выпустить udpxy 2.0 или udpxEE (udpxy Enterprise Edition) трансформировалась в решение оформить новый продукт под похожим, но новым именем. Этим именем стало Gigapxy.

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

Разработка начиналась под FreeBSD, но вскоре стала параллельно идти под Linux как набирающей популярность в серверной среде. В отличие от udpxy, Gigapxy было решено сделать не "forked", а событийно-ориентированным сервером, где количество процессов не имеет пропорциональной зависимости от количества задач.


Архитектура, взаимодействие модулей

Приложение было разделено на два квази-независимых модуля: 1) gws - сервер, отвечающий за обработку клиентских (HTTP) запросов, интерфейс, обработку статистики и генерацию отчётов. И 2) gng - рабочий "движок", занятый приёмом-передачей данных из каналов-источников в соединения клиентов. Движков предполагалось использовать несколько, для баланса нагрузки в рамках сервера. Каждый из движков мог быть привязан к отдельному ядру процессора.

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

Архитектура взаимодействия модулей иерархична: изначально происходит запуск gws. gws создаёт два локальных интерфейса: 1) для административных запросов (возможность посмотреть статус программы по HTTP и статистику по каналам) и 2) интерфейс связи с "движками". Интерфейс для обработки клиентских запросов не добавляется до установления связи с "движками". Вслед за gws стартуют "движки", каждый из которых устанавливает связь с gws.

Затем gws начинает обрабатывать запросы от пользователей. Модуль проверяет корректность запроса - синтаксически и с точки зрения прав доступа, затем формирует задачу (источник-клиент) и передаёт её для выполнения выбранному процессу gng. На стороне "движка" задача преобразуется в последовательность операций чтения источника и передачи данных клиенту.

Каждый "движок" отвечает за множество клиентов в рамках своего процесса и работает со множеством каналов (M каналов на N клиентов, при N >= M). Изначально, каналы не дублировались на различных gng: заполучив однажды канал К, gng приобретал исключительное право на его обслуживание, все клиенты канала К направлялись на данный "движок". Однако данный подход имел серьёзный изъян. Клиенты могли в одночасье предпочесть некий канал А всем иным (как, например, во время трансляции футбольного матча) и перегрузить отведённый каналу (единственный) "движок" (читай - ядро процессора). Изъян был исправлен - в настоящее время существует опция, позволяющая равномерно распределять каналы по различным "движкам".


Разграничение доступа

Возможность перенести логику разграничения доступа со стороннего приложения (например, NginX) на Gigapxy была оценена высоко. В одном из клиентских сценариев, освобождённые аппаратные ресурсы позволили нарастить количество клиентских запросов до 30%.

Разнообразие систем авторизации и аутентификации изначально повергли в замешательство: невозможно было поддержать их все. Невероятно было бы и рассчитывать на то, что все покупатели пользуются лишь двумя-тремя - выбор был широк. В этой ситуации помог пример архитектурного решения от прокси-сервера Squid, где многочисленные функции можно было делегировать "плагинам", поддерживающим связь с "родителем" через потоки стандартного ввода-вывода. Язык реализации "плагинов" был произволен. Данный механизм был применён в Gigapxy. Вопрос интерфейса с той или иной системой переносился в реализацию "плагинов". В ответственности gws оставалось общение с "плагином" (по некому протоколу) и поддержание достаточного количества сущностей "плагинов" для своевременной обработки запросов.

Следует упомянуть, что решение переложить часть функций на сторонние компоненты поставило проблему "крахов" с их стороны. Код "плагинов" не контролируем, но в обязанности gws остаётся стабильная работа подконтрольных модулей. В результате, была реализована защита от "циклических падений": ситуации, когда приложение в цикле пытается запустить мгновенно "падающий" компонент. Циклы подобного рода, как правило, чреваты бесконтрольным расходом ресурсов и разбухшим логом (в т.ч. и системным).

Дополнительной трудностью была и скорость работы самих "плагинов", упиравшаяся в скорость ответа системы, с которой они контактировали. Был добавлен механизм кэширования отказов: запросы, получавшие ранее отказ на доступ, получали повторный отказ (в течение некоторого периода времени) без обращения к "плагинам", а непосредственно от gws.

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


Один канал - один сокет, буферные цепочки

Создание отдельного сокета на чтение мультикаст-канала каждым клиентом в udpxy было расточительным. Прежде всего, это порождало значительное количество системных вызовов, на которых в высоконагруженных системах полагается экономить. Gigapxy кэширует данные каналов и использует для каждого канала связанный список буферов. Буфер может быть как в памяти, так и на диске, в зависимости от выбора (в конфигурации). Размер цепочки буферов автоматически корректируется в зависимости от нужд клиентов канала, и при ненадобности буфер отправляется в "резерв", откуда может быть востребован другим каналом.

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

Почему не был выбран иной механизм, например, кольцевой буфер? Система цепочек воспринималась при планировании наиболее гибкой, а схема потребления память цепочками - более разумной. Оправдался ли расчёт? Несомненно. Усилия, вложенные в не самый тривиальный код, окупились высвобождением значительных ресурсов для предприятий, переходивших на Gigapxy c крупных программных комплексов конкурентов. Для достижения этих результатов, правда, система управления буферами потребовала комплекса доработок и тестирования.


"Ванька-встанька" - динамическое восстановление модулей

Расчёт на то, что в процессе долговременной работы процесс gws может в какой-то момент "упасть" был оправдан. Модуль, отвечающий за обработку внешних запросов, рано или поздно сталкивается с "нестандартными" запросами, способными причинить вред из-за скрытых недостатков кода. Сталкивается этот модуль и с DDOS атаками. За несколько лет по обеим причинам было выявлено и устранено около десятка дефектов.

Автономность модулей (каждый из которых - отдельный процесс) помогла достигнуть высокой стабильности. gws мог перестать принимать новые запросы в результате сбоя или DDOS атаки, но видеопотоки продолжали поступать клиентам. gws мог "упасть", но "движки" продолжали работу и переходили под управление заново запущенного gws. Падений же gng, благодаря простоте внутренней логики, было крайне мало.


Работа с HTTP каналами и цепочками приложений

Возможность запрашивать данные не только из UDP мультикаста, но и по HTTP ссылке была добавлена почти сразу же. Источником (каналом) мог стать любой передаваемый по HTTP поток. Возможность была востребована. В качестве источника Gigapxy поддерживает и HTTP, и TCP и UDP потоки в "чистом" виде. Источником может быть и файл.

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


Клиенты и покупатели - немного истории

Основным рынком Gigapxy (по разнообразным причинам) оказался Европейский Союз. Первой фирмой, испытывавшей позднюю альфу и последующие беты "в бою", был IPTV провайдер из Стокгольма. Опыт испытаний на "боевой" конфигурации сложно переоценить, а уровню надёжности и стабильности продукта, достигнутому за несколько лет, продукт, безусловно, обязан взаимодействию с клиентами.

В настоящее время клиентская база охватывает большинство стран ЕС. Причины, по которым компании хотят работать с продуктом Gigapxy можно просуммировать следующим списком:

  • Высокая стабильность ПО. Стабильность, отсутствие регулярных перебоев и "крахов" ценится на рынке, по моему опыту, больше всех иных факторов. Несколько покупателей перешли с конкурентных продуктов именно из-за проблем с регулярными сбоями и "падениями" модулей прежнего ПО.
  • Сокращение расходов на "железо". Я неоднократно был свидетелем крайнего удивления (иногда переходившего в восторженное возбуждение) от количества высвобождаемых ресурсов в результате миграции на Gigapxy с иных систем. Разумеется, есть конкурентные продукты, идущие вровень, где удивления не стоит ожидать. Тем не менее, данный опыт повторялся не один раз. Эталоном остаётся пример покупателя, сумевшего "насытить" 10 гигабитную сетевую карту потоками с не самого современного сервера.
  • Оперативность в обслуживании. Без особых гарантий и громких обещаний мне, как правило, удаётся ответить на вопросы клиентов весьма оперативно. По личному опыту работы в корпорациях и фирмах разнообразных видов и размеров, могу сказать, что инертность пропорциональна размеру компании. "Гиганты индустрии" подчас не могут позволить себе быстрой обратной связи. Масштаб также часто не позволяет им отнестись с должным вниманием (и приоритетом) к запросам не крупных покупателей. В Gigapxy, множество изменений по запросам клиентов были внесены ещё на стадии испытаний.
  • Цена - существующая схема лицензирования вполне гибка и позволяет позволить себе покупку даже весьма небольшим предприятиям.


Уроки и пожелания

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

  • Универсальность (к примеру, ввода-вывода из любого источника в любой протокол) бывает подчас излишней. Сценариев использования, как правило, не так много, а стремление к универсальности ведёт к усложнению кода и перегрузке логики.
  • Делегировать функции сторонним компонентам имеет смысл, если упрощает приложение, не уменьшая надёжности. Система выдачи отчётов, опиравшаяся на передачу данных от gws к gng, несколько усложнила логику gws. Система авторизации же напротив - упростила код gws, перенеся разумную часть нагрузки на клиента.
  • Документацию, сколь бы аккуратно и скрупулёзно она ни была написана, не берутся читать, а если берутся, то не дочитывают до конца. К сжатой документации по продукту стоит прилагать менее "сухие" по стилю руководства по установке, настройке и т.п. - их, как правило, читают.

 

Камо грядеши? - GigA+

Через год после завершения бета-тестирования Gigapxy, начали поступать запросы на добавление поддержки протокола Apple HLS. Это оказалось не столь тривиальной задачей, сколь могло бы показаться. После пары прототипов, работа над соответствующей версией началась. Сам протокол HLS весьма прост, и обсуждаться здесь не будет. В процессе разработки, задачу усложнили, добавив к HLS поддержку DVR - возможности проигрывать поток с заданной задержкой во времени; начать проигрывать, к примеру, за два часа до текущего времени.

Первым "новоприбывшим" модулем стал модуль сегментирования потока (gxseg). Потребность генерировать различные плейлисты, в зависимости от задержки DVR, дали рождение модулю, ответственному за них. Сегментирование базировалось на библиотеке libav (от команды ffmpeg). С использованием библиотеки пришли ограничения, заставившие "обернуть" gxseg модулем управления потоком канала - vsm. Потребность в реплицировании сегментов и балансировки запросов прибавила ещё два микро-модуля. Это был уже иной продукт, и не было смысла считать его новой версией старого. Новый продукт был назван GigA+, выход его в "бету" состоялся 26 сентября 2017 года.


Кому это выгодно?

GigA+ заинтересует тех, кто желает привнести HLS в "репертуар", но не идёт по пути построения "хитроумного агрегата" собственными силами. Тем, кто уже работал с Gigapxy и знаком с  "архитектурным стилем" данного продукта. Стиль этот будет выдержан и улучшен в GigA+.


Что в первой бете?

Бета - достаточно длительный период для продукта, в котором сделан упор на стабильность. Gigapxy перестал быть бетой тогда, когда стабильность его стала непререкаемым фактом (ни одного дефекта не поступило в течение полугода). Потому период беты разбивается на несколько крупных "сборок". В начальной сборке GigA+ присутствуют следующие основные функции:

  1. Линейная доставка каналов формата MPEG-TS - по сути, всё то, что включено в Gigapxy 1.0. NB: код Gigapxy 1.0 (в силу исторических причин) несколько отличен от ветки GigA+ и его стабильность (в силу внесённых изменений) официально не может быть классифицирована как равная Gigapxy 1.0, и считается также бетой.
  2. Доставка по протоколу HLS, сегментов в H.264 кодеке (видео) посредством MPEG-TS. Поддерживаются режимы LIVE и DVR. Поддерживается масштабирование на несколько серверов и балансировка запросов при помощи плагина для сервера NginX.


Что дальше?

Укажу лишь то, что уже внесено в план разработки и ожидает своей очереди. Итак:

  1. DRM - сперва в простейшей реализации AES- 128/256. Есть и далеко идущие планы в этой области.
  2. MPEG4 сегменты в HLS.
  3. Перевод отчётов (каналы, клиенты, статистика) на внешние сервисы.
  4. Система мониторинга состояния модулей.
От редакции: если у вас есть чем поделиться с коллегами по отрасли, приглашаем к сотрудничеству
Ссылка на материал, для размещения на сторонних ресурсах
/articles/article/32520/ot-udpxy-k-giga-put-razvitiya-po-dostavki-videopotokov.html

Обсудить на форуме

Оставлять комментарии могут только зарегистрированные пользователи

Зарегистрироваться