company_banner

Загрузка видео «без единого разрыва»

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

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


    Да, это



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


    Цифры решают всё

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

    Каждый день к нам на серверы попадает 15-20 терабайт нового видео, пиковый входящий трафик до 5 гигабит/сек а исходящий достигает 500 гигабит/сек. Большинство загружаемых видео — это короткие ролики, снятые пользователями на смартфоны. В то же время по суммарному объему загрузок в терабайтах web все еще остается лидером.

    Изменилось и качество видео — камера формата Full HD давно стала стандартом комплектации любого мобильного устройства. По мере выхода из обращения старых смартфонов и приобретения новых доля загружаемых пользователями видеороликов в высоком и сверхвысоком разрешении неумолимо растет. За последний год число загружаемых роликов в качестве выше чем Full HD выросло более чем вдвое.



    Разумеется, вместе с повышением качества растет и размер загружаемых видеофайлов: при переходе в качестве на 1 шаг вверх (720p —> 1080p, 1080p —> 1440p и т.д.) объем дискового пространства, занимаемого видео, возрастает примерно в два с половиной раза.

    Давайте посмотрим, как реализована загрузка видео на портал в наших клиентах: в браузере (веб-версия), в мобильных приложениях (iOS/Android/WinPhone) и на мобильном портале.

    Web-версия

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

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

    А если автоматически обновляются — тоже могут быть проблемы. Вот, вышел неделю назад Firefox 40, и у миллионов наших пользователей, которые автоматически проапдейтились на него, сломалась загрузка фоток. Мы быстро все починили (в этот раз во всем были виноваты несовместимости в Content Security Policy), но бывает, что починка занимает довольно существенное время.


    Как же нам удалось добиться стабильной работы портала в таком зоопарке браузеров? Fallback, fallback и еще раз fallback!

    Клиентская часть нашего загрузчика видео написана на JavaScript c использованием фреймворков RequireJS, jQuery и замечательной библиотеки FileAPI от RubaXa из Mail.Ru.

    FileAPI определяет, поддерживает ли пользовательский браузер HTML5. Если поддерживает, то все процедуры выполняются с помощью HTML5. Если не поддерживает — то FileAPI сам переключается на Flash. Также от браузера пользователя зависит и размер отправляемых chunk’ов.

    Для каждого браузера мы экспериментальным путём подобрали свой размер чанка. В среднем он равен 2 Мб, а диапазон колеблется от 100 Кб до 10 Мб.


    Загрузка файлов сделана максимально удобной для юзера. Поддерживается джентльменский набор функций: drag&drop, одновременная загрузка нескольких файлов, автоматически возобновляемая загрузка, кнопка паузы, индикатор хода выполнения и т.д. и т.п.

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



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

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



    Логика этого процесса очень проста. FileAPI отправляет на upload-сервер один чанк и ждёт ответа. Если ответ не приходит в течение некоторого времени, клиент отправляет этот чанк снова, потом еще раз и еще раз, до тех пор, пока сервер не подтвердит успешное принятие. В свое время переход на FileAPI позволил нам в несколько раз сократить число ошибок во время загрузки.



    Мобильные устройства

    Если говорить о количестве загрузок видео на портал, то картина получается такая:



    Мобильные пользователи могут загружать видео двумя способами — из браузера и из приложения. В мобильных браузерах загрузка возобновляется при обрыве сети, а в мобильных приложениях — еще и после перезагрузки телефона (например, в случае разрядки батареи).

    Клиентская часть мобильного загрузчика сначала пытается залить сразу весь файл от начала до конца, используя XMLHttpRequest.send(). В случае обрыва соединения загрузчик пытается восстановить связь с сервером, опрашивая статус загрузки. Если удаётся получить ответ от сервера, загрузчик использует Blob.slice() для того, чтобы получить блок данных, следующий за последним успешно загруженным байтом.

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

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

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

    Бэкенд загрузки видео. Архитектура

    В связи с постоянным ростом нагрузки мы непрерывно расширяем и модернизируем инфраструктуру нашего видеосервиса. Сегодня сервис видео — это
    • 240 серверов для хранения пользовательских видео. Дисков там более 7000 — суммарно около 30 петабайт;
    • метаданные и кэш развёрнуты еще на 36 машинах;
    • за трансформацию видеороликов в наш внутренний формат отвечают еще 150 серверов;
    • наконец, еще 36 машин используются для раздачи и загрузки видео.

    Таким образом наш видеосервис состоит из более чем 400 машин. Железо у нас в целом довольно обычное — что-то типа двухпроцессорных E5-2620 с 64Гб RAM, но сервера трансформации имеют более мощные CPU, а на серверах раздачи — 256Гб RAM и 10Тб SSD. Архитектура хорошо скалируется, позволяет нам запросто использовать эти дешевые и, в общем-то, уже далеко не новые процессоры и тем самым существенно экономить на железе. Экономика тут простая: каждая $1000 экономии в цене сервера выливается нам в полмиллиона долларов экономии на всем видеосервисе. А если говорить про портал в целом, где серверов у нас сейчас около 7 тысяч, то картина становится еще приятнее :)

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


    За загрузку видео в Одноклассниках отвечает подсистема из 6 серверов, распределённых по трем датацентрам. Перед каждой парой upload-серверов в ДЦ стоит кластер LVS серверов (Linux Virtual Server — это модуль ядра Linux, который позволяет распределять IP трафик на любое количество физических серверов).

    Для балансировки запросов между ДЦ используется DNS-GSLB (Global Server Load Balancing). Это сервера, которые резолвят доменное имя в IP наиболее разгруженного/доступного датацентра. В случае отказа одного из датацентров DNS-GSLB равномерно перераспределит нагрузку по оставшимся.



    Рассмотрим процесс загрузки видео:
    • пользователь инициирует загрузку, и сервер выдает ему URL для загрузки: http(s)://vu.mycdn.me/upload.do?...
    • далее DNS-GSLB разрешает доменное имя vu.mycdn.me в IP одного из LVSов (на рисунке в ip1);
    • DNS-GSLB партиционирует пользователей по первым трем октетам их IP адреса. Таким образом, одному пользователю при повторных DNS резолвах выдается IP одного и того же датацентра. Выдача IP-адреса другого ДЦ произойдет только при его отказе или смене IP пользователя, что случается редко;
    • далее LVS внутри ДЦ уже перенаправляет запросы к менее загруженному и доступному серверу;
    • на LVS настроен IP affinity, который обеспечивает отправку всех пользовательских запросов к одному серверу.


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

    Параллельно процессу загрузки видео на upload-сервер полученные данные отправляются в распределённое хранилище. Для каждого пользователя на сервере открыта сессия и буфер для приема данных. Размер буфера — 10 МБ. Как только старый буфер заполняется, одновременно происходят две вещи:
    • открывается новый буфер;
    • запускается асинхронная операция сброса старого буфера в промежуточное распределенное хранилище.

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

    В случае выхода из ротации одного из серверов внутри ДЦ LVS передаст все запросы доступному upload-серверу внутри ДЦ. Доступный upload server восстанавливает состояния клиентской сессии по данным, имеющимся в распределенном хранилище, и пользователь незамедлительно продолжает загрузку, в худшем случае с retry последних загруженных 10 Мб.



    Когда пользователь переключается на другой сервер, может появиться «дырка» в последовательности загружаемых байт. В этом случае сервер возвращает специальный код ошибки 416 — «Range is not acceptable error, recoverable» с заголовком «X-Last-Known-Byte». Если клиент поддерживает данный заголовок, то он возобновляет загрузку с места, указанного в этом заголовке, а если нет — идет на один чанк назад.

    В случае выхода ДЦ из строя (ситуация более редкая, чем выход из строя сервера) клиентская библиотека загрузки файлов (например, FileAPI) будет в течение «ретрай-времени» пытаться возобновить загрузку по IP LVSа, расположенного в упавшем ДЦ. Все новые загрузки продолжатся через доступные ДЦ.



    Отказоустойчивость бэкэнда

    Три основных сценария для проверки отказоустойчивости нашего сервиса — это:
    • сценарий с выходом датацентра из строя;
    • сценарий с перегрузкой по диску;
    • сценарий с перегрузкой по трафику.


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

    Сценарий с перегрузкой по входящему трафику для нас тоже малореален. Каналы, которые мы приобретаем в датацентрах, симметричны, и поскольку наш download трафик превосходит наш upload трафик примерно в 100 раз, то перегрузку по upload мы тоже всерьез не считаем за угрозу. Основная наша защита здесь — рубильники, которые отключают части пользователей загрузку видео. Таких частей (партиций) у нас 256, поэтому мы можем регулировать количество пользователей, которые могут загружать (или наоборот просматривать) видео, с шагом меньше, чем 0,4%.

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

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

    Факап со шпинделями

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

    После Парада Победы 9 мая начался резкий рост загрузок видеозаписей парада и салюта. Мы не ожидали трехкратного увеличения пикового трафика, поэтому дисковая подсистема временного хранилища очень быстро оказалась загруженной на 100%. Upload-сервера стали получать ошибки при попытке сбросить чанк во временное хранилище — хранилище не отвечало. У каждой сессии есть буфер, в который принимаются входящие данные. Буферы жрут место, поэтому место в оперативке для сессий на upload-серверах тоже быстро закончилось…

    Т.е.
    • клиентский загрузчик хотел загрузить чанк
    • в буфере сессии не было места
    • сервер возвращал клиенту возобновляемую ошибку.

    Клиентский загрузчик повторял попытки до тех пор, пока у upload-сервера не появлялся свободный буфер (пока upload-серверу не удавалось сбросить буфер в распределенное хранилище).

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

    Итоги были таковы: в целом скорость загрузки на портал просела примерно вдвое, но отказа сервиса не произошло, и все пользователи в итоге догрузили свое видео.

    Выводы

    • Если у вас в требованиях работа во многих браузерах, то используйте готовые решения для fallback — FileAPI для загрузки файлов, Atmosphere и Pusher для push-нотификаций и т.п.;
    • для лучшего баланса между производительностью и кроссбраузерностью имеет смысл менять размер чанка в зависимости от клиентского браузера. Дефолтный размер чанка — 2 Мб, но есть проблемные браузеры, для которых этот размер нужно уменьшать до 500 Кб, а то и до 100 Кб;
    • практически любую высоконагруженную систему имеет смысл тестировать на отказоустойчивость несколькими различными сценариями, в том числе имитируя аварии.

    Ну и не забывайте про мобильные устройства — мобильный трафик на крупных порталах давно уже превысил трафик с десктопов.
    Одноклассники
    269,00
    Делимся экспертизой
    Поделиться публикацией

    Комментарии 12

      +1
      240 серверов для хранения пользовательских видео. Дисков там более 7000 — суммарно около 30 петабайт;
      метаданные и кэш развёрнуты еще на 36 машинах;
      за трансформацию видеороликов в наш внутренний формат отвечают еще 150 серверов;
      наконец, ещё 36 машин используются для раздачи и загрузки видео.

      Почему нельзя конвертировать видео на 240 стороджах? На сторадже всегда CPU загружен минимально и было бы логично конвертировать именно там.
      И почему нельзя загружать файлы и раздавать файлы опять таки напрямую со стороджей? Насколько я понимаю, канал наружу — это 36 серверов? Они наверняка часто втыкают по диску из-за загрузки?
        +7
        Сервера отвечающие за трансформацию имеют специфичное для этого железо, которое делает трансформацию видео на порядок быстрее чем у конкурентов. Попробуйте залить 1080 или выше в другие соц сети :)
        Обязательно раскроем все секреты трансформации в следующей статье.

        Раздавать со стораджей мы пробовали, и потом быстро отказались, ибо замена диска может ребут требовать, а это уже даунтайм.
          +1
          Специфичное железо это те самые красивые дорогие серверные видеокарты без видеовыходов?
            +2
            пока нет, хотим в будущем заменить эти 150 серверов, на 15 но с GPU
            пока пробовали резать на Tesla K40, используя ffmpeg 2.6 со свежей реализацией кодека nvenc. производительность параллельной нарезки видео 2160р в 8 качеств вышла такая же, как у процессора E5-2643
        +5
        Канал на отдачу видео это 30 серверов и на каждом 40Гбит/сек сеть — они имеют 2 уровня кэша 256Гб рама и 10Тб SSD дисков.
        Они не втыкают, они умеют менять контейнер видео на лету (mp4, dash, hls) и про это тоже в следующей статье.
        +1
        картинка с матом для привлечения внимания морально деградировавшей части аудитории?
          +6
          Я тоже считаю, что такие картинки не к месту к техническим статьями.
            +9
            А по-моему смешная картинка. Мат тоже не люблю, но данная надпись как мат не воспринимается.
              –11
              Слы-ы-ыш, мля! Ты чё на ОК гонишь, поцанчек? С кокова раёна? Сюда иди, ёмана!
              0
              для лучшего баланса между производительностью и кроссбраузерностью имеет смысл менять размер чанка в зависимости от клиентского браузера. Дефолтный размер чанка — 2 Мб, но есть проблемные браузеры, для которых этот размер нужно уменьшать до 500 Кб, а то и до 100 Кб

              А можно поподробней? В каких браузерах возникают проблемы?
              Почему вы привязывайтесь к весу чанка а не к частоте кейфреймов?

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

              Самое читаемое