Что такое распределённая транзакция в микросервисной архитектуре?

Ответ

Распределённая транзакция в контексте микросервисов — это бизнес-операция, которая обновляет данные в нескольких независимых сервисах, и для которой требуется обеспечить атомарность (все обновления выполняются, либо ни одно не выполняется) и согласованность.

Проблема: В монолитной системе для этого используется транзакция БД (ACID). В микросервисах каждый сервис управляет своей собственной базой данных (паттерн Database per Service), что делает классические ACID-транзакции с двухфазным коммитом (2PC) непрактичными из-за сложности, блокировок и низкой производительности.

Основные подходы к реализации:

  1. Сага (Saga): Наиболее распространённый паттерн. Длинная транзакция разбивается на последовательность локальных транзакций в каждом сервисе.

    • Каждая локальная транзакция публикует событие, которое запускает следующую.
    • При сбое выполняются компенсирующие транзакции (compensating transactions) для отката уже выполненных шагов.
    • Пример (Оформление заказа):
      1. Order Service создаёт заказ в статусе PENDING.
      2. Payment Service резервирует средства.
      3. Inventory Service блокирует товар на складе.
        • Если шаг 3 fails, Payment Service должен выполнить компенсирующую транзакцию — вернуть средства.
  2. Двухфазный коммит (2PC): Координатор управляет процессом голосования и фиксации изменений во всех участвующих сервисах. Используется редко из-за недостатков (блокировки ресурсов, низкая доступность, сложность).

  3. Паттерн "Исход-компенсация" (Try-Confirm/Cancel): Вариант Saga, где сначала выполняется этап проверки и резервирования (Try), а затем подтверждение (Confirm) или отмена (Cancel).

Вывод: В микросервисах стремятся к согласованности в конечном счёте (eventual consistency) и используют Saga как основной паттерн для управления распределёнными транзакциями, жертвуя немедленной согласованностью ради доступности и масштабируемости.

Ответ 18+ 🔞

А, распределённые транзакции в микросервисах! Ну это ж классика, блядь, вечный геморрой! Сидишь такой, думаешь: «Вот щас сделаю красивую архитектуру, всё разнесу, независимо будет». А потом бац — и надо деньги списать, заказ создать и товар со склада убрать, и чтобы всё разом, а сервисы-то друг про друга нихуя не знают! Ёпта, вот где собака зарыта, точнее, где Муму утопили, блядь!

Смотри, в монолите-то всё просто: база одна, транзакцию накинул — и спи спокойно, либо всё запишется, либо нихуя. Красота, ACID, ёбаный в рот! А тут у тебя каждый сервис — как тот самый Герасим, немой и глухой, в своей крепости сидит. Свою базу свою имеет, и на соседа ему похуй. Кричи ему «Сделай шаг два!», а он тебе в ответ: «Мууу. У меня своя транзакция прошла, а что там у других — не моя проблема, иди нахуй».

И вот сидит архитектор, чешет репу: «Как же обеспечить, чтобы либо все шаги прошли, либо откатились, как будто ничего и не было?». И тут на сцену выходит, блядь, главная звезда этого ёбанного театра — Сага.

Сага — это такая длинная, многосерийная история, как «Игра престолов», только про твои данные. Вместо одной жирной транзакции — цепочка маленьких, локальных. Каждый сервис делает своё дело и, вместо того чтобы молчать как Герасим, орет на весь мир (ну, в брокер сообщений): «Я, сука, деньги списал! Следующий, делай что должен!».

И вся соль в чём? В откате. Потому что если на третьем шаге складской сервис такой: «А товара-то нет, пиздец», — то надо всё назад откатывать. Но просто так отменить уже выполненное — нельзя. Поэтому для каждого шага придумывают компенсирующую транзакцию — это как извинение, только кодом. «Ой, бля, прости, я деньги-то списал, щас верну».

Пример, чтобы совсем охуенно стало понятно:

  1. Сервис заказов: «Так, мудаки, заказ создал, статус PENDING (ожидает)». Публикует событие «Заказ создан».
  2. Платежный сервис: «О, событие! Щас клиента поимею... то есть деньги резервирую». Публикует событие «Деньги зарезервированы».
  3. Складской сервис: «Ага, деньги есть. Сейчас товар заблокирую... Опа! А товара-то и нет! Всё, пизда!». Публикует событие «Товара нет, всё пропало».

И тут начинается магия компенсаций, блядь. Событие о провале летит назад:

  • Платежный сервис его ловит: «А, бля, ну значит не судьба. Компенсирующая транзакция, активируй! Возвращаем деньги».
  • Сервис заказов тоже в теме: «Жаль, конечно. Компенсирующая транзакция! Меняю статус заказа на CANCELLED».

И в итоге система в целом пришла в согласованное состояние, хоть и не мгновенно. Это и есть согласованность в конечном счёте (eventual consistency). Все немного понервничали, но в итоге всё устаканилось.

А что с двухфазным коммитом (2PC)? А его, этого пидора шерстяного, все нахуй послали за редким исключением. Потому что он — тот самый крикливый князь, который всех блокирует и требует немедленного ответа. Координатор такой: «Все готовы закоммитить?». И если один сервис лег или просто медленно думает, то все остальные сидят на блокировках и не могут двигаться дальше. Доступность на нуле, производительность — пиздец. В микросервисах это почти табу.

Вывод, сука, какой? В мире микросервисов надо забыть про мгновенную, идеальную согласованность как в монолите. Здесь царствует Сага с её долгими историями и компенсациями. Жертвуешь строгой согласованностью ради того, чтобы сервисы не задыхались в объятиях друг друга, а были свободными и масштабируемыми. Просто нужно быть готовым, что какое-то время данные в разных сервисах могут немного не сходиться, но в итоге всё будет хорошо. Главное — правильно обрабатывать «ой, бля, не вышло».