В чём разница между хореографией и оркестрацией в Saga
// Чем оркестратор отличается от обычного метода: // 1. Персистит состояние (переживает рестарты) // 2. Обрабатывает асинхронные события // 3. Имеет built-in retry и compensation
🟢 Junior Level
Хореография и оркестрация — два способа реализации паттерна Saga.
Хореография — нет центрального управляющего. Каждый сервис слушает события других сервисов и реагирует.
Оркестрация — есть центральный оркестратор, который говорит каждому сервису что делать.
// Чем оркестратор отличается от обычного метода: // 1. Персистит состояние (переживает рестарты) // 2. Обрабатывает асинхронные события // 3. Имеет built-in retry и compensation
Хореография:
Order Service → "OrderCreated" → Payment Service → "PaymentDone" → Shipping Service
Оркестрация:
Orchestrator
/ | \
Order Payment Shipping
↓ ↓ ↓
"создай" "оплати" "отправь"
🟡 Middle Level
Хореография — Event-driven
// Order Service
@EventListener
public void on(OrderCreatedEvent event) {
paymentService.reserve(event.orderId());
eventPublisher.publish(new PaymentReservedEvent(event.orderId()));
}
// Payment Service
@EventListener
public void on(PaymentReservedEvent event) {
shippingService.ship(event.orderId());
eventPublisher.publish(new ShippingCompletedEvent(event.orderId()));
}
// Компенсация
@EventListener
public void on(PaymentFailedEvent event) {
orderService.cancel(event.orderId());
eventPublisher.publish(new OrderCancelledEvent(event.orderId()));
}
Оркестрация — Central coordinator
@Component
public class OrderOrchestrator {
public void processOrder(Order order) {
try {
orderService.create(order);
paymentService.charge(order);
inventoryService.reserve(order);
shippingService.ship(order);
} catch (PaymentException e) {
orderService.cancel(order);
// throw e — исключение поднимается до HTTP-контроллера,
// который возвращает клиенту 500 с описанием ошибки компенсации.
throw e;
} catch (InventoryException e) {
paymentService.refund(order);
orderService.cancel(order);
// throw e — исключение поднимается до HTTP-контроллера,
// который возвращает клиенту 500 с описанием ошибки компенсации.
throw e;
}
}
}
Сравнение
| Хореография | Оркестрация |
|---|---|
| Без центрального контроля | Центральный оркестратор |
| Event-driven | Command-driven |
| Сложно отследить поток | Легко понять поток |
| Циклические зависимости | Нет циклических зависимостей |
| При 2-3 сервисах поток событий ещё можно держать в голове. | При 5+ сервисах связи растут квадратично, и без оркестратора невозможно понять, кто кого вызывает. |
Event-driven = сервисы реагируют на события (кто-то опубликовал факт). Command-driven = оркестратор явно говорит каждому сервису «сделай X».
Типичные ошибки
- Циклические зависимости в хореографии:
Service A → событие → Service B → событие → Service A → бесконечный цикл!
🔴 Senior Level
Архитектурные Trade-offs
Хореография:
Плюсы:
- Нет single point of failure
- Слабая связанность сервисов
- Естественный event-driven стиль
Минусы:
- Сложно дебажить (поток неочевиден)
- Риск циклических зависимостей
- Трудно добавить новый шаг
- Нет единого места для мониторинга
Оркестрация:
Плюсы:
- Чёткий поток выполнения
- Легко добавить шаг
- Централизованный мониторинг
- Нет циклических зависимостей
Минусы:
- Оркестратор — bottleneck
- Оркестратор — single point of failure
- Оркестратор знает слишком много о других сервисах
Production Experience
Когда выбрать хореографию:
- 2-3 сервиса
- Простая логика
- Уже есть event-driven инфраструктура
- Нужна максимальная отказоустойчивость
Когда выбрать оркестрацию:
- 5+ сервисов
- Сложная логика с условиями
- Нужен мониторинг и tracing
- Команды разные для каждого сервиса
Real-world orchestrator (Axon Framework):
@Saga
public class OrderSaga {
@Autowired
private transient CommandGateway commandGateway;
@StartSaga
@SagaEventHandler(associationProperty = "orderId")
public void handle(OrderCreatedEvent event) {
commandGateway.send(new ReserveInventoryCommand(event.getOrderId()));
}
@SagaEventHandler(associationProperty = "orderId")
public void handle(InventoryReservedEvent event) {
commandGateway.send(new ProcessPaymentCommand(event.getOrderId()));
}
@SagaEventHandler(associationProperty = "orderId")
public void handle(PaymentCompletedEvent event) {
commandGateway.send(new CompleteOrderCommand(event.getOrderId()));
end();
}
@SagaEventHandler(associationProperty = "orderId")
public void handle(PaymentFailedEvent event) {
commandGateway.send(new CancelOrderCommand(event.getOrderId()));
end();
}
}
Best Practices
✅ Хореография для простых Saga (2-3 шага)
✅ Оркестрация для сложных Saga (5+ шагов)
✅ Мониторьте Saga в обоих подходах
✅ Реализуйте idempotency
❌ Не смешивайте подходы в одной Saga
❌ Не создавайте циклические зависимости в хореографии
❌ Не делайте оркестратор слишком "умным"
🎯 Шпаргалка для интервью
Обязательно знать:
- Хореография — event-driven, без центрального контроля, сервисы реагируют на события
- Оркестрация — command-driven, центральный координатор управляет потоком
- Хореография: нет SPOF, но сложно дебажить, риск циклических зависимостей
- Оркестрация: чёткий поток, легко мониторить, но оркестратор — bottleneck
- Хореография для простых Saga (2-3 шага), оркестрация для сложных (5+)
- В хореографии каждый сервис знает только о соседях, в оркестрации — оркестратор знает обо всех
- Оба подхода требуют idempotency и компенсаций
Частые уточняющие вопросы:
- Как избежать циклических зависимостей в хореографии? Проектировать направленный граф событий, использовать оркестрацию при сложной логике.
- Что если оркестратор упал? Персистит состояние — после перезапуска продолжает с места сбоя.
- Можно ли комбинировать подходы? Не в одной Saga, но разные Saga в системе могут использовать разные подходы.
- Как тестировать оркестратор? Unit-тесты логики + интеграционные тесты с мокнутыми сервисами.
Красные флаги (НЕ говорить):
- “Хореография проще для 10 сервисов” — нет, поток станет нечитаемым
- “Оркестратор не может упасть” — может, нужна персистентность состояния
- “В хореографии нет coupling” — есть, через события
- “Оркестратор = антипаттерн, нарушает loose coupling” — это trade-off, а не абсолют
Связанные темы:
- [[1. Что такое паттерн Saga и когда его использовать]]
- [[3. Как реализовать распределённые транзакции в микросервисах]]
- [[4. Что такое компенсирующие транзакции]]
- [[15. Как организовать коммуникацию между микросервисами]]
- [[26. Какие инструменты используются для оркестрации микросервисов]]