Как управлять распределенной транзакцией между несколькими микросервисами?

«Как управлять распределенной транзакцией между несколькими микросервисами?» — вопрос из категории Архитектура, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В микросервисной архитектуре классические двухфазные коммиты (2PC) не подходят из-за требований к доступности и слабой связанности. Основной подход — Паттерн Saga.

Суть: Длинная бизнес-транзакция разбивается на последовательность локальных транзакций в каждом сервисе. Для каждого шага определяется компенсирующее действие (Compensating Transaction), которое откатывает изменения в случае сбоя.

Два стиля координации:

  1. Оркестрация (Orchestration):

    • Центральный координатор (оркестратор) управляет потоком, вызывает сервисы и решает, что делать при ошибке.
    • Пример на C#:
      public class OrderOrchestrator
      {
      public async Task ProcessOrder(Order order)
      {
          try
          {
              await _paymentService.ChargeAsync(order); // Шаг 1
              await _inventoryService.ReserveAsync(order); // Шаг 2
              await _notificationService.SendConfirmationAsync(order); // Шаг 3
          }
          catch (Exception)
          {
              // Компенсация (обратный порядок)
              await _inventoryService.ReleaseAsync(order);
              await _paymentService.RefundAsync(order);
              throw;
          }
      }
      }
  2. Хореография (Choreography):

    • Сервисы общаются через события (через брокер: Kafka, RabbitMQ). Каждый сервис слушает события и выполняет свой шаг, публикуя следующее событие.
    • Пример потока событий: OrderPlaced -> PaymentProcessed -> InventoryReserved. Если сервис инвентаря не может выполнить шаг, он публикует событие InventoryReservationFailed, которое запускает компенсирующие события (PaymentRefunded).

Ключевые компромиссы:

  • Оркестрация проще для контроля и мониторинга, но создает точку централизации.
  • Хореография более распределенная и гибкая, но сложнее в отладке и отслеживании общего состояния процесса.

Инструменты: Для сложных сценариев можно использовать специализированные фреймворки (например, на основе состояния, сохраняемого в БД) или платформы вроде Azure Durable Functions для оркестрации.