У чому різниця між хореографією та оркестрацією в 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. Які інструменти використовуються для оркестрації мікросервісів]]