Вопрос 2 · Раздел 17

В чём разница между хореографией и оркестрацией в Saga

// Чем оркестратор отличается от обычного метода: // 1. Персистит состояние (переживает рестарты) // 2. Обрабатывает асинхронные события // 3. Имеет built-in retry и compensation

Версии по языкам: English Russian Ukrainian

🟢 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».

Типичные ошибки

  1. Циклические зависимости в хореографии:
    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. Какие инструменты используются для оркестрации микросервисов]]