Блог Amazon Web Services
Выбор сервисов сообщений для бессерверных приложений
Оригинал статьи: ссылка (James Beswick, Senior Developer Advocate, AWS Serverless Team) часть 1 (текущая), часть 2, часть 3
Большинство бессерверных приложений в своей архитектуре используют комбинацию сервисов AWS, микро-сервисов и функций AWS Lambda. Сервисы сообщений являются ключевыми для большинства бессерверных приложений, работающих в производственной среде, обеспечивая возможность для взаимодействия распределённых приложений друг с другом.
Сервисы сообщений помогают улучшить отказоустойчивость, доступность и масштабируемость приложений при правильном использовании. Они также позволяют приложениям взаимодействовать за пределами ваших рабочих нагрузок и даже за пределами AWS Cloud и облегчают добавление нового функционала в ваши приложения и выпуск новых версий ваших сервисов.
В этой статье я сравню функционал основных сервисов сообщений, предлагаемых AWS, и покажу, как вы можете использовать их в бессерверных архитектурах. Также я покажу, как можно развернуть и использовать эти интеграции с помощью AWS Serverless Application Model (AWS SAM).
Примеры кода, используемые в данной статье, вы сможете найти и загрузить из репозитория GitHub. Файл README.md содержит инструкции по запуску и развёртыванию каждого из примеров кода.
Обзор
Три наиболее полезные паттерна обмена сообщениями, используемые разработчиками бессерверных приложений, – это очереди, модель «издатель – подписчик» (Pub/Sub) и шина событий. В AWS, эти паттерны реализованы в соответствующих сервисах: Amazon SQS, Amazon SNS и Amazon EventBridge. Все эти сервисы являются полностью управляемыми и высоко-доступными, без необходимости управлять базовой инфраструктурой. Также все три могут интегрироваться с AWS Lambda, позволяя отправлять сообщения посредством AWS SDK и вызывать функции в качестве обработчиков сообщений. Каждый из этих сервисов играет важную роль в бессерверных архитектурах.
SNS позволяет надёжно обмениваться сообщениями между частями вашей инфраструктуры. Этот сервис использует надёжный механизм повторения отправки сообщений, когда конечные сервисы, куда отправляется сообщение, недоступны. В случае исчерпания максимального количества повторений отправки, заданного в политике, сервис может отправить эти сообщения в dead-letter queue для дальнейшей обработки. SNS использует топики для логического разделения сообщений на каналы отправки, и Lambda функция взаимодействует с топиками для обработки сообщений.
SQS предоставляет функционал очередей для бессерверных приложений. Вы можете использовать очередь для отправки, хранения, и получения сообщений между разными сервисами в вашем приложении. Очереди являются важным механизмом обеспечения отказоустойчивости в распределённых системах и позволяют разделять функционал различных частей вашего приложения. SQS эластично масштабируется и не имеет ограничения на количество сообщений в очереди. Сервис гарантированно сохраняет сообщения до тех пор, пока они не будут обработаны конечным потребителем.
EventBridge – это бессерверная шина событий, упрощающая перенаправление сообщений между сервисами AWS, SaaS-провайдерами и вашими приложениями. EventBridge даёт возможность логически разделять потоки данных на основе шин событий, и позволяет задавать правила пересылки. Вы можете фильтровать и преобразовывать входящие сообщения на уровне сервиса, без дополнительного кода, а также доставлять события к различным целевым адресатам, включающим Lambda-функции.
Интеграция SQS очередей с помощью AWS SAM
Первый пример демонстрирует шаблон AWS SAM, определяющий бессерверное приложение с двумя Lambda-функциями и очередью SQS:
Вы определяете очередь SQS в шаблоне AWS SAM ресурсом AWS::SQS::Queue:
MySqsQueue:
Type: AWS::SQS::Queue
Для публикации сообщений в очередь функция-отправитель должна иметь права доступа на отправку сообщений. Используя шаблон AWS SAM для политики безопасности, вы можете применить политику, которая позволяет отправку сообщений в определенную очередь:
Policies:
- SQSSendMessagePolicy:
QueueName: !GetAtt MySqsQueue.QueueName
Шаблон AWS SAM передаёт имя очереди в Lambda-функцию через переменную окружения. Функция использует метод sendMessage класса AWS.SQS для публикации сообщения:
const AWS = require('aws-sdk')
AWS.config.region = process.env.AWS_REGION
const sqs = new AWS.SQS({apiVersion: '2012-11-05'})
// The Lambda handler
exports.handler = async (event) => {
// Params object for SQS
const params = {
MessageBody: `Message at ${Date()}`,
QueueUrl: process.env.SQSqueueName
}
// Send to SQS
const result = await sqs.sendMessage(params).promise()
console.log(result)
}
Когда очередь SQS получает сообщение, она отправляет его в Lambda-функцию «получателя». Для настройки такой интеграции в AWS SAM, функции-получателю назначаются права доступа SQSPollerPolicy. Источник событий для функции настроен на получение сообщений из очереди порциями по 10 штук:
QueueConsumerFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: code/
Handler: consumer.handler
Runtime: nodejs12.x
Timeout: 3
MemorySize: 128
Policies:
- SQSPollerPolicy:
QueueName: !GetAtt MySqsQueue.QueueName
Events:
MySQSEvent:
Type: SQS
Properties:
Queue: !GetAtt MySqsQueue.Arn
BatchSize: 10
Сообщение из SQS передается на вход функции-получателя в качестве данных для обработки. Эти данные представляют собой массив сообщений размером до максимального настроенного «пакета» сообщений. Он содержит атрибут body со значением поля MessageBody, которое было установлено функцией-отправителем. Вы можете увидеть значения этих атрибутов в логе CloudWatch для функции:
Интеграция топиков SNS с помощью AWS SAM
Второй пример демонстрирует шаблон AWS SAM, определяющий бессерверное приложение с тремя Lambda-функциями и топиком SNS:
Вы можете определить SNS-топик и подписанные на него Lambda-функции в ресурсе AWS::SNS::Topic:
MySnsTopic:
Type: AWS::SNS::Topic
Properties:
Subscription:
- Protocol: lambda
Endpoint: !GetAtt TopicConsumerFunction1.Arn
- Protocol: lambda
Endpoint: !GetAtt TopicConsumerFunction2.Arn
Для обеспечения необходимых прав для сервиса SNS нужно определить AWS::Lambda::Permission для каждой из подписанных на топик функций:
TopicConsumerFunction1Permission:
Type: 'AWS::Lambda::Permission'
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !Ref TopicConsumerFunction1
Principal: sns.amazonaws.com
Шаблон политики безопасности SNSPublishMessagePolicy предоставляет права на отправку сообщений в топик для функции-отправителя. В Lambda-функции, метод publish в классе AWS.SNS управляет публикацией сообщения:
const AWS = require('aws-sdk')
AWS.config.region = process.env.AWS_REGION
const sns = new AWS.SNS({apiVersion: '2012-11-05'})
// The Lambda handler
exports.handler = async (event) => {
// Params object for SNS
const params = {
Message: `Message at ${Date()}`,
Subject: 'New message from publisher',
TopicArn: process.env.SNStopic
}
// Send to SQS
const result = await sns.publish(params).promise()
console.log(result)
}
Сообщение из SNS передается на вход функции-получателя в качестве данных для обработки. Это массив сообщений, содержащих атрибуты subject и message, полученные из функции-отправителя. Вы можете увидеть значения этих атрибутов в логе функции в CloudWatch:
Различия в конфигурации между SQS и SNS
SQS-очереди и SNS-топики имеют разную функциональность, но оба сервиса могут публиковать сообщения в результирующие Lambda-функции.
Сообщения в SQS хранятся в очереди до 14 дней или пока не будут успешно обработаны подписчиком.
SNS не сохраняет сообщения, если отсутствуют подписчики на топик. В такой ситуации пришедшее сообщение будет отброшено.
SNS-топики могут рассылать сообщения многочисленным целевым адресатам, это называется fan-out. Вы можете использовать этот подход для распараллеливания обработки сообщений по нескольким Lambda-функциям или отсылать сообщения в несколько целевых сред (например, тестовую среду или среду разработки). SNS-топик может иметь до 12,5 миллионов подписчиков, обеспечивая высоко-масштабируемые возможности по рассылке сообщений. Целевыми адресатами могут быть конечные точки HTTP/S, текстовые сообщения SMS, мобильные уведомления SNS, емейлы, SQS и Lambda-функции.
В шаблонах AWS SAM вы можете получить свойства очередей и топиков, такие как ARN и имена, используя следующие встроенные функции:
Amazon SQS | Amazon SNS | |
Тип канала | Очередь | Топик |
Получение ARN | !GetAtt MySqsQueue.Arn | !Ref MySnsTopic |
Получение имени | !GetAtt MySqsQueue.QueueName | !GetAtt MySnsTopic.TopicName |
Интеграция EventBridge с помощью AWS SAM
Третий пример демонстрирует шаблон AWS SAM, определяющий бессерверное приложение с двумя Lambda-функциями и правилом EventBridge:
В каждом аккаунте AWS уже существует шина сообщений «по умолчанию». Для определения правила фильтрации сообщений в шине событий используйте ресурс AWS::Events::Rule:
EventRule:
Type: AWS::Events::Rule
Properties:
Description: "EventRule"
EventPattern:
source:
- "demo.event"
detail:
state:
- "new"
State: "ENABLED"
Targets:
- Arn: !GetAtt EventConsumerFunction.Arn
Id: "ConsumerTarget"
Правило описывает паттерн сообщения посредством определения совпадающих атрибутов JSON. Сообщение, совпавшее с паттерном в правиле, будет перенаправлено в список целевых адресатов. Для работы сервиса EventBridge нужно предоставить права для вызова Lambda-функций из списка целевых адресатов:
PermissionForEventsToInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Ref: "EventConsumerFunction"
Action: "lambda:InvokeFunction"
Principal: "events.amazonaws.com"
SourceArn: !GetAtt EventRule.Arn
Шаблон AWS SAM использует права доступа IAM для предоставления привилегий функции-отправителю на отправку сообщений в шину событий:
EventPublisherFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: code/
Handler: publisher.handler
Timeout: 3
Runtime: nodejs12.x
Policies:
- Statement:
- Effect: Allow
Resource: '*'
Action:
- events:PutEvents
Функция-отправитель использует метод putEvents класса AWS.EventBridge, который возвращает результат после гарантированного сохранения сообщения в EventBridge:
const AWS = require('aws-sdk')
AWS.config.update({region: 'us-east-1'})
const eventbridge = new AWS.EventBridge()
exports.handler = async (event) => {
const params = {
Entries: [
{
Detail: JSON.stringify({
"message": "Hello from publisher",
"state": "new"
}),
DetailType: 'Message',
EventBusName: 'default',
Source: 'demo.event',
Time: new Date
}
]
}
const result = await eventbridge.putEvents(params).promise()
console.log(result)
}
Сообщение из EventBridge передаётся на вход функции-получателя в качестве данных для обработки. Это массив сообщений, содержащих атрибуты subject и message, полученные из функции-отправителя. Вы можете увидеть значения этих атрибутов в логе CloudWatch для функции:
Сравнение SNS с EventBridge
SNS и EventBridge очень похожи. Оба сервиса могут использоваться для разделения издателей и подписчиков сообщений, позволяют фильтровать сообщения или события и предоставляют возможности по массовой рассылке или приёму сообщений. Но существуют отличия в поддерживаемом списке адресатов и функционале каждого из сервисов, и выбор конкретного сервиса зависит от ваших задач.
EventBridge предлагает две новых возможности, которые недоступны в SNS.
Первая – это интеграция с SaaS-провайдерами, которая позволяет вам авторизовать SaaS-провайдеров для отправки сообщений из их шины сообщений EventBridge в партнёрские шины сообщений в вашем аккаунте AWS. Таким образом, больше нет необходимости настраивать webhook или механизмы опросов на изменения (polling). Это обеспечивает высоко-масштабируемый способ загружать SaaS-сообщения напрямую в ваш аккаунт AWS.
Вторая – это Schema Registry, позволяющая обнаруживать и управлять схемами OpenAPI для событий. EventBridge может определять схему на основе прошедших через него событий, используя механизм обнаружения схем (schema discovery). Этот механизм может быть использован для генерации привязок кода (code bindings) напрямую в ваше IDE для типобезопасных языков, таких как Python, Java и TypeScript. Это, в свою очередь, помогает ускорять процесс разработки и автоматизировать генерацию классов и кода на основе обрабатываемых событий.
Таблица сравнивает основной функционал обоих сервисов:
Amazon SNS | Amazon EventBridge | |
Количество целевых адресатов | 10 миллионов (soft) | 5 адресатов на правило |
SLA доступности | 99,9% | 99,99% |
Сервисные лимиты | 100 тысяч топиков. 12,5 миллионов подписок на топик. |
100 шин сообщений. 300 правил на шину сообщений. |
Пропускная способность отправки сообщений | Зависит от Региона. Регулируемая квота. | Зависит от Региона. Регулируемая квота. |
Преобразование входных данных | Нет | Да – смотрите детали. |
Фильтрация сообщений | Да – смотрите детали. | Да, включая совпадение по IP-адресам – смотрите детали. |
Максимальный размер сообщения | 256 KB | 256 KB |
Оплата | за 64 KB | за 64 KB |
Формат | Raw или JSON | JSON |
Получение сообщений от AWS CloudTrail | Нет | Да |
Адресаты | HTTP(S), SMS, SNS Mobile Push, Email/Email-JSON, SQS, Lambda-функции. | 17 адресатов, включая AWS Lambda, Amazon SQS, Amazon SNS, AWS Step Functions, Amazon Kinesis Data Streams, Amazon Kinesis Data Firehose, точки доступа REST API в API Gateway и кластеры Amazon Redshift. |
Интеграция с SaaS-провайдерами | Нет | Да – смотрите список интеграций. |
Интеграция с Schema Registry | Нет | Да – смотрите детали. |
Поддержка dead-letter queues | Да | Да |
FIFO порядок сообщений | Да – смотрите детали. | Нет |
Публичная доступность | Можно создавать публичные топики | Нет |
Ценообразование | $0.50/миллион запросов + цена за доставку (варьируется) + цена за отправку данных в Интернет (data transfer out). Цена за SMS варьируется. | $1.00/миллион сообщений. Бесплатно для сообщений AWS. Нет цены за доставку. |
Размер сообщения, за который происходит оплата | 1 сообщение = 64 KB | 1 сообщение = 64 KB |
Уровень бесплатного пользования AWS | Да | Нет |
Межрегиональное взаимодействие | Можно подписать Lambda функцию на топик Amazon SNS из любого Региона. | Адресаты должны быть в том же Регионе. Можно отправлять сообщения между Регионами в другие шины сообщений. |
Политика повтора отправки |
|
«Хотя-бы-один-раз» (at-least-once) доставка сообщения адресатам, включая повторения с экспоненциальной политикой до 24 часов. |
Выводы
Сервисы сообщений являются важной частью бессерверных приложений, и AWS предоставляет возможность использования очередей, модели «издатель – подписчик» (Pub/Sub) и шины событий. Этот пост рассматривает основной функционал сервисов SNS, SQS и EventBridge, и как они позволяют решать задачи для ваших приложений.
Я показал три примера приложений, которые отправляют и получают сообщения из трёх сервисов сообщений. Мы рассмотрели примеры кода AWS SAM для развёртывания этих ресурсов в ваших приложениях.
И, наконец, мы сравнили сервисы сообщений между собой.
Чтобы узнать больше о разделённых (decoupled) архитектурах, смотрите серию обучающих матералов по EventBridge. Чтобы ознакомиться с обучающими материалами по бессерверным технологиям, смотрите https://serverlessland.com.