Ответ
Традиционные ACID-транзакции (например, двухфазный коммит) плохо подходят для микросервисов из-за сильной связанности и блокировок. Вместо них используются паттерны, основанные на принципе конечной согласованности (eventual consistency).
-
Saga Pattern
- Идея: Длинная транзакция разбивается на серию локальных транзакций в каждом сервисе. Если какой-то шаг не удается, выполняются компенсирующие транзакции для отмены предыдущих шагов.
- Реализации:
- Оркестрация (Orchestration): Центральный сервис-координатор управляет процессом, вызывая сервисы по очереди.
- Хореография (Choreography): Сервисы общаются через события (events). Каждый сервис подписывается на события других и реагирует на них, запуская свою локальную транзакцию.
-
Two-Phase Commit (2PC)
- Идея: Классический алгоритм с координатором и участниками.
- Фаза 1 (Prepare): Координатор спрашивает всех участников, готовы ли они к коммиту. Участники блокируют ресурсы.
- Фаза 2 (Commit/Abort): Если все готовы, координатор отправляет команду
commit. Если хоть один не готов — командуabort.
- Недостатки: Считается анти-паттерном в микросервисах из-за низкой производительности, блокировок и наличия единой точки отказа (координатора).
- Идея: Классический алгоритм с координатором и участниками.
-
Outbox Pattern
- Идея: Обеспечивает надежную доставку сообщений/событий. Вместо того чтобы сразу отправлять событие в брокер сообщений после изменения данных в БД, сервис выполняет 2 действия в рамках одной локальной транзакции:
- Сохраняет бизнес-сущность в свою таблицу.
- Сохраняет событие в специальную таблицу
outbox.
- Отдельный процесс (или сам сервис) асинхронно читает события из
outboxи надежно доставляет их в брокер сообщений (Kafka, RabbitMQ). Это гарантирует, что событие не будет потеряно и будет отправлено только если бизнес-транзакция успешно завершилась.
- Идея: Обеспечивает надежную доставку сообщений/событий. Вместо того чтобы сразу отправлять событие в брокер сообщений после изменения данных в БД, сервис выполняет 2 действия в рамках одной локальной транзакции:
-
Event Sourcing
- Идея: Состояние приложения не хранится в его текущем виде. Вместо этого хранится полная последовательность событий (фактов), которые привели к этому состоянию. Текущее состояние можно восстановить, "проиграв" все события. Этот подход хорошо сочетается с хореографической сагой.
Вывод: Для большинства микросервисных систем Saga и Outbox Pattern являются наиболее предпочтительными и популярными решениями. В Go для реализации саг часто используют готовые фреймворки, например, dtm-labs/dtm.
Ответ 18+ 🔞
А, слушай, вот эта вся хуйня с транзакциями в микросервисах, это же просто пиздец, а не тема! Раньше, в монолите, жили как у Христа за пазухой — накинул BEGIN TRANSACTION, наделал делов, COMMIT, и все, красота. А теперь эти ваши сервисы, как тараканы, по углам расползлись, и как их, блядь, согласовать?
Так вот, классические ACID-транзакции, типа двухфазного коммита (2PC), в этой архитектуре — это как пытаться управлять оркестром, где каждый музыкант в отдельной комнате и ещё пьяный в дрызг. Сплошные блокировки, связанность пиздец какая, и если координатор накроется — всем пипец, концерт окончен. Поэтому тут работает принцип «ну, ладно, согласуемся как-нибудь потом», он же eventual consistency.
Давай по порядку, а то у меня уже терпения ноль ебать.
1. Сага (Saga Pattern) Вот это, блядь, наш бронепоезд! Суть проще пареной репы: длинную операцию разбиваем на кучу маленьких шагов, каждый в своём сервисе. Если на каком-то шаге всё пошло по пизде, мы не плачем, а запускаем компенсирующие транзакции — откатываем всё, что натворили до этого. Как в жизни: купил диван, а потом понял, что он не влезает в лифт — везешь обратно, пизда вопрос.
А реализовать это можно двумя способами, и оба — огонь:
- Оркестрация: Заводим себе отдельного зануду-координатора. Он, как мама в детстве, всем командует: «Вася, сделай это!», «Петя, а теперь ты!». Если Петя обосрался, координатор говорит: «Вася, отмени, что сделал!». Прямолинейно, но координатор — это единая точка пиздеца, да.
- Хореография: А вот это уже вечеринка! Никаких начальников. Каждый сервис, сделав своё дело, кричит в общий чат (брокер сообщений): «Эй, народ, я только что заказ создал!». Другой сервис слышит это, такой: «О, клёво!», и бежит резервировать товар. А третий, если что-то не так, орёт: «Всё нахуй, отмена!». Все друг друга слышат и реагируют. Красота, но если логика сложная, можно так запутаться, что волосы дыбом встанут.
2. Двухфазный коммит (2PC) Про это даже говорить не хочется, честно. Ну ладно, для истории. Координатор спрашивает всех: «Готовы, пацаны?». Все отвечают «Да» и замирают в ожидании, ресурсы на замке. Если все готовы — координатор командует: «Вперёд!». Если хоть один мудак сказал «Нет» — «Отмена!». Проблема в чём? Пока они все ждут, они заблокированы. А если координатор ляжет — все так и будут ждать до второго пришествия. В микросервисах это антипаттерн, ядрёна вошь. Забудь как страшный сон.
3. Паттерн «Исходящий ящик» (Outbox Pattern) А вот это, блядь, гениальная штука, чтобы события не терялись! Представь: сервису нужно и в свою базу данные записать, и событие в Kafka отправить. А если после записи в базу сервис упадёт, событие-то не уйдёт! И будет несостыковочка, пизда.
Как делают умные люди? В рамках одной-единственной, нормальной, локальной транзакции они делают ДВЕ записи:
- Пишут бизнес-данные (например,
заказ_создан). - Пишут точно такое же событие в специальную таблицу
outboxв той же самой базе.
BEGIN;
INSERT INTO orders ...; -- Основная бизнес-таблица
INSERT INTO outbox (event_data) VALUES ('{"type":"OrderCreated"}'); -- Таблица-почтальон
COMMIT;
И уже потом отдельный, долбоёбистый и неубиваемый процесс выгребает события из outbox и тащит их в Kafka. Гарантия железная: событие уйдёт ровно тогда, когда основная транзакция завершится. Просто, как три копейки, и надёжно, как швейцарские часы.
4. Event Sourcing (Помешательство на событиях)
Это для самых отчаянных философов. Тут вообще не хранят текущее состояние. Вместо этого пишут лог ВСЕХ событий, которые когда-либо произошли: ЗаказСоздан, ТоварЗарезервирован, ПлатежПрошел. Хочешь узнать текущее состояние заказа? Блядь, проиграй всю эту ленту с начала! Зато история полная, и для саг-хореографий это просто родной дом.
Итог, нахуй:
Забудь про 2PC, это прошлый век. Для координации между сервисами бери Сагу (особенно с Outbox'ом, чтобы события не терялись). А если хочешь полный контроль и аудит — посмотри в сторону Event Sourcing. В Go, кстати, для саг есть готовые штуки, типа dtm-labs/dtm, чтобы велосипед не изобретать. Вот и вся магия, ебать мои старые костыли.