Знание шаблонов событийно-ориентированной архитектуры позволяет:
- Создавать слабосвязанные системы, в которых сбой одного компонента не приводит к полному отказу всей системы, а составные части приложения легче масштабировать и модифицировать.
- Эффективно управлять асинхронными операциями и обрабатывать непредсказуемые события в системе.
- Разрабатывать отзывчивые и эффективные приложения, обрабатывающие данные в реальном времени.
- Создавать высоконагруженные системы, в которых требуется быстрая реакция на события.
- Эффективно использовать современные технологии, например потоковую обработку данных и бессерверные вычисления.
Шаблон конкурирующих потребителей
Шаблон конкурирующих потребителей используется для эффективного распределения большого количества асинхронных сообщений между несколькими потребителями.
🚀 Внимание, джедаи кода!
Пришло время освоить силу шаблонов проектирования!
🎮 Обучайтесь, создавая легендарную игру «Звездные войны»!
С 18 по 25 сентября действует космическая акция: -30% на курс «Архитектуры и шаблоны проектирования» по промокоду MIDDLE
.
🔥 Что вас ждет:
- Погружение в мир профессионального проектирования
- Практические навыки на реальном проекте
- Создание собственной игры по мотивам «Звездных войн»
Основные компоненты и принцип работы этого паттерна выглядят так:
Производители сообщений
- Один или несколько производителей отправляют сообщения в очередь.
- Эти сообщения представляют собой задачи, которые нужно выполнить.
Очередь сообщений
- Все сообщения попадают в одну централизованную очередь.
Потребители
- Настраивается несколько экземпляров потребителей.
- Каждый потребитель способен обрабатывать сообщения из очереди.
Конкуренция за сообщения
- Потребители соревнуются друг с другом за получение и обработку сообщений.
- Когда потребитель успешно получает сообщение, оно становится недоступным для других потребителей.
Обработка и удаление
- После обработки сообщения потребитель подтверждает его получение.
- Обработанное сообщение удаляется из очереди.
Ключевой момент в этом шаблоне – необходимость обработки каждого сообщения только одним потребителем. Разные инструменты и платформы решают эту задачу по-своему:
RabbitMQ использует предварительную выборку:
- Потребители устанавливают лимит на количество неподтвержденных сообщений.
- Полученное сообщение учитывается в полете и не доставляется другим потребителям.
Azure Service Bus применяет механизм peek-lock (просмотр и блокировка):
- Потребитель получает сообщение в режиме peek-lock, что блокирует сообщение.
- Сообщение остается в очереди, но становится невидимым для других потребителей.
- После обработки потребитель помечает сообщение как завершенное.
AWS SQS устанавливает тайм-аут видимости:
- При получении сообщения потребителем, SQS устанавливает тайм-аут видимости.
- В течение этого времени сообщение скрыто от других потребителей.
- После обработки потребитель удаляет сообщение.
- Если тайм-аут истекает до удаления, сообщение снова становится видимым для других.
Шаблон повторных попыток сообщений
Шаблон повторных попыток сообщений используется для обработки ошибок при работе с очередями сообщений. Этот шаблон позволяет создать надежную систему обработки транзакций, способную справляться с временными сбоями и обеспечивающую контролируемый процесс для работы с проблемными транзакциями, например, при обработке платежей.
Основные компоненты паттерна и их функции:
- Основная очередь – сюда поступают новые транзакции для обработки.
- Очередь мертвых писем (Dead Letter Queue, DLQ) – отдельная очередь для сообщений, которые не удалось обработать после нескольких попыток.
- Очередь повторных попыток (опционально) – ее можно использовать для планирования повторных попыток с задержкой.
Компоненты шаблона взаимодействуют так:
Потребитель (например, процессор платежей) берет сообщение из основной очереди и пытается обработать транзакцию. Если обработка не удалась:
- Проверяется счетчик попыток (обычно хранится в метаданных сообщения).
- Если счетчик меньше максимального числа попыток, то счетчик увеличивается, а сообщение возвращается в очередь (с задержкой или без).
- Если счетчик больше или равен максимальному числу попыток – сообщение перемещается в DLQ.
Паттерн позволяет использовать 2 стратегии повторных попыток:
- Можно возвращать сообщения напрямую в основную очередь с задержкой.
- Или использовать отдельную очередь повторных попыток с триггером по времени.
Обработка мертвых сообщений DLQ:
- Необходимо мониторить DLQ для сообщений, исчерпавших попытки обработки.
- Реализовать процесс для работы с такими сообщениями (например, ручная обработка).
При реализации этого паттерна стоит следовать следующим лучшим практикам:
- Экспоненциальная задержка – нужно увеличивать интервал между попытками экспоненциально, чтобы не перегружать систему.
- Идемпотентность – необходимо обеспечить безопасность повторной обработки платежа без риска двойного списания.
- Время жизни сообщения – нужно установить общее время жизни для сообщений, чтобы предотвратить обработку очень старых транзакций.
- Лимиты повторных попыток – установить максимальное число попыток обработки.
- Типы ошибок – надо различать временные ошибки (можно повторить) и постоянные ошибки (сразу отправлять в DLQ).
Шаблон асинхронного запроса-ответа
Шаблон асинхронного запроса-ответа позволяет создавать масштабируемые и устойчивые к сбоям системы, где сервисы могут взаимодействовать асинхронно, не блокируя друг друга и сохраняя способность корректно обрабатывать ответы даже при изменении состояния системы между запросом и ответом.
Проблемы, которые решает шаблон:
- В синхронном REST API один экземпляр запрашивающего сервиса всегда связан с одним экземпляром отвечающего сервиса.
- В асинхронной модели экземпляр, отправивший запрос, может быть недоступен к моменту получения ответа.
- Необходимо правильно соотнести запросы и ответы при наличии множества экземпляров сервисов.
Оптимальное решение этих проблем – использование корреляционного ID, уникального идентификатора, который связывает запрос и соответствующий ему ответ. При наличии такого ID организовать процесс работы (на примере показанного выше взаимодействия Сервиса заказов и Платежного сервиса) можно так:
1. Клиент размещает заказ через экземпляр.
2. Сервис заказов:
2.1 Генерирует уникальный корреляционный ID для этого заказа.
2.2. Сохраняет данные заказа и корреляционный ID в базе данных, распределенном кэше или локальной хэш-таблице.
2.3. Отправляет запрос на оплату в очередь запросов вместе с корреляционным ID.
3. Платежный сервис:
3.1 Получает запрос на оплату из очереди.
3.2 Обрабатывает платеж.
3.3. Отправляет ответ в очередь ответов, включая тот же корреляционный ID.
4. Сервис заказов (тот же или другой экземпляр):
4.1. Получает ответ из очереди ответов.
4.2. Использует корреляционный ID для сопоставления ответа с исходным запросом заказа.
4.3. Выполняет необходимые действия (например, подтверждение заказа).
Преимущества использования корреляционного ID:
- Позволяет отправлять несколько запросов на оплату для одного заказа (повторные попытки, частичные платежи и т.д.).
- Разделяет логику маршрутизации и бизнес-контекст (например, ID заказа).
- Облегчает отслеживание потока запроса через несколько сервисов.
Важные аспекты, которые необходимо учесть при реализации шаблона:
- Хранение контекста – надо сохранять информацию о запросе и корреляционном ID.
- Обработка таймаутов – нужно предусмотреть механизм обработки ситуаций, когда ответ не приходит в ожидаемое время.
- Идемпотентность – важно обеспечить корректную обработку повторных ответов.
Есть ли у вас опыт применения этих шаблонов в реальных проектах?
Комментарии