При проектировании взаимодействия между микросервисами часто встает вопрос о реализации распределённых транзакций. В монолитах контроля хватает встроенных механизмов, но в микросервисах ситуация усложняется из-за разных БД, технологий, форматов обмена данными. Главное правило — избегать длинных распределённых транзакций, они плохо масштабируются и несут риск деградации производительности.
Вместо классических ACID-протоколов рекомендуется использовать паттерн SAGA. Это цепочка локальных транзакций, где каждая микрослужба фиксирует свои изменения и, при необходимости выполнения отката, отправляет компенсационную операцию в рамках своей ответственности.
Пример упрощённой реализации управления сагой на Node.js c REST:
// Saga orchestrator на Express app.post('/saga', async (req, res) => { try { await serviceA.transaction(); await serviceB.transaction(); res.send('ok'); } catch (err) { await serviceA.rollback(); res.status(500).send('rollback performed'); } });
Ключевые особенности:
Можно ли использовать классические двухфазные коммиты (2PC) между микросервисами для поддержки транзакций?
Можно, но это не рекомендуется для микросервисных архитектур. 2PC тормозит масштабирование и связывает сервисы технологически и организационно.
Все ли сценарии SAGA подходят для финансовых операций?
Нет. SAGA сложнее корректно реализовать для сценариев, где критична строгость ACID, например, пересчёт остатков на одном счёте. Здесь важно оценивать риски и выбирать компромисс.
Как происходит обработка неуспеха промежуточного шага, если микросервис не может откатиться?
В таких случаях нужно реализовать ручной или автоматизированный протокол компенсации, возможно, с помощью отдельного журнала событий.