Как ответить
Я бы начал с анализа требований: сколько заказов в секунду, какие гарантии целостности нужны, допустимая задержка. Возможный вариант — разбить систему на три микросервиса: Order, Payment, Inventory. Для транзакций, которые затрагивают несколько сервисов, хорошо подходит паттерн Saga в варианте хореографии. Order создаёт событие OrderCreated, Payment слушает его, списывает деньги, публикует PaymentCompleted, Inventory резервирует товар и публикует InventoryReserved. Если на каком-то шаге ошибка — публикуем компенсирующее событие.
- Каждый сервис имеет свою БД (PostgreSQL). Для коммуникации используем Kafka — это даёт асинхронность и буферизацию при пиках.
- Обработчики событий идемпотентны: храним обработанный ID события в таблице processed_events.
- Компенсации: Payment вызывает refund, Inventory — release. Saga-координатор не нужен — каждый сервис сам решает, что делать при получении события-ошибки.
Пример основной логики (псевдокод на Kotlin):
@Component
class CreateOrderHandler(private val eventBus: EventBus) {
fun handle(command: CreateOrder) {
val order = Order.create(command.userId, command.items, command.total)
repository.save(order)
eventBus.publish(OrderCreated(order.id, order.userId, order.total, command.paymentMethod))
}
}
@Component
class PaymentHandler {
fun on(event: OrderCreated) {
if (!deduplication.isProcessed(event.eventId)) {
val result = paymentGateway.charge(event.userId, event.total)
if (result.isSuccess) {
eventBus.publish(PaymentCompleted(event.orderId))
} else {
eventBus.publish(PaymentFailed(event.orderId, result.error))
}
}
}
}
// Аналогично InventoryHandler с событием InventoryReserved или InventoryReservationFailed
Что даёт такой подход:
- Слабая связанность — сервисы не вызывают друг друга напрямую.
- Масштабирование независимо — каждый сервис может иметь разное количество инстансов.
- При сбое одного сервиса остальные продолжают работать, заказы накапливаются в Kafka.
Из недостатков — сложность отладки и трассировки. Решаем её сквозным correlationId, который прокидывается через все события, и OpenTelemetry для сбора трейсов.