Распределенная транзакция в микросервисах - это последовательность локальных операций, каждая из которых обновляет данные в своем сервисе и публикует событие для запуска следующего шага. Проблема: нет общей базы данных, ACID-гарантии недоступны, а частичный отказ одного сервиса оставляет систему в несогласованном состоянии. Решение - маршрутизация процессов через шаблоны Saga, CQRS и Event Sourcing, усиленная инфраструктурными слоями API Gateway и Service Mesh.
По данным опроса O'Reilly 2025 года, 85% организаций уже используют микросервисы в production. При этом 63% команд называют управление распределенными транзакциями главной архитектурной болью. Эта статья - практический каркас для DevOps-инженера и архитектора: разберем, как выбрать и собрать шаблоны маршрутизации, чтобы система выдерживала частичные отказы и сохраняла согласованность данных.
Почему маршрутизация процессов - ключевая задача в микросервисах
Монолит обрабатывает сквозной бизнес-процесс внутри одного процесса. Транзакция охватывает несколько таблиц, и ACID-менеджер базы данных гарантирует атомарность. В микросервисах каждый сервис владеет своей базой. Бизнес-операция, например «оформить заказ», распределяется между сервисами Заказ, Платеж и Склад. Сетевые задержки, таймауты и отказы отдельных узлов становятся нормой.
Без явной маршрутизации процессов возникают три проблемы:
- Частичные отказы. Платеж списан, но склад не получил команду резервирования - заказ завис.
- Несогласованность данных. Каждый сервис видит свой срез реальности. Клиент видит «оплачено», склад - «не зарезервировано».
- Сложность отладки. Трассировка запроса через десяток сервисов без централизованного контекста требует часов ручного разбора логов.
Маршрутизация процессов решает эти проблемы через набор шаблонов. Saga управляет распределенными транзакциями через компенсирующие действия. CQRS разделяет модели чтения и записи, оптимизируя нагрузку. Event Sourcing сохраняет каждое изменение как событие, давая полный аудит и возможность пересобрать состояние. API Gateway и Service Mesh берут на себя сетевую координацию: обнаружение сервисов, повторные попытки, обрыв цепи.
Если вы проектируете миграцию с монолита, изучите пошаговый план перехода на микросервисы. Для понимания основ масштабирования и выбора архитектурного стиля используйте сравнительную таблицу паттернов масштабирования.
Шаблон Saga: управление распределенными транзакциями
Saga заменяет одну ACID-транзакцию цепочкой локальных транзакций. Каждая локальная транзакция обновляет данные в своем сервисе и публикует событие или команду для следующего шага. При отказе на любом этапе Saga выполняет компенсирующие транзакции - откатывает уже выполненные шаги. Два способа координации: хореография и оркестрация.
Хореография: децентрализованная координация через события
В хореографии нет центрального координатора. Сервисы обмениваются событиями через брокер сообщений. Каждый сервис слушает события, выполняет свою часть работы и публикует результат как новое событие.
Сценарий: оформление заказа. Сервис Заказ создает заказ в статусе PENDING и публикует событие OrderCreated. Сервис Платеж слушает OrderCreated, списывает средства и публикует PaymentCompleted. Сервис Склад слушает PaymentCompleted, резервирует товар и публикует InventoryReserved. При отказе Платежа публикуется PaymentFailed, и сервис Заказ отменяет заказ.
// Сервис Заказ: обработка события PaymentFailed
@KafkaListener(topics = "payment-events")
public void handlePaymentFailed(PaymentFailedEvent event) {
Order order = orderRepository.findById(event.getOrderId());
order.setStatus(OrderStatus.CANCELLED);
orderRepository.save(order);
// Публикация события для уведомления клиента
eventPublisher.publish(new OrderCancelledEvent(order.getId()));
}
Плюсы хореографии: слабая связанность сервисов, простота добавления новых участников - они просто подписываются на события. Минусы: поток управления размазан по подпискам, сложно отследить текущий шаг процесса. Циклические зависимости между событиями могут образоваться незаметно. При 5+ сервисах отладка превращается в раскопки логов.
Оркестрация: централизованное управление процессом
Оркестратор - отдельный сервис, который явно вызывает каждый шаг Saga и обрабатывает ответы. Он знает всю последовательность и принимает решение о компенсации при отказе.
Тот же сценарий с оркестратором. Сервис SagaOrchestrator получает команду «создать заказ». Он вызывает сервис Заказ, получает orderId, затем вызывает сервис Платеж с orderId. Если платеж отклонен, оркестратор вызывает компенсирующий метод сервиса Заказ - отмену заказа.
// Оркестратор на Camunda BPMN
@Component
public class OrderSagaOrchestrator {
@Autowired
private OrderService orderService;
@Autowired
private PaymentService paymentService;
@Autowired
private InventoryService inventoryService;
public void executeOrder(OrderRequest request) {
try {
Long orderId = orderService.createOrder(request);
paymentService.processPayment(orderId, request.getAmount());
inventoryService.reserveItems(orderId, request.getItems());
orderService.completeOrder(orderId);
} catch (PaymentFailedException e) {
orderService.cancelOrder(e.getOrderId());
throw e;
} catch (InventoryException e) {
paymentService.refundPayment(e.getOrderId());
orderService.cancelOrder(e.getOrderId());
throw e;
}
}
}
Плюсы оркестрации: явный поток управления в одном месте, простая отладка и мониторинг состояния процесса. Минусы: оркестратор становится единой точкой отказа, увеличивается связанность - оркестратор знает API всех участников.
Критерий выбора: хореография - для простых линейных процессов с 2-3 сервисами. Оркестрация - для сложных ветвящихся процессов с условными переходами и таймаутами. На практике часто комбинируют: оркестратор управляет высокоуровневым потоком, а внутри шага сервисы обмениваются событиями.
Детали настройки брокера сообщений для Saga, включая идемпотентность и гарантии доставки, разобраны в руководстве по брокерам сообщений в микросервисах.
CQRS и Event Sourcing: разделение ответственности и хранение событий
CQRS (Command Query Responsibility Segregation) разделяет модель на две: команды изменяют состояние, запросы читают его. Event Sourcing хранит не текущее состояние, а последовательность событий, которые к нему привели. Вместе они решают проблемы производительности чтения и аудита в микросервисах.
Когда использовать CQRS: практические критерии
CQRS не нужен в простых CRUD-системах. Признаки, что пора внедрять:
- Асимметрия нагрузки. Чтений в 10-100 раз больше записей. Модель, оптимизированная под запись, тормозит чтение.
- Сложные запросы. Агрегации, JOIN по нескольким сервисам, полнотекстовый поиск. Реляционная БД не справляется, нужна денормализованная проекция.
- Разные требования к консистентности. Запись требует строгой согласованности, чтение допускает eventual consistency с задержкой в несколько секунд.
Пример: в системе заказов команда CreateOrder пишет в PostgreSQL, оптимизированный под транзакции. Запрос «активные заказы клиента за месяц с детализацией по товарам» читает из MongoDB, где данные уже агрегированы. Проекция обновляется асинхронно через события.
Event Sourcing: построение аудита и восстановление состояния
В Event Sourcing источником истины становится журнал событий. Текущее состояние - производная от воспроизведения всех событий с начала. Это дает полный аудит: вы видите не только что счет равен 1000 рублей, но и все операции, которые к этому привели - пополнения, списания, возвраты.
Сценарий: аудит заказа. Сервис Заказ хранит события OrderCreated, ItemAdded, PaymentApplied, OrderShipped. Чтобы узнать текущий статус, сервис загружает все события заказа и воспроизводит их. Для ускорения периодически создается снапшот состояния, и новые события применяются к нему.
// Восстановление агрегата из событий с EventStoreDB
@EventSourcingAggregate
public class OrderAggregate {
private OrderStatus status;
private List<OrderItem> items = new ArrayList<>();
@CommandHandler
public void handle(CreateOrderCommand cmd) {
apply(new OrderCreatedEvent(cmd.getOrderId(), cmd.getCustomerId()));
}
@EventSourcingHandler
public void on(OrderCreatedEvent event) {
this.status = OrderStatus.CREATED;
}
@EventSourcingHandler
public void on(ItemAddedEvent event) {
this.items.add(new OrderItem(event.getProductId(), event.getQuantity()));
}
}
Event Sourcing и CQRS дополняют друг друга. События из журнала проецируются в читаемые модели: одна проекция для UI заказов, другая для аналитики продаж, третья для рекомендательной системы. Каждая проекция оптимизирована под свой запрос и обновляется асинхронно.
Цена внедрения: eventual consistency между командной и читаемой моделью. Пользователь может не увидеть свой заказ сразу после создания - задержка зависит от скорости обработки событий проекцией. Для большинства бизнес-сценариев задержка до 1-2 секунд приемлема. Для финансовых операций с жесткими требованиями используйте синхронное чтение из командной модели после записи.
Интеграция с API Gateway и Service Mesh
Saga, CQRS и Event Sourcing решают логику процессов. API Gateway и Service Mesh решают сетевую маршрутизацию: как запрос клиента доходит до нужного сервиса и как сервисы общаются между собой без потерь.
API Gateway: управление внешним трафиком
API Gateway - единая точка входа для клиентов. Он принимает запросы, маршрутизирует их к сервисам, агрегирует ответы. Попутно выполняет аутентификацию, rate limiting, трансформацию протоколов.
Паттерн Backend for Frontend (BFF) создает отдельный шлюз для каждого типа клиента: мобильное приложение получает агрегированные данные в одном запросе, веб-интерфейс - в другом, внешние API-партнеры - в третьем. Это снижает количество round-trip запросов и адаптирует ответы под нужды клиента.
# Конфигурация маршрута в Kong
routes:
- name: order-route
paths: ["/api/orders"]
methods: ["GET", "POST"]
service: order-service
plugins:
- name: rate-limiting
config:
minute: 100
- name: circuit-breaker
config:
timeout: 5000
max_failures: 3
API Gateway интегрируется с Saga на уровне компенсации. Если шлюз не может доставить ответ клиенту из-за таймаута, он инициирует компенсирующий вызов через оркестратор. Circuit breaker на шлюзе предотвращает каскадные отказы: при превышении порога ошибок запросы к проблемному сервису временно блокируются.
Service Mesh: надежная коммуникация между сервисами
Service Mesh выносит сетевую логику из кода сервисов в sidecar-прокси. Envoy (или Linkerd-proxy) внедряется рядом с каждым сервисом и перехватывает весь трафик. Сервис вызывает другой сервис через localhost, а прокси обеспечивает обнаружение, балансировку, повторные попытки, обрыв цепи и mTLS.
Istio управляет этими прокси через две ключевые сущности: VirtualService задает правила маршрутизации, DestinationRule определяет политики для версий сервиса.
# Istio VirtualService: маршрутизация по версиям
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: payment-service
spec:
hosts:
- payment-service
http:
- match:
- headers:
x-api-version:
exact: "v2"
route:
- destination:
host: payment-service
subset: v2
timeout: 3s
retries:
attempts: 2
perTryTimeout: 1s
- route:
- destination:
host: payment-service
subset: v1
weight: 90
- destination:
host: payment-service
subset: v2
weight: 10
Эта конфигурация делает три вещи: направляет запросы с заголовком x-api-version: v2 на новую версию сервиса, применяет canary-развертывание (10% трафика на v2), настраивает таймаут 3 секунды и две повторные попытки при отказе.
Service Mesh усиливает Saga на транспортном уровне. Вместо того чтобы кодировать повторные попытки и таймауты в каждом сервисе, вы задаете их в конфигурации Istio. Оркестратор вызывает сервис, а Mesh гарантирует доставку вызова с заданными политиками.
Другие паттерны маршрутизации данных, включая Request/Reply и Event-Driven, сравниваются в статье о паттернах маршрутизации данных.
Выбор подхода: сравнительный анализ и рекомендации
Каждый шаблон решает свою часть проблемы. Saga - согласованность распределенных транзакций. CQRS - производительность чтения. Event Sourcing - аудит и восстановление состояния. API Gateway - внешний трафик. Service Mesh - внутреннюю связность. Выбор зависит от требований конкретной системы.
| Критерий | Saga (хореография) | Saga (оркестрация) | CQRS + Event Sourcing | API Gateway + Service Mesh |
|---|---|---|---|---|
| Согласованность | Eventual, компенсации | Eventual, явные компенсации | Eventual, проекции | Не влияет |
| Сложность внедрения | Средняя | Высокая | Очень высокая | Средняя |
| Масштабируемость | Высокая | Ограничена оркестратором | Высокая (раздельные БД) | Высокая |
| Отказоустойчивость | Высокая, нет единой точки | Требует резервирования оркестратора | Высокая | Высокая (circuit breaker, retry) |
| Отладка | Сложная | Простая | Средняя (события - это лог) | Простая (трассировка в Mesh) |
Типовые сценарии и рекомендации:
- Электронная коммерция. Saga с оркестрацией для процесса заказа, CQRS для каталога товаров (чтений в 100 раз больше записей), API Gateway для мобильного и веб-клиента, Service Mesh для canary-развертываний новых версий корзины.
- Финансовые транзакции. Saga с оркестрацией и строгим аудитом через Event Sourcing. Каждое изменение счета - событие. CQRS оправдан для отчетов и выписок. Service Mesh обязателен для mTLS между сервисами.
- IoT-платформа. Хореография для потока телеметрии (высокая пропускная способность, слабая связанность). CQRS для разделения потока записи (InfluxDB) и чтения аналитики (ClickHouse). API Gateway для управляющих команд от пользователей.
Антипаттерны: Event Sourcing для простого CRUD-сервиса с 5 полями - избыточно. Оркестратор, вызывающий один сервис - бесполезная прослойка. Service Mesh в кластере из трех сервисов - переусложнение инфраструктуры.
Практические примеры: сквозная реализация
Соберем систему обработки заказов, объединяющую все шаблоны. Стек: Java 21, Spring Boot 3, PostgreSQL (командная модель), MongoDB (читаемая модель), Kafka (события), Istio (Service Mesh), Kong (API Gateway).
Архитектура: клиент отправляет запрос через Kong. Шлюз направляет его в сервис OrderSagaOrchestrator. Оркестратор выполняет Saga: создает заказ, резервирует склад, списывает оплату. Каждый шаг публикует событие в Kafka. Проектор CQRS слушает события и обновляет читаемую модель в MongoDB для запросов UI. Event Sourcing сохраняет все события в EventStoreDB для аудита. Istio обеспечивает повторные попытки и таймауты между сервисами.
# docker-compose: основные сервисы
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: orders_command
mongodb:
image: mongo:7
environment:
MONGO_INITDB_DATABASE: orders_query
kafka:
image: confluentinc/cp-kafka:7.6.0
environment:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
order-orchestrator:
build: ./order-orchestrator
ports: ["8081:8081"]
depends_on: [postgres, kafka]
payment-service:
build: ./payment-service
ports: ["8082:8082"]
inventory-service:
build: ./inventory-service
ports: ["8083:8083"]
Пошаговый запуск:
- Разверните инфраструктуру:
docker compose up -d postgres mongodb kafka - Соберите и запустите сервисы:
docker compose up -d --build - Примените конфигурацию Istio:
kubectl apply -f istio-virtualservice.yaml - Настройте маршруты Kong:
kong config db_import kong-routes.yaml - Отправьте тестовый заказ:
curl -X POST http://gateway/api/orders -d '{"customerId": 1, "items": [{"productId": 10, "quantity": 2}]}' - Проверьте статус:
curl http://gateway/api/orders/1
При отказе платежного сервиса оркестратор получит исключение, вызовет компенсацию на складе (отмена резервирования) и отменит заказ. Все события записаны в EventStoreDB - вы можете восстановить состояние на любой момент и проанализировать, что пошло не так.
Для production-развертывания этой архитектуры требуется облачная инфраструктура с управляемым Kubernetes. Timeweb Cloud предоставляет кластеры Kubernetes, базы данных и S3-хранилище с поминутной тарификацией - подходит для размещения микросервисных систем с переменной нагрузкой.
Маршрутизация процессов в микросервисах - это комбинация шаблонов под конкретные требования. Начните с Saga для распределенных транзакций. Добавьте CQRS, когда чтение становится узким местом. Внедрите Event Sourcing для аудита. Усильте инфраструктуру API Gateway и Service Mesh. Каждый слой решает свою задачу, а вместе они дают управляемую, отказоустойчивую систему.