В прошлых лекциях мы познакомились с Event-Driven Architecture (EDA) — событийно-ориентированной архитектурой, её принципами и компонентами. Мы разобрали, как события создают слабую связанность между микросервисами, снижают зависимость и улучшают масштабируемость. Вы узнали, как работают асинхронные коммуникации, изучили концепции издателей (producers) и подписчиков (subscribers), а также поняли, как брокеры сообщений, такие как Kafka, RabbitMQ и ActiveMQ, управляют передачей данных. Также мы обсудили типичные ошибки при внедрении EDA и лучшие практики её проектирования.
Пришло время применить теорию на практике и попробовать спроектировать событийно-ориентированную архитектуру для конкретного кейса.
Практическое проектирование событийно-ориентированной архитектуры
Постановка задачи: кейс "Магазин электронной коммерции"
Представьте, что вам нужно разработать архитектуру событий для интернет-магазина. Как главный архитектор системы, вы сталкиваетесь с такими задачами:
- Обработка заказов, включая уведомления о статусе заказов, оплату, и доставку.
- Автоматическое обновление информации о наличии товаров на складе.
- Отправка уведомлений пользователям о скидках на их любимые товары.
- Логирование всех событий для аналитики (например, для построения отчетов).
Наша цель — использовать событийно-ориентированный подход, чтобы снизить связанность сервисов и повысить отказоустойчивость.
Шаг 1: Определение событий
Первый шаг — понять, какие события происходят в системе. Событие — это некая "новость" о том, что что-то случилось. Например:
| Событие | Описание |
|---|---|
OrderPlaced |
Заказ был создан пользователем |
OrderPaid |
Пользователь оплатил заказ |
OrderShipped |
Заказ отправлен службой доставки |
InventoryUpdated |
Изменилось количество товара на складе |
DiscountCreated |
Создана новая скидка, которая может заинтересовать пользователей |
UserNotificationSent |
Уведомление отправлено пользователю |
Каждое событие имеет свою полезную нагрузку (payload) и метаданные, такие как время создания, идентификатор пользователя и т.д.
Шаг 2: Идентификация издателей и подписчиков
Теперь, когда мы определили события, нужно понять, кто их производит (издатели) и кто на них реагирует (подписчики).
| Событие | Издатель | Подписчики |
|---|---|---|
OrderPlaced |
Order Service | Inventory Service, Payment Service |
OrderPaid |
Payment Service | Shipping Service, Notification Service |
OrderShipped |
Shipping Service | Notification Service |
InventoryUpdated |
Inventory Service | Analytics Service, Notification Service |
DiscountCreated |
Admin Service | Notification Service |
UserNotificationSent |
Notification Service | Analytics Service |
Пример:
- Когда пользователь создаёт заказ,
Order Serviceпубликует событиеOrderPlaced. Это событие обрабатываетсяInventory Service, чтобы уменьшить количество товаров на складе, иPayment Service, чтобы инициировать процесс оплаты.
Шаг 3: Создание схемы взаимодействия
Давайте визуализируем, как услуги обмениваются событиями. Вот схема, показывающая взаимодействие через брокер сообщений (например, Apache Kafka):
User
↓
Order Service ──> OrderPlaced ─┬──> Inventory Service (уменьшить склад)
└──> Payment Service (инициировать оплату)
↓
Payment Service ──> OrderPaid ─┬──> Shipping Service (отправить заказ)
└──> Notification Service (уведомить пользователя)
↓
Shipping Service ──> OrderShipped → Notification Service
Шаг 4: Определение структуры событий
События должны содержать полезную информацию для подписчиков.
Пример структуры события OrderPlaced:
{
"eventId": "12345",
"eventType": "OrderPlaced",
"timestamp": "2023-10-01T12:34:56Z",
"payload": {
"orderId": "7890",
"userId": "456",
"orderItems": [
{
"productId": "101",
"quantity": 2
},
{
"productId": "202",
"quantity": 1
}
],
"totalPrice": 159.99
}
}
Подобные структуры помогут унифицировать обработку событий, ведь подписчики всегда знают, чего ожидать.
Шаг 5: Моделирование брокера сообщений
Для реализации архитектуры мы будем использовать Apache Kafka. Каждое событие будет публиковаться в свой топик.
| Топик | Тип события | Примеры сообщений |
|---|---|---|
orders |
OrderPlaced |
Данные о созданных заказах |
payments |
OrderPaid |
Данные об успешных оплатах |
shipping |
OrderShipped |
Данные об отправленных заказах |
inventory |
InventoryUpdated |
Данные об изменении остатков на складе |
notifications |
UserNotificationSent |
Данные об отправленных уведомлениях |
Упражнение: реализация продюсера и консьюмера для события OrderPlaced
Реализация продюсера:
// Producer для отправки события OrderPlaced в Kafka
@Component
public class OrderEventProducer {
private final KafkaTemplate<String, String> kafkaTemplate;
public OrderEventProducer(KafkaTemplate<String, String> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public void sendOrderPlacedEvent(String orderId, String eventPayload) {
kafkaTemplate.send("orders", orderId, eventPayload);
System.out.println("Событие OrderPlaced отправлено: " + eventPayload);
}
}
Реализация подписчика:
// Consumer для обработки события OrderPlaced
@Component
@KafkaListener(topics = "orders", groupId = "inventory-service")
public class OrderEventConsumer {
@Autowired
private InventoryService inventoryService;
@KafkaHandler
public void handleOrderPlacedEvent(String message) {
System.out.println("Получено событие OrderPlaced: " + message);
inventoryService.updateInventory(message);
}
}
Советы по проектированию событийно-ориентированной архитектуры
- Минимизируйте зависимости. Каждый сервис должен быть максимально изолирован. Например,
Notification Serviceне должен знать внутреннюю логикуOrder Service. - Логируйте события. Это поможет отследить, что происходит в системе, особенно в асинхронной обработке.
- Идентифицируйте схемы событий. Используйте JSON Schema, чтобы все события следовали чёткому формату.
- Обеспечьте согласованность. Если событие не обработано, его можно повторить благодаря Kafka's "At least once".
Заключительное упражнение
Для закрепления знаний спроектируйте событийно-ориентированную архитектуру для системы бронирования авиабилетов. Определите ключевые события (FlightBooked, PaymentProcessed, TicketIssued), их издателей и подписчиков. Опишите взаимодействие сервисов и создайте схему событий.
Вот и всё! Теперь вы практическим путём освоили основы проектирования событийно-ориентированной архитектуры. Впереди — ещё больше EDA и асинхронной магии.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ