Блог Amazon Web Services
Представляем CloudFront Functions: запускайте код в любых масштабах на периферии с низкой задержкой
Зарегистрируйтесь, чтобы получать приглашения на мероприятия AWS на русском языке.
Оригинал статьи: ссылка (Danilo Poccia, Chief Evangelist (EMEA))
С помощью Amazon CloudFront вы можете безопасно доставлять данные, видео, приложения и API клиентам по всему миру с низкой задержкой и на высокой скорости. Для индивидуальной настройки возвращаемого результата и обеспечения минимально возможной задержки многие современные приложения выполняют часть бизнес-логики на периферии. Такие сценарии можно сгруппировать в две основные категории:
- Сложные операции, требующие большое количество вычислительных ресурсов, которые выполняются, если нужный объект не найден в кэше. В 2017 году мы запустили Lambda@Edge, которая позволяет создать полностью программируемую среду для бессерверных вычислений на периферии: с помощью неё можно выполнять широкий спектр задач по сложной обработке запросов. Функции Lambda@Edge запускаются на периферийных серверах кэширования в регионах (regional edge cache), которые обычно находятся в регионе AWS, ближайшем к используемой клиентом точке присутствия CloudFront. Например, при потоковой передаче видео или аудио вы можете использовать Lambda@Edge для создания и отправки нужных сегментов «на лету», что позволяет уменьшить требования к масштабируемости сервера-источника. Другой популярный пример – использование Lambda@Edge и базы данных Amazon DynamoDB для конвертации удобных коротких URL-адресов в полные адреса.
- Простые преобразования запросов или ответов HTTP(s), которые могут быть выполнены функциями за очень короткое время. Для такого сценария вам нужна гибкая среда программирования с высокой производительностью, масштабируемостью и экономичностью, что позволит запускать функцию для каждого запроса.
Мы рады сообщить о выпуске CloudFront Functions: это новая платформа бессерверного выполнения скриптов, которая поможет вам со второй категорией сценариев, описанных выше. Она позволяет запускать легковесный JavaScript-код на более чем 218 периферийных местоположениях CloudFront по стоимости примерно равной 1/6 от цены Lambda@Edge.
CloudFront Functions идеально подходят для простой обработки веб-запросов, например:
- Работа с ключом кэширования и нормализация: изменение атрибутов HTTP-запроса (URL, заголовки, файлы cookie, строка запроса) для создания ключа кэширования, который является уникальным идентификатором объектов в кэше. Он используется для проверки, содержится ли объект в кэше или нет. Например, вы можете сохранять данные в кэше на основании заголовка, который определяет тип устройства пользователя. Таким образом, вы создаёте две версии сайта: для мобильных и для настольных устройств. Кроме того, с помощью изменения атрибутов вы можете нормализовать разные запросы к одному ключу кэширования, тем самым повысив частоту попадания в кэш.
- Изменения URL и перенаправления: вы можете вернуть ответ, который перенаправит запрос на другой URL-адрес. Например, перенаправить неавторизованного пользователя на страницу входа вместо страницы с закрытым доступом. Также изменение URL можно использовать для A/B-тестирования.
- Изменение HTTP-заголовков: просматривайте, добавляйте, изменяйте или удаляйте любые заголовки запросов и ответов. Например, вы можете добавить заголовки HTTP Strict Transport Security (HSTS) к ответу или добавить новый заголовок запроса к серверу-источнику, в котором будет содержаться IP-адрес пользователя.
- Авторизация доступа: внедрите контроль доступа к содержимому, предоставляемому через CloudFront, с помощью создания и проверки пользовательских токенов, таких как HMACили JSON web tokens (JWT), для разрешения или запрета запросов.
Чтобы обеспечить производительность и масштаб, которые требуются современным приложениям, CloudFront Functions используют новую модель изоляции на уровне процессов вместо изоляции на уровне виртуальных машин, которая используется в AWS Lambda и Lambda@Edge. Для этого нам пришлось ввести некоторые ограничения, такие как запрет на доступ к сети и файловой системе. Кроме того, функции должны выполняться менее 1мс (миллисекунды), что позволяет обработать миллионы запросов в секунду. Благодаря этому, функции практически не влияют на общую производительность сети доставки контента (CDN).
По аналогии с Lambda@Edge, CloudFront Functions выполняют ваш исходный код в ответ на триггеры (события) из CloudFront, а именно, они могут вызываться после получения запроса от пользователя (viewer request) или перед отправкой ответа пользователю (viewer response).
Функции Lambda@Edge, помимо этого, могут выполняться перед тем, как CloudFront перенаправит запрос к серверу-источнику (origin request), и после того, как CloudFront получит ответ от сервера-источника (origin response). Вы можете использовать CloudFront Functions и Lambda@Edge вместе в зависимости от того, когда вам необходимо изменить содержимое: до или после кэширования.
Если вам необходимы возможности Lambda@Edge, которые недоступны в CloudFront Functions, например, сетевой доступ или более долгое время выполнения, вы всё так же можете использовать Lambda@Edge до и после кэширования содержимого в CloudFront.
Чтобы помочь вам лучше понять различия между CloudFront Functions и Lambda@Edge, мы создали следующее простое сравнение:
CloudFront Functions | Lambda@Edge | |
Среды выполнения | JavaScript (совместимый с ECMAScript 5.1) |
Node.js, Python |
Место выполнения | 218+ периферийных местоположений CloudFront | 13 периферийных серверов кэширования CloudFront в регионах |
Поддерживаемые триггеры CloudFront | Запрос от пользователя (viewer request) Ответ пользователю (viewer response) |
Запрос от пользователя (viewer request) Ответ пользователю (viewer response) Запрос к источнику (origin request)Ответ от источника (origin response) |
Максимальное время выполнения | Менее 1 миллисекунды | 5 секунд (для триггеров пользователя) 30 секунд (для триггеров источника) |
Максимальный объём памяти | 2 MB | 128 MB (для триггеров пользователя) 10 GB (для триггеров источника) |
Максимальный размер | 10 KB | 1 MB (для триггеров пользователя) 50 MB (для триггеров источника) |
Доступ к сети | Нет | Да |
Доступ к файловой системе | Нет | Да |
Доступ к телу запроса | Нет | Да |
Цена | Доступен бесплатный уровень пользования; оплата за запрос |
Нет бесплатного уровня пользования; оплата за запрос и за время выполнения функции |
Давайте теперь посмотрим, как это работает на практике.
Использование CloudFront Functions из консоли
Я хочу изменять содержимое моего сайта в зависимости от страны пользователя. Для этого я использую раздачу CloudFront, созданную для бакета S3 в качестве источника. Первым делом я создаю политику кэширования, которая добавляет заголовок CloudFront-Viewer-Country
(он содержит двухбуквенное обозначение страны пользователя) в ключ кэширования. CloudFront Functions могут работать с заголовками, созданными CloudFront (такими как заголовки геолокации or заголовки с информацией об устройстве), только если они включены в политику источника или политику ключа кэширования.
В консоли CloudFront я перехожу в раздел Functions в меню слева и нажимаю Create function. Я ввожу название моей функции и нажимаю Continue.
Здесь мы пройдём по следующим шагам создания функции:
- Build: предоставление исходного кода функции.
- Test: проверка функции с помощью образца запроса.
- Publish: перенос функции из стадии разработки в производственную среду.
- Associate: настройка функции для одной или нескольких раздач CloudFront.
1. На вкладке Build я могу получить доступ к коду в двух средах: Development, используемый для тестирования, и Live, используемый одной или несколькими раздачами CloudFront. На вкладке Development я добавляю следующий исходный код и нажимаю Save:
function handler(event) {
var request = event.request;
var supported_countries = ['de', 'it', 'fr'];
if (request.uri.substr(3,1) != '/') {
var headers = request.headers;
var newUri;
if (headers['cloudfront-viewer-country']) {
var countryCode = headers['cloudfront-viewer-country'].value.toLowerCase();
if (supported_countries.includes(countryCode)) {
newUri = '/' + countryCode + request.uri;
}
}
if (newUri === undefined) {
var defaultCountryCode = 'en';
newUri = '/' + defaultCountryCode + request.uri;
}
var response = {
statusCode: 302,
statusDescription: 'Found',
headers: {
"location": { "value": newUri }
}
}
return response;
}
return request;
}
Эта функция проверяет значение заголовка CloudFront-Viewer-Country
, добавленного CloudFront. Если в нём содержится одна из поддерживаемых стран, а URL-адрес ещё не содержит префикс, указывающий на страну, то функция добавляет такой префикс в начало пути. В противном случае функция не изменяет запрос.
2. На вкладке Test, я выбираю тип триггера (Viewer Request), среду (пока что Development) и образец события для тестирования.
Я могу изменить запрос для тестирования в разделе Input: выбрать метод HTTP, а также путь URL и опционально задать IP-адрес клиента. Кроме того, я могу добавить заголовки, файлы cookie и строку запроса. В данном случае я оставляю все значения по умолчанию и добавляю заголовок CloudFront-Viewer-Country
со значением FR
(Франция). Кроме того, вместо использования визуального редактора я могу поменять запрос для тестирования, предоставив его в формате JSON.
Я нажимаю кнопку Test, после чего получаю результат в разделе Output. Как и ожидалось, запрос был перенаправлен (код ответа HTTP 302
). В заголовках ответа (вкладка Response headers) я могу увидеть, что перенаправленный запрос начинается с пути /fr/
, чтобы пользователям из Франции была предоставлена локализованная версия сайта. Если что-то в моих тестах пойдёт не так, я могу посмотреть в раздел Function Logs. Я также могу использовать в коде console.log()
, чтобы вывести дополнительную отладочную информацию.
В разделе Output прямо над кодом ответа HTTP я могу увидеть поле Compute utilization, которое содержит число от 0 до 100: оно показывает время выполнения функции в процентах от максимально разрешённого. В моём случае это значение составило 21: это означает, что функция завершилась за 21% от максимально разрешённого времени.
3. Я запускаю другие тесты для проверки разных наборов URL и заголовков, а потом перехожу на вкладку Publish, чтобы скопировать функцию из среды разработки в производственную среду. После этого она будет готова для настройки в существующей раздаче CloudFront.
4. На вкладке Associate я выбираю раздачу (Distribution), триггер (Event type: Viewer Request или Viewer Response) а также настройки кэша (Cache behavior: в моём случае на раздаче созданы только настройки по умолчанию Default (*)). Затем я нажимаю Add association и подтверждаю добавление в открывшемся диалоговом окне.
После этого я могу увидеть настроенную раздачу для функции в нижней части вкладки Associate.
Чтобы проверить работу функции из двух разных географических местоположений я создал два инстанса Amazon Elastic Compute Cloud (EC2): один в регионе US East (N. Virginia), а другой в регионе Europe (Paris). Я подключаюсь к ним по SSH и использую cURL, чтобы получить необходимый объект из раздачи CloudFront. Перед этим я загрузил два файла в бакет S3, который используется в качестве источника раздачи: один для клиентов из Франции с префиксом fr/
, другой для клиентов из неподдерживаемых стран с префиксом en/
.
Я проверяю, что объекты действительно созданы, с помощью интерфейса командной строки AWS (AWS CLI):
Затем на инстансе в регионе US East (N. Virginia) я выполняю следующую команду, чтобы скачать файл:
Такую же команду я выполняю в регионе Europe (Paris):
Как и ожидалось, хоть я и использовал одинаковый URL, я получил разные результаты. Для того чтобы cURL следовал по полученному перенаправлению, я использовал ключ -L
. В этом случае каждая команда выполняла два HTTP-запроса: первый получал перенаправление от функции CloudFront, а второй – следовал по этому перенаправлению. При этом, во втором случае функция не изменяла запрос, так как в нём уже содержался путь со страной в URL (/en/
или /fr/
).
Чтобы увидеть возвращённое значение перенаправления, а также все заголовки ответа HTTP, я могу использовать cURL с ключом -i
. Ниже приведены заголовки ответа для инстанса, запущенного в США. Функция выполнялась на периферийном местоположении в Вирджинии:
Ниже приведены заголовки ответа для инстанса EC2, расположенного во Франции. В этот раз функция выполнялась на периферийном местоположении рядом с Парижем:
Доступность и стоимость
CloudFront Functions доступны уже сегодня: вы можете использовать их как с новыми, так и с уже существующими раздачами (distributions). Вы можете создавать функции в Консоли управления AWS, с помощью Интерфейса командной строки AWS (AWS CLI), Инструментов для разработки AWS (AWS SDK), а также AWS CloudFormation. В случае CloudFront Functions вы платите за количество вызовов. Вы можете начать их использование без дополнительных затрат с Уровнем бесплатного пользования AWS. Более подробную информацию вы можете узнать на странице цен на Amazon CloudFront.
Используйте CloudFront Functions уже сегодня, чтобы добавить в ваши приложения логику на периферии.