Как мы созвонились компанией в 10 тысяч человек
В Тензоре около 7 тысяч сотрудников и более 100 филиалов по всей стране — такой компании категорически необходима видеокоммуникация. Существует 2 соизмеримых по издержкам решения: использовать существующий продукт или реализовать свой.
В этой статье я, разработчик отдела вебинаров, расскажу, каким образом наша компания, выбрав когда-то второй путь, пришла к собственному сервису вебинаров. Пройдя несколько итераций развития, на сегодняшний день мы научились проводить видеоконференции буквально на всех наших сотрудников.
Дисклеймер: здесь и далее мы будем говорить про веб-решения видеосвязи, основанные на технологии WebRTC. Всё, что нужно о ней знать для понимания статьи: WebRTC — технология, позволяющая устанавливать P2P соединение между двумя браузерами и обмениваться данными: медиа-потоками, такими как изображение с камеры, звук с микрофона, демонстрацию вашего экрана и др, а также потоками любых других данных. Более подробно с ней можно ознакомиться на официальном сайте: https://webrtc.org/.
Позвольте начать с предыстории.
Отдел вебинаров. Начало (2017 год)
Собственная видеосвязь в Тензоре существовала уже несколько лет, позволяла собирать в одном звонке до 50–60 человек. Это покрывало все потребности компании, оставляя нерешёнными всего 2 проблемы:
Проведение массовых конференций и онлайн-корпоративов.
В Тензоре всё чаще стала возникать потребность в видео-конференциях с большим количеством слушателей, разбросанных по всей стране. Очевидно, что собрать их всех в одном месте можно только в интернете.
Постепенный рост отделов и среднего числа участников совещаний.
К концу 2016 года эта проблема становиться особенно острой, так как созвонов где одновременно вещают 50–60 человек становится недостаточно. Компания расширяется, появляются новые отделы, старые увеличиваются и делятся на подотделы… И всем по-прежнему нужно проводить планёрки с максимальной явкой, а сервера уже работают на пределе возможностей.
Могли ли мы тогда просто масштабироваться? Давайте посчитаем.
Что такое полноценный видеозвонок? Видеосовещание, в котором каждый участник, с одной стороны, должен иметь возможность показывать свою камеру, а с другой — видеть всех остальных.
Как бы ни была организована обработка потоков на сервере, от каждого участника идёт хотя бы 1 поток и каждому нужно отправлять хотя бы n-1 потоков (по одному от каждого другого). Иначе говоря, рост потребляемых ресурсов был квадратичным по отношению к увеличению числа участников.
Таким образом, потенциал для масштабирования был, но был он небольшой и очень дорогой: потратить круглую сумму, чтобы отсрочить проблему на 1–2 года.
Очень быстро стало понятно, что на этом далеко не уехать, необходимо принципиально новое решение, если мы хотим преодолеть барьер по числу участников. Именно тогда наш доблестный теперь уже сеньор-разработчик (Влад, привет!) предлагает амбициозный проект сервиса вебинаров.
Действительно, ведь чем вебинар принципиально отличается от звонка? Теперь только некоторая группа участников в совещании являются активными, все остальные наблюдают за их разговором. По сути вебинар — это звонок, который транслируется на максимально возможное количество зрителей. Ключевой особенностью была механика запроса голоса: любой зритель мог запросить слово и — с разрешения ведущего — стать спикером, установив с сервером WebRTC соединение.
В конце лета того же года было принято судьбоносное решение в компании: сформировать команду, которая в кратчайшие сроки должна предоставить прототип сервиса. Так появляется наш отдел Вебинаров!
Рецепт первых вебинаров
Глобально, сервис должен состоять, как минимум, из трёх частей:
Модуль приёма видеопотока от ведущего (ведущих) по WebRTC.
Модуль отправки этого потока зрителям.
Модуль управления трансляцией.
С первым модулем задача уже была решена в звонках, нам нужно было лишь перенять от них опыт — подготовить медиа-сервер для приёма потоков.
Всё самое интересное предстояло решить со вторым:
Что модуль отправки получал на вход? Открываем спецификацию WebRTC и видим, что поток сжимается видеокодеком VP8 и аудиокодеком Vorbis — всё это оборачивается в контейнер .webm.
В каком виде этот поток следует отправлять зрителям? Как бы сильно нам ни хотелось отправлять «в таком же» формате, увы, вышеупомянутые кодеки не поддерживались IE и Safari (нам важна была поддержка и первого, и второго браузера). По этой причине у нас сразу же появляется задача конвертации .webm (VP8/Vorbis) в .mp4 (H264/AAC). Для этого, очевидно, понадобится одноимённый компонент конвертор. При этом видео для отправки необходимо будет разбивать на сегменты (чанки), что и послужит в дальнейшем названием микросервиса.
А как именно отправлять поток зрителям? Очевидный ответ — по WebRTC. Догадаетесь, откуда полетят палки в колёса? … Если Apple уже летом 2017 анонсирует поддержку технологии в 11-м сафари, то IE… без шансов. Поэтому для такого случая модуль должен уметь отправлять поток резервным способом — мы выбрали для этого websocket.
Что касается третьего модуля, здесь всё просто: у ведущего должна быть возможность начинать/завершать трансляцию, ставить её на паузу. Сервер обработки сигналов с клиента мы так и назвали — сигналлер (signaller).
Таким образом, у нас уже намечалась следующая микросервисная архитектура:
Интерактивность
Очень скоро мы решили, что одной трансляции камеры ведущего будет недостаточно, поэтому сразу заложили дополнительные возможности: демонстрацию экрана, демонстрацию презентации и доску для рисования.
С трансляцией последних двух нас здорово выручал canvas: его механизмзахватывал всё происходящее, и этот стрим можно было отправлять вместе со стримом ведущего.
Иными словами, браузерное API до неприличия непринуждённо закрывало нам все вопросы со стримами:
getUserMedia () — метод захвата стрима с микрофона и камеры
getDisplayMedia () — метод захвата стрима с окна или экрана
canvas.captureStream () — метод захвата стрима с канваса
Наконец, какой вебинар может пройти без чата зрителей? С этим оказалось всё намного проще: функционал уже был в звонках, им занимался другой отдел, и нам любезно предоставили ту же возможность, дав сконцентрироваться именно на трансляции :)
Запрос голоса
В то же время нужно было сохранить возможность выступить любому участнику вебинара, не только ведущему. Для этого мы сделали механизм запроса голоса: зритель, запрашивая слово, подключался к медиа-серверу тем же механизмом, что и ведущий. В результате они могли общаться будто в звонке, а их видеопотоки отправлялись зрителям, что позволяло наблюдать за диалогом.
Что по трафику?
Как видно, в нашей первоначальной схеме чанкер честно отдаёт видеопоток (стрим) каждому зрителю. Вместе с ростом их числа назревал вопрос:, а как себя почувствует корпоративная сеть в филиалах, когда все сотрудники одного офиса единовременно начнут смотреть вебинар, т.е. загружать из внешней сети FullHD стрим?
Нужно было разработать решение, которое бы снизило трафик внутри локальной сети. К счастью, на помощь пришёл сам WebRTC: тот факт, что мы можем устанавливать прямое соединение между двумя клиентами, позволил реализовать т.н. P2P-дерево доставки контента.
При таком подходе зритель, получая контент от чанкера, может сам выступать в роли отправляющего другим участникам. Безусловно, каждое дополнительное WebRTC соединение повышало нагрузку на него, поэтому один участник мог раздавать стрим максимум трём другим. Последние могли раздавать следующим — отсюда и получалось дерево.
Вебинары. Первый релиз (лето 2017 года)
Итак, нашей команде понадобилось всего полгода, чтобы на свет появилась первая полноценная версия сервиса!
Пока компания привыкала к вебинарам, у нас стояла только одна задача: исследовать нагрузку с реальных зрителей, понять текущий максимум, определить направления оптимизации.
Результат первых «боевых» испытаний: 450 зрителей в одном вебинаре. Позже мы смогли зафиксировать рекорд в 500 человек, дальше чанкер начинает умирать.
Это, конечно, был колоссальный результат на фоне предыдущего барьера звонков. Но, очевидно, что потенциал вебинаров был совсем не раскрыт. Нужно двигаться в направлении оптимизации — просто масштабировать систему пока рано.
Во что мы упирались? Однозначно в раздачу контента.
Как разгрузить чанкер?
После релиза мы также убедились в полной работоспособности идеи P2P-дерева: контент действительно раздавался между зрителями, и это снижало не только нагрузку на сеть, но и нагрузку на чанкер.
Решили взять эту идею в основу дальнейшей оптимизации. Зритель по-прежнему раздавал стрим не более трём другим участникам. Но что, если сделать микросервис, который был бы готов раздавать большему числу зрителей?
Так у нас появился репитер (repeater).
Репитер (лето 2018 — 2019)
Микросервис разворачивался внутри локальной сети филиала. Технически он ничем не отличался от обычного зрителя кроме одного: на нём не было лимита подключений для P2P.
При этом мы скорректировали изначальный алгоритм работы дерева, и теперь каждый зритель сначала пытался подключиться именно к репитеру и только в случае неудачи искал другого «раздающего».
Таким образом, получилось снизить нагрузку и на чанкер, и на каждого клиента в среднем. Трафик локальной сети сконцентрировали в одном направлении, а главное — открыли перспективу масштабирования: гораздо проще увеличивать теоретический пул репитеров в филиале, чем создавать тот же пул чанкеров и систему обмена контентом между ними.
Первая тысяча
Сразу после внедрения репитера мы фиксируем на вебинаре первую тысячу участников! В тот момент — грандиозный успех! Руководители секторов становились смелее и начинали планировать вебинары на 1500–2000 человек — и такое количество нам тоже удавалось держать!
Помните 2 проблемы в начале статьи? Уже на этом этапе они были решены: крупные совещания прекрасно проводились в рамках вебинара, а большие корпоративные конференции, пусть не на всю компанию, но на треть, тоже были возможны!
Разумеется, на этом никто не собирался останавливаться, но спросите нас тогда — что мешало сервису держать на несколько тысяч человек больше? Мы бы ответили — дайте чуть больше железок… Увеличим чуть больше репитеров, нарастим мощность, и всё — весь Тензор в одном вебинаре.
Необходимости такой не было, решение временно отложили…
Свободное развитие (2019)
Безусловно, это самый спокойный период в истории нашей команды. Основная проблема в то время — баги, которые периодически находили тестировщики. Естественно, мы их исправляли.
Вебинарами в компании пользовались всё чаще: у сотрудников уже появлялись идеи для внутренних тренингов, проводились в том числе и развлекательные мероприятия (Впервые провели новогодний 5-тичасовой эфир Тензор ТВ на всю компанию).
В сравнении с бурным стартом мы действительно спокойно развивали продукт:
1. Во всю улучшали фронтенд.
Компания активно использовала свой фреймворк Wasaby (https://wasaby.dev), — у нас была возможность внедрять новые фишки в числе первых отделов.
2. Добавили демонстрацию видеофайлов.
Функционал демонстрации презентаций уже был, почему бы не сделать то же самое с видео? Технически их реализации мало чем отличались: компонент video имеет точно такой же метод captureStream (), как и canvas, т.е. трансляция велась с плеера ведущего.
3. Делали ресёрч.
Было достаточно ресурсов для ресёрча повышения доступности вебинаров: на тот момент для бесперебойного просмотра нужен был стабильный быстрый интернет-канал, но как сделать трансляцию, например, для 3G?
На тот момент набирали популярность технологии адаптивной потоковой передачи данных (Adaptive Bitrate Streaming, ABR) — открытая MPEG-DASH и проприетарная HLS от Apple. Идея механизма заключалась в раздаче стримов сразу в нескольких аудио и видео дорожках (качествах): от 240p до 1080p. Зритель мог бы сам переключаться между ними или довериться алгоритму плеера для выбора оптимального качества (недавно у нас вышла статья на эту тему — ABR для живых трансляций).
Пожалуй, самый неудобный вопрос к нашему сервису в то время был следующий: хорошо, репитер действительно закрыл проблемы нагрузки в филиалах, но как быть с удалёнными сотрудниками? Им ведь приходится подключаться напрямую к чанкеру? Что, если их количество увеличится?
К 2019 году доля удалённых сотрудников компании была невелика. Именно к этому мы и апеллировали: в Тензоре абсолютное большинство очных работников, предпосылок к изменениям в этом никаких не наблюдается.
В конце концов, что такого должно произойти в мире, чтобы количество дистанционных сотрудников стало на порядок больше обычных? …
2020
Разумеется, не только «мы», а весь мир
«That would be funny. If it weren’t so sad.» Выбора не было — с приходом тотальной удалёнки в репитере исчез смысл, P2P-дерево не работало.
По возможностям мы откатились не просто к моменту старта, всё было ещё хуже — в лучшем случае чанкер выдерживал 200 человек. Это была катастрофа!
Обнаружилось ещё и то, что не у всех сотрудников хороший домашний интернет. Поэтому помимо проблемы с нагрузкой чанкера актуальной стала задача адаптивного стриминга, ресёрчем чего мы, к счастью, уже занимались.
В вебинарах предстояло много инноваций.
Рождение ориджина
С самого начала наша архитектура предполагала наличие активного соединения со зрителем — непосредственная отправка стрима по WebRTC или websocket.
Однако существовал принципиально другой подход: складывать чанки на ресурсе и отправлять зрителям ссылку на них. В этом случае, клиент будет скачивать его по HTTP, как статику с кеш-сервера. Ключевой момент: нет никакого постоянного соединения между ориджином и клиентом.
Эта фишка идеально сочеталась с ABR: зритель получал ссылку на плейлист чанков (.mpd файл в случае MPEG-DASH и .m3u8 в случае HLS), внутри которого содержалась информация о всех вариантах качества стрима, а также ссылки, по которым их можно загружать.
Основное преимущество такого микросервиса — простейшая масштабируемость: чанки складываются на основном (origin) сервере, пользователи же обращаются к edge серверам. Если у edge сервера отсутствует конкретный чанк, он загружает его с ориджина и отдаёт зрителю. Следующим зрителям он сразу отдаст этот сегмент.
Стало ясно, что с чанкером пора прощаться. Осталось только из WebRTC-потока ведущего научиться делать ABR.
От конвертера к транскодеру
Одно дело — конвертировать .webm в .mp4, совсем другое — делать из потока сразу несколько дорожек по стандарту ABR. Это уже задача транскодирования, ввиду чего нужен был новый сервис — транскодер (transcoder).
От сигналлера к бизнес-логике (БЛ)
Зрители как-то должны получать ссылку на стрим. Если раньше у них было активное соединение с чанкером, теперь хотелось бы дать API для получения информации о стримах. Так мы трансформировали сигналлер в бизнес-логику.
Вебинары. Второе поколение (2020 год)
Спустя первую половину этого кошмарного года архитектура стала выглядеть следующим образом:
Но это того стоило!
Результаты после релиза второго поколения, 2000 зрителей. Вернулись к показателям прошлого года. Только теперь сотрудники были «разбросаны по интернету».
Догадываетесь, какая приоритетная задача стала у нас следующей?
Проект »10к зрителей на один вебинар» (2021 год)
Очевидно, что нашей следующей задачей становится полное покрытие штата компании. Так появился проект с говорящим названием.
Суть выражалась кратко: всё оптимизировать и масштабироваться, — что может быть проще? Тем не менее, вот три важных момента:
Минимизация расходов на железо. Нужно было пройтись шлифовкой по всем микросервисам: где-то устранить неоправданно высокий жор ресурсов, где-то просто оптимизировать работу.
Масштабирование кеша. Ориджин отлично справлялся со своей работой раздачи стримов, но оказалось, что более выгодно купить внешний CDN, чем разворачивать дополнительные мощности у себя.
P2P. Сотрудники потихоньку возвращаются в офис, а значит, становится актуальным знакомый механизм. Необходимо по максимуму оптимизировать его алгоритмы.
Указанное число зрителей бралось с приличным запасом: на момент старта проекта число сотрудников компании только-только приближалось к отметке 6000. И понятно: для проверки достижения именно этого числа понадобится нагрузочное тестирование с применением зрителей-ботов.
Как вы думаете, что в этом проекте было самым сложным? Вы правы — провести это самое нагрузочное тестирование! Продемонстрировать, что мы достигли цели, и можем собрать всех сотрудников на один вебинар!
Оказалось, что раньше, не имея такой возможности, никто и не планировал никаких всеобщих конференций — они просто не предусматривались!
Компания уже проводила стабильные трансляции, на которых присутствовали по 3–4 тысячи человек, но для сдачи проекта всё равно нужно было набрать 10 тысяч.
На момент 2021 года мы не нашли сервис ботов, который бы предоставил их в таком количестве — максимум 4 тысячи. Следовательно, нам точно нужны были все компьютеры компании. Сначала хотели, чтобы одним вечером все сотрудники всех филиалов под конец рабочего дня не выключали машины, чтобы мы могли их использовать в нашем нагрузе, но многие всё равно этого не сделали. В конце концов, безопасники фокус не оценили, сказали «небезопасно» (и, в общем-то, были правы) — фокус не удался :) Далее в компании был объявлен день единого вебинара — день, когда все сотрудники всех подразделений должны зайти на вебинар и посмотреть, функционирует ли он конкретно в их браузере на их компьютере.
В Тензоре много отделов, и сотрудники не обязаны знать про каждый. Но вот с того момента в компании не осталось ни одного человека, кто не слышал бы про нас.
Вебинары 3. На пути к совершенству (2022 год — наст. время)
Преодолев отметку в 10 тысяч зрителей, мы смогли сконцентрироваться на фичах нашего сервиса. Архитектура оставалась прежней, но, тем не менее, произошло событие, ознаменовавшее новое поколение вебинаров — переход фронтенда на ReactJS.
Вместе с этим сразу адаптировали интерфейс к мобильным устройствам — теперь стало возможным смотреть вебинар через браузер телефона (в начале 2023 мы сделали возможным даже проводить его с телефона).
Транскодер тоже получил новые фичи. Далеко не полный список:
Научился транслировать видеофайл сам.
Раньше мы транслировали его напрямую из плеера ведущего, теперь же транскодер получает сигналы «перемотай», «останови», а зрители видят нужную секунду видеофайла.
Научился работать с видеокодером (OBS).
Вебинары всё больше становились похожи на стриминговые платформы — мы решили сделать возможным использовать тот же инструментарий.
Научился накладывать виртуальный фон.
Уверен, у каждого сотрудника одно из ярких воспоминаний года удалёнки — виртуальные фоны, скрывающие бардак на заднем плане. Теперь это стало возможным сделать и у нас!
Заключение
Чем же занимаемся мы сейчас? «Быстрее, выше, сильнее». Теперь наша задача — сделать продукт предельно отказоустойчивым.
Тернистый путь к сегодняшним вебинарам занял у нас почти 7 лет и 3 большие итерации. Могли мы сразу разработать текущую архитектуру? Однозначно нет. WebRTC — одна из самых молодых веб-технологий, и мы развивались буквально вместе с ней (более того — развиваемся до сих пор).
Чему мы научились за эти годы?
Пробовать разные популярные медиа-серверы в поисках максимально подходящего под наши нужды.
Распотрошили полностью ffmpeg в собственном форке — не бойтесь брать такого масштаба open-source проекты и делать его под себя.
Пришли к внешнему CDN кешу: отказ от внешнего сервиса видеосвязи не означает, что мы не можем использовать внешний сервис кеширования. Это решение оказалось более дешёвым и простым.
Всей этой истории и нашего отдела не было бы, выбери тогда компания сторонний сервис видеосвязи.
Наконец, самое главное, чего мы достигли — полностью закрыли вопрос видеокоммуникации в нашей компании и сделали это даже с запасом!