Первоначально опубликовано на Serverless 30 ноября 2016 г.
Уведомления в реальном времени — важный сценарий использования для современных приложений. Например, вам может понадобиться уведомить пользователя о том, что в его социальной ленте появилось еще одно сообщение или что кто-то добавил комментарий к одной из его фотографий.
Но как это сделать бессерверно?
Как правило, вы используете WebSockets и имеете выделенный сервер. Вы устанавливаете постоянную связь между пользователем и сервером и используете схему публикации-подписки для обмена сообщениями. Браузер подписывается на автоматическое получение новых сообщений, не нуждаясь в механизме опроса для постоянной проверки обновлений.
Но если вы собираетесь использовать бессерверный подход, у вас не будет выделенного сервера.
Вместо этого вам понадобится облачный сервис, который решит эту проблему за вас, обеспечив масштабируемость, высокую доступность и оплату за сообщения, а не за час.
Решение: AWS + Serverless Framework
В этой статье я расскажу, как я реализовал систему уведомлений для неаутентифицированных пользователей с помощью Serverless Framework и AWS IoT для браузеров.
Я знаю, что «Интернет вещей» звучит странно для использования на сайте, но он поддерживает WebSockets, очень прост в использовании и, в отличие от Amazon SNS (Simple Notification Service), поддерживает WebSockets. Победа!
Почему IoT?
Я использовал IoT из-за его простой системы обмена сообщениями. Вы создаете «тему» и заставляете пользователей подписаться на нее. Сообщение, отправленное в эту тему, будет автоматически передано всем подписавшимся пользователям. Чаще всего для этого используется система чата.
Если вам нужны приватные сообщения, вам просто нужно создать приватные темы и ограничить доступ к ним. Только один пользователь будет подписан на эту тему, и вы можете заставить свою систему (функции Lambda) отправлять обновления в эту тему для уведомления этого конкретного пользователя.
Демонстрация
Вы можете найти код на GitHub.
Попробуйте здесь: https://serverless-notifications.zanon.dev (откройте две вкладки браузера).
Архитектура
В этом демо я использовал следующую архитектуру.
-
Пользователь делает запрос к Route 53, который настроен на ссылку на S3 bucket.
-
Ведро S3 предоставляет код фронтенда (HTML / CSS / JavaScript / изображения) и код клиента IoT.
-
После загрузки кода фронтенда выполняется Ajax-запрос к шлюзу API для получения временных ключей.
-
Шлюз API перенаправляет запрос для обработки функцией Lambda.
-
Функция Lambda подключается к IAM для принятия роли и создания временных ключей AWS.
-
Код фронтенда подписывается на события IoT, используя временные ключи.
Фронтенд
Эта демонстрация работает на статическом сайте, размещенном на Amazon S3. Поскольку я использовал модуль Node.js для соединения с IoT, в файл index.html добавлен bundle.js, который был обработан с помощью Browserify. Я объясню, как это было сделано, в следующих разделах.
AWS IoT
В этом проекте я использовал Node-модуль AWS IoT SDK для подключения к службе IoT.
Сначала необходимо создать «устройство» (клиентский браузер), предоставив ключи доступа и установив конечную точку IoT, характерную для вашей учетной записи AWS. Позже я покажу, как найти эти данные. После предоставления этих значений устройство попытается подключиться.
Следующий шаг — установка функций обратного вызова для обработки входящих событий. Вам нужно задействовать как минимум функции message (получение сообщений) и connect (подписка на тему после успешного подключения к IoT), но вы также можете обрабатывать следующие события: reconnect, error, offline и close.
Для отправки сообщений используется: client.publish(iotTopic, message).
В папке проекта вы можете найти папку с именем iot. Откройте ее и запустите npm install, а затем node make-bundle для выполнения Browserify и экспорта зависимости bundle.js, которая может работать в браузере.
Код на стороне клиента
На стороне клиента будет использоваться объект IoT, который вы только что создали. За него будут отвечать:
- Ключи доступа к запросу и адрес конечной точки IoT.
Этот запрос будет отправлен на API Gateway и обработан функцией Lambda, которая будет настроена позже.
- Подключение к IoT и подписка на будущие сообщения
- Отправить сообщения
## Бэкэнд
Теперь вам нужно создать свой бэкенд. Использование Serverless Framework облегчит эту задачу, развернув конечную точку шлюза API и вашу функцию Lambda. Функция будет отвечать за создание временных ключей AWS. Однако ей нужна роль, чтобы определить, какой доступ будут предоставлять эти ключи.
Создайте роль IoT
Вы можете создать эту роль с помощью консоли IAM или выполнить файл index.js, который находится в папке create-role, чтобы создать его для вас. Этот пакет использует AWS SDK и требует установки npm перед его выполнением.
Для этой роли необходимо следующее «Доверительное отношение»:
Обратите внимание, что вам нужно заменить строку AWS_ACCOUNT на номер вашего счета. Если вы используете код, который я предоставил, он автоматически получит номер вашего счета с помощью службы STS.
Разрешения будут установлены для функций IoT и для всех ресурсов, что означает, что клиент сможет подписаться на любую тему IoT. При желании вы можете ограничить этот доступ.
Бессерверный фреймворк
Теперь вы создадите функцию Lambda, которая будет генерировать временные ключи (действительные в течение 1 часа) для подключения к IoT-сервису. Здесь вам поможет Serverless Framework. Если он у вас еще не установлен, сделайте это с его помощью:
В serverless.yml необходимо добавить разрешения Lambda для iot:DescribeEndpoint (чтобы найти конечную точку вашей учетной записи) и sts:AssumeRole (чтобы создать временные ключи). Я также создаю простую функцию с именем auth и исключаю другие папки, которые находятся внутри этого проекта, чтобы не застегивать их вместе с моей Lambda.
Функция Lambda довольно проста. Я использую AWS SDK и делаю 3 запроса:
-
iot.describeEndpoint(): найти конечную точку IoT вашего аккаунта (вы можете жестко закодировать этот результат, если хотите)
-
sts.getCallerIdentity(): получить ID вашей учетной записи AWS, который необходим для поиска роли (вы также можете жестко закодировать этот результат)
-
sts.assumeRole(): создайте временные ключи AWS, которые разрешены только для доступа к службе IoT.
Теперь разверните сервис с помощью команды serverless deploy и скопируйте конечную точку API Gateway, которую Serverless Framework вывел в командной строке. Этот адрес будет использоваться в нашем коде фронтенда.
Ценообразование
Сколько это стоит? Всего $5 за миллион сообщений (США). Это может быть довольно дешево в зависимости от вашего масштаба и трафика, потому что вам не нужно платить за выделенный сервер.
Официальная страница с ценами для IoT: https://aws.amazon.com/iot/pricing/.
Улучшение данного демонстрационного образца
В данном примере рассматривается, что существует только одна тема. Это нормально, если все подписаны на один и тот же канал. Однако если вы хотите отправлять приватные уведомления конкретному пользователю, вам нужно создать новую тему для каждого пользователя.
Вы можете модифицировать функцию Lambda для достижения этого ограничения. Когда она вызывает assumeRole, добавьте параметр Policy, который ограничивает доступ данного конкретного пользователя к определенному имени темы. Подробнее об этом параметре здесь.
Если вам нужно предоставить временные ключи для аутентифицированных пользователей (зарегистрированных с помощью Facebook, Twitter, OpenID, Custom и т.д.), я предлагаю вам попробовать Cognito напрямую, а не использовать API Gateway + Lambda.
Что еще?
Я попробовал провести еще один эксперимент и создал демо для бессерверной многопользовательской игры. Если вы хотите разработать HTML5-игру в бессерверной архитектуре, вы можете использовать IoT для обмена сообщениями между игроками и реализовать дешевую многопользовательскую игру. Производительность достаточно хороша для динамичных игр.
Вы можете посмотреть демонстрацию здесь, а код — на GitHub. Вы можете попробовать его с помощью настольного компьютера и телефона, чтобы протестировать функцию многопользовательской игры.
Заключение
IoT также можно использовать для уведомлений в реальном времени в браузере. Уведомления являются распространенным сценарием использования в современных приложениях, и это еще одна проблема, которую можно решить с помощью Serverless.
Первоначально опубликовано на https://www.serverless.com.