🔥 Как управлять данными и транзакциями в распределенных системах
CQRS (Command Query Responsibility Segregation)
Что это?
Паттерн, разделяющий операции записи (команды) и чтения (запросы) данных. У каждой части — своя модель данных и часто даже своя база.
Зачем нужно?
- Масштабируемость: Чтение (например, отчеты) и запись (например, оплата) могут масштабироваться независимо.
- Гибкость: Разные модели для разных задач (оптимизация под аналитику или транзакции).
- Производительность: Кэширование данных для чтения без влияния на запись.
Как работает?
- Command Side (Запись):
- Принимает команды (CreateOrder, UpdateUser).
- Валидирует данные и обновляет Write Model (основная БД).
- Публикует события об изменениях (например, через Kafka).
- Query Side (Чтение):
- Слушает события из Command Side.
- Обновляет Read Model (оптимизированную для чтения, например, денормализованную таблицу).
- Отвечает на запросы (GetOrderDetails, GetUserStatistics).
Пример:
- В интернет-магазине:
- Command: Создание заказа → пишет в PostgreSQL.
- Query: Отображение истории заказов → читает из ElasticSearch (быстрый поиск).
Плюсы:
- Разделение нагрузки.
- Возможность использовать разные СУБД (PostgreSQL для записи, Redis для чтения).
Минусы:
- Сложность синхронизации данных между Write и Read моделями.
- Риск «несвежих» данных в Read Model.
Saga
Что это?
Паттерн для управления распределенными транзакциями в микросервисах. Гарантирует согласованность данных между сервисами без использования ACID-транзакций (которые невозможны в распределенных системах).
Зачем нужно?
В микросервисах:
- Нет единой БД → транзакции охватывают несколько сервисов.
- Нужен механизм отката изменений при ошибках.
Типы Saga:
1. Choreography (Хореография)
Каждый сервис самостоятельно запускает следующие шаги и обрабатывает ошибки через события.
Как работает:
Сервис А выполняет действие → публикует событие.
Сервис Б слушает событие → выполняет свое действие → публикует новое событие.
Если ошибка → сервис публикует событие-компенсацию.
Пример Saga для заказа:
CopyOrderService → Создает заказ → публикует «OrderCreated».
InventoryService → Резервирует товар → публикует «InventoryReserved».
PaymentService → Списание денег → публикует «PaymentCompleted».
Если оплата не прошла → PaymentService публикует «PaymentFailed» → OrderService отменяет заказ.
Плюсы:
Нет централизованного управления.
Высокая гибкость.
Минусы:
Сложно отслеживать поток событий.
Риск циклических зависимостей.
2. Orchestration (Оркестрация)
Центральный координатор (оркестратор) управляет потоком выполнения.
Как работает:
Оркестратор вызывает сервисы по очереди.
Если шаг завершен → переход к следующему.
Если ошибка → запускает компенсирующие транзакции.
Пример Saga с оркестратором:
1. Вызвать OrderService → создать заказ.
2. Если успешно → вызвать InventoryService → зарезервировать товар.
3. Если успешно → вызвать PaymentService → списать деньги.
4. Если оплата успешна → подтвердить заказ.
Если на любом шаге ошибка → откатить предыдущие шаги.
Плюсы:
Централизованное управление → проще дебажить.
Четкий контроль потока.
Минусы:
Оркестратор становится точкой отказа.
Дополнительная сложность реализации.
Когда использовать CQRS и Saga?
CQRS: Системы с высокой нагрузкой на чтение (аналитика, отчеты), где данные для чтения и записи имеют разную структуру.
Saga: Транзакции, затрагивающие несколько сервисов (например, оформление заказа, бронирование билетов).
Проблемы и решения
Для CQRS:
- Синхронизация моделей: Используйте Event Sourcing (сохранение всех событий изменения состояния) + Kafka.
- Задержка данных: Настройте TTL для кэша или информируйте пользователей о возможной задержке.
Для Saga:
- Идемпотентность: Убедитесь, что компенсирующие транзакции можно выполнять многократно без побочных эффектов.
- Мониторинг: Внедрите трейсинг (например, Jaeger) для отслеживания выполнения шагов.
Примеры реализации
CQRS + Event Sourcing
1. Пользователь отправляет команду "CreateUser".
2. Command Handler валидирует данные и сохраняет событие "UserCreated" в Event Store.
3. Read Model обновляется асинхронно (проекция события в MongoDB).
4. API для чтения возвращает данные из Read Model.
Saga с компенсацией
Сценарий: Отмена заказа.
1. OrderService → отменить заказ.
2. InventoryService → вернуть товар на склад.
3. PaymentService → вернуть деньги.
Если шаг 2 или 3 не выполнен → повторить компенсацию или уведомить поддержку.
🔥 Заключение
- CQRS — ваш выбор, когда нужно разделить нагрузку и оптимизировать чтение/запись.
- Saga — спасение для распределенных транзакций, но требует тщательного проектирования откатов.
Используете эти паттерны? Делитесь кейсами в комментариях!
#микросервисы #архитектура #CQRS #Saga