Завантаження відео «без жодного розриву»

Відео – один з найпопулярніших сервісів на Однокласниках. Чого тільки не вантажать наші користувачі, від милих сюжетів з дитячого ранку до знятих на відеореєстратор аварій. Тому швидко і стабільно працює завантаження відео важлива нам не тільки як одна з найбільш затребуваних користувачами функцій, але і як необхідна умова для генерації контенту. А значить, і для бізнесу: є хороший контент — є користувачі, тобто користувачі — є бабло.

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


Так, це



У цій статті ми розповімо про те, як ми перемогли всі ці проблеми, опишемо архітектуру нашого рішення і причини, з яких вона вийшла саме такою.


Цифри вирішують все
Щодня користувачі «Однокласників» завантажують майже двісті тисяч відеороликів, а з аудиосообщениями (так-так, ми хостим аудіоповідомлення на тому ж кластері, що і відео) — кількість щоденних завантажень перевищує мільйон.

Кожен день до нас на сервери потрапляє 15-20 терабайт нового відео, а пікове навантаження досягає 5 гігабіт/сек. Більшість завантажених відео – це короткі ролики, зняті користувачами на смартфони. У той же час за сумарним обсягом завантажень терабайтах 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 з використанням фреймворків RequireJS, jQuery і чудової бібліотеки FileAPI від RubaXa Mail.Ru.

FileAPI визначає, чи підтримує інтерфейс браузер HTML5. Якщо підтримує, то всі процедури виконуються за допомогою HTML5. Якщо не підтримує — то FileAPI сам перемикається на Flash. Також від браузера користувача залежить і розмір відправляються chunk'ів.

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


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

З точки зору користувача все це багатство проявляється приблизно так: поки йде завантаження користувач може ввести назву для свого відеоролика, заповнити опис, вибрати відеоканал, задати теги і вибрати обкладинку. І, природно, паралельно ходити при цьому за порталу — слухати музику, нишпорити фотки і спілкуватися в приват з друзями.



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

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



Логіка цього процесу дуже проста. FileAPI відправляє на сервер завантаження один чанк і чекає відповіді. Якщо відповідь не приходить протягом деякого часу, клієнт відправляє цей чанк знову, потім ще раз і ще раз, до тих пір, поки сервер не підтвердить успішне прийняття. У свій час перехід на FileAPI дозволив нам в кілька разів скоротити число помилок під час завантаження.



Мобільні пристрої
Якщо говорити про кількість завантажень відео на портал, то картина виходить така:



Мобільні користувачі можуть завантажувати відео двома способами — з браузера і з програми. У мобільних браузерах завантаження поновлюється при обриві мережі, а в мобільних додатках — ще й після перезавантаження телефону (наприклад у разі розрядки батареї).

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

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

Якщо браузер підтримує HTML5 Web Worker API, то завантаження здійснюється в окремому потоці, що допомагає зробити нам інтерфейс більш чуйним.

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

Бекенд завантаження відео. Архітектура
У зв'язку з постійним зростанням навантаження ми постійно розширюємо та модернізуємо інфраструктуру нашого відеосервісу. Сьогодні сервіс відео — це
  • 240 серверів для зберігання призначених для користувача відео. Дисків там більше 7000 — сумарно близько 30 петабайт;
  • метадані і кеш розгорнуті ще на 36 машинах;
  • за трансформацію відеороликів в наш внутрішній формат відповідають 150 серверів;
  • нарешті, 36 машин використовуються для роздачі і завантаження відео.
Таким чином, наш відеосервіс складається з більш ніж 400 машин. Залізо у нас досить звичайне — щось типу двопроцесорних E5-2620 з 64Гб ОПЕРАТИВНОЇ пам'яті. Архітектура добре скаліруется, дозволяє нам запросто використовувати ці дешеві і, загалом-то, вже далеко не нові процесори, і тим самим істотно економити на залозі. Економіка тут проста: кожна $1000 економії в ціні сервера виливається нам у півмільйона доларів економії на всьому відеосервісі. А якщо говорити про портал в цілому, де серверів у нас зараз, близько 11 тисяч, то картина стає ще приємніше :)

Власне, архітектура бекенду завантаження відео, побудована з урахуванням наступних основних вимог:
  • відновлення завантаження протягом декількох діб після втрати з'єднання;
  • працездатність сервісу при програмні помилки апаратних відмови;
  • гарантія збереження завантажених даних при відмові сервера або втрати цілого датацентру;
  • висока продуктивність.


За завантаження відео в Однокласниках відповідає підсистема з 6 серверів, розподілених за трьома датацентрах. Перед кожною парою серверів завантаження в ДЦ варто кластер 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 server-у межах ДЦ. Доступний 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 Кб;
  • практично будь-яку высоконагруженную систему має сенс тестувати на відмовостійкість кількома різними сценаріями, в тому числі, імітуючи аварії.
Ну і не забувайте про мобільні пристрої — мобільний трафік на великих порталах давно вже перевищив трафік з десктопів.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.