Хмари на службі ЗМІ, або Як Amazon допомагає обробляти великі обсяги відеоконтенту

Нашому замовнику, одному з найбільших світових видавництв, потрібно було збільшити продуктивність програми для публікації відео новин у зв'язку з зрослим обсягом трафіку. Користувачі програми — редактори media-ресурсів. В день через нього проходить близько 200 новинних роликів, середній розмір кожного з них ~ 500 мб, усього близько 100 Гб свіжих новин на добу.

Сьогодні ми поділимося досвідом, як CloudFront і S3 допомогли нам побудувати высоконагруженную і стійку систему обробки контенту.



Сподіваємося, що наш досвід зацікавить розробників/проектувальників систем по зберіганню та обробці матеріалів (відео, аудіо, зображення) і технічних спеціалістів, що активно використовують сервіси AWS.


Визначимося з інструментами і термінологією

Amazon Web Services пропонує набір сервісів для зберігання і доставки контенту, а їх використання стає невід'ємною частиною сучасних IT платформ.



Передісторія — що ми з'ясували?

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



Проаналізувавши архітектуру системи, ми виявили наступні вузькі місця:


#1 Проблема завантаження великого обсягу даних з різних точок земної кулі
Систему використовують редактори з різних точок земної кулі, а оригінальний відеоконтент має, як правило, досить великий об'єм (сотні Mb для 10-хвилинного ролика). Процес передачі даних, а стало бути, і час їх обробки і публікації, залежить від віддаленості редактора від сервера додатків.

#2 Проблема навантаження сервера
Завантажуване редакторами відео першим кроком потрапляє на сервер, де розгорнуто додаток. Далі нам потрібно перекодувати відео в різні формати, додати для нього субтитри. Для цього ми використовуємо сторонні сервіси обробки відео. Робота з кожним сервісом проходить за наступною схемою:



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

Що ми зробили?

В першу чергу, ми перейшли до пошуку вирішення проблеми навантаження сервера. Для зменшення обсягу переданої інформації вирішили перенести зберігання і роздачу контенту на плечі сторонніх файлових сховищ або сервісів.
Ми розглядали сервіси, які задовольняли б таким основним критеріям:
можливість стороним систем забирати контент на обробку;
можливість обмежувати доступ до контенту як за часом, так і по посиланнях;
Першим основним кандидатом для нас став AWS S3, який дозволяє використовувати підписані урли (деталі -> docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html).

З використанням S3 процес обробки контенту сторонніми сервісами змінюється. Додаток тепер відправляє лише посилання на контент, стороння система забирає його самостійно S3 по підписаної посиланням.



Але в нашому випадку такий варіант не підходив, бо не вирішувалася завдання прискорення завантаження даних у сховище.



Наступною альтернативою став CDN CloudFront. На відміну від інших популярних CDN, він дозволяє, використовуючи http методи POST, PUT, DELETE, управляти контентом на S3, тобто фактично CDN стає повноцінною обгорткою для свого джерела-сховища. CloudFront шле дані з оптимізованим маршрутами, використовує постійні з'єднання TCP / IP і прискорює доставку контента ( aws.amazon.com/ru/about-aws/whats-new/2013/10/15/amazon-cloudfront-now-supports-put-post-and-other-http-methods).

Як бачимо, схема роботи з сервісами обробки контенту залишається практично такою ж, що і у випадку з S3.



Але для користувачів системи все стало значно краще: вміст завантажується на найближчий CloudFront сервер швидше, ніж безпосередньо в сховище S3.



Таким чином, ми вбиваємо відразу двох зайців: швидке завантаження даних і їх збереження безпосередньо в AWS S3, минаючи сервер додатка і файлову систему.

В результаті реструктуризації отримуємо наступну систему:
  • додаток відео-менеджер працює безпосередньо тільки з метаданими;
  • вихідні відеофайли зберігаються безпосередньо з інтерфейсу на S3 через CloudFront;
  • сторонні сервіси, яким потрібний відеоконтент, отримують його за підписаним посилання
через CloudFront.



Технічні деталі



Кілька ключових моментів по конфігурації S3 і CloudFront
Конфігурація S3


Налаштування CORS
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>


Налаштування CloudFront

Налаштовуємо два distribution CloudFront'a на наш цільовий S3-бакет. Перший потрібен тільки для завантаження контенту.
Ключові конфігурації:

Settings Origin
Restrict Bucket Access - Yes;
Allowed Http Methods - GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE; 
Default Cache Settings Behavior
Restrict Viewer Access (Use Signed URLs) - Yes;
Trusted Signer - Self
Другий налаштовуємо для віддачі:
Origin Settings
Restrict Bucket Access - Yes;
Allowed Http Methods - GET, HEAD;
Default Cache Settings Behavior
Restrict Viewer Access (Use Signed URLs) - Yes;
Trusted Signer - Self



Інтеграція з додатком

Робота на стороні користувача


Для того щоб нова схема взаємодії запрацювала, довелося вирішити декілька інтеграційних завдань.

Популярні завантажувачі контенту використовують multipart/form-data, який не вийде використовувати з CloudFront, т. к. він не розбирає тіло запиту, а зберігає його як є. Довелося трохи модифікувати плагін angular-file-upload (на проекті використовується в основному AngularJS): для завантаження файлу методом PUT використовували xhr.send(Blob) (деталі тут -> dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#the-send%28%29-method).

Як з'ясувалося, завантажені таким чином файли доступні AWS системі тільки для псевдо-користувача cloudfront-identity і не доступні за підписаним урлам. Ми почали шукати спосіб налаштувати права доступу для файлів, що завантажуються на AWS. Довелося вивчати документацію і експериментувати, т. к. в мережі подібної інформації вкрай мало. У результаті встановили, що права при завантаженні файлів через CloudFront налаштовуються http-заголовків S3 docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html.

Приклад коду
Ми використовували angular-file-upload для завантаження файлів

Визначаємо FileUploader:
$scope.videoUploader = new FileUploader({
autoUpload: true,
method: "PUT",
useDirectUpload: true, // а це наша кастомізація для FileUploader - використовуємо html5 XmlHttpRequest завантаження без FormData
headers: {
'x-amz-acl': 'authenticated-read' // той самий magic header (http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html)
}
});


Визначаємо handler для генерації кінцевої посилання завантаження на cloudfront:
$scope.videoUploader.onBeforeUploadItem = function(item) {
$.ajax({
url: "base-url.com/file/generateUploadUrl", // генеруємо підписаний урл для завантаження на CloudFront
type: 'GET',
data: {fileName: item.file.name, fileSize:item.file.size},
async: false,
success: function(data) {
item.url = data.uploadUrl; // виставляємо аплоадеру отриманий урл
}
});
};


Визначаємо handler успішного закінчення завантаження
$scope.videoUploader.onSuccessItem = function (item, response, status, headers) {
if (200 <= status && status < 300) {
... // якісь дії, наприклад, шолом сервера підтвердження завантаження файлу.
}}



На сервері

Щоб отримати підписану посилання на скачування файлу, використовуємо стандартний клас з AWS SDK com.amazonaws.services.cloudfront.CloudFrontUrlSigner .

Згенеровані посилання ми віддаємо користувачам для заливки файлів на s3 або сервісів для їх скачування.

Приклад коду

public class CloudFrontConfig {
/**
* for example http://get.example.cf.com/ or http://put.example.cf.com/
*/
private String cloudFrontDomainNameForGet;
private String cloudFrontDomainNameForPut;

private String cloudFrontPrivateKey;
private String cloudFrontKeyPairId;

public String getDownloadUrlForUser(String s3key) throws Exception {
return getSignedURL(cloudFrontDomainNameForGet, s3key);
}

public String getPutUrlForService(String s3key) throws Exception {
return getSignedURL(cloudFrontDomainNameForPut, s3key);
}

private String getSignedURL(String domain, String s3Key) throws Exception {
PrivateKey privateKey = loadPrivateKey(cloudFrontPrivateKey);

Date dateLessThan = getDateLessThan();

String url = CloudFrontUrlSigner.getSignedURLWithCannedPolicy(domain + s3Key,
cloudFrontKeyPairId, privateKey, dateLessThan);
return url;
}

private Date getDateLessThan() {
LocalDateTime dateNow = LocalDateTime.now();
ZonedDateTime zdt = dateNow.plusDays(1).atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}

private PrivateKey loadPrivateKey(String cloudFrontPrivateKey) {
// конструюємо об'єкт PrivateKey з допомогою приватного ключа
}

}



Що ми отримали в результаті?



Редактори видавництва залишилися задоволені оновленою системою: за їх словами, вона стала працювати набагато швидше, що дозволило прискорити випуск новин.

За статистикою від AWS ми отримали:
  • зменшення вхідного трафіку на сервер з 3Tb до 1 Гб в місяць;
  • зменшення вихідного трафіку з сервера з 12Tb до 1 Гб в місяць;
  • розмір файлової системи зменшився з 500Гб до 2Гб.


У результаті:
  • Ми оптимізували завантаження і управління доступом до контенту за допомогою використання S3 і CloudFront;
  • Знизили і мережеву файлову навантаження на сервері;
  • Написали статтю :)

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

0 коментарів

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