Я прочитал некоторую информацию о распределенных транзакциях 2 Phase Commit/XA и о том, как JTA поддерживает их. Кажется, что есть много менеджеров ресурсов - RM (например, RDBMS или JMS) и один экземпляр TransactionManager (TM), который управляет глобальными транзакциями во многих RM.
Я знаю, что лучше использовать шаблон Saga, но все же интересно подумать:
UPD: в мире JTA TransactionManager
не предоставляет REST API для управления транзакциями между микросервисами. LIXA предоставляет эту возможность. Статья с примерами в дополнение к ответам :)
Мое понимание 2PC/XA: если у нас есть одно монолитное приложение с двумя разными подключениями к базе данных - мне ясно, как использовать TransactionManager
, который будет частью этого приложения, чтобы мы могли делегировать управление распределенными транзакциями по * многим базам данных / JMS. системы в TransactionManager
. Но я не могу представить, как управлять несколькими базами данных в разных микросервисах, где мы используем шаблон базы данных для каждого сервиса, и каждый сервис имеет доступ только к своей БД. Как в этом случае делать распределенные транзакции 2PC/XA?
В микросервисах транзакция должна выполняться путем предоставления API-интерфейсов Prepare & Commit. Также должен быть менеджер транзакций для координации транзакций.
Например, предположим, что существует 2 разных банка и 100 долларов США со счета_A в банке 1 должны быть переведены на счет_B в банке 2. Кроме того, предположим, что орган центрального банка несет ответственность за завершение транзакции. способ работы 2PC выглядит следующим образом:
Центральный банковский орган (менеджер транзакций) получит запрос на перевод 100 долларов США со счета_A из банка1 на счет_B из банка2.
a. https://CentralBank/Transaction?from=Bank1-Account_A&to=Bank2-Account_B&amount=100
Центральный банк сохранит это в своей базе данных транзакций с некоторым идентификатором транзакции = 123. Также он вернет идентификатор транзакции для вызова, чтобы позже он мог вызвать, чтобы получить статус транзакции.
a. add transaction 123 in database with status open
PREPARE PHASE Менеджер транзакций выдаст следующие RPC-команды:
a. https://Bank1/Prepare?Account=Account_A&money=100&action=subtract&transactionid=123
b. https://Bank2/Prepare?Account=Account_B&money=100&action=add&transactionid=123
ЭТАП СОВЕРШЕНИЯ Когда он получает успешный ответ на оба вызова на этапе подготовки, он переходит к этапу фиксации, где выдает следующие команды:
a. move transaction 123 to committed state
b. https://Bank1/Commit?transactionid=123
c. https://Bank2/Commit?transactionid=123
Как только он получит успешный ответ на оба вызова на этапе фиксации, центральный банк может перевести транзакцию в состояние «Завершено» (необязательно).
Если какой-либо из шагов фазы PREPARE или COMMIT завершается неудачей, координатор транзакции прерывает транзакцию, выдавая следующие команды:
a. move transaction 123 to Failed state
b. https://Bank1/Rollback?transactionid=123
c. https://Bank2/Rollback?transactionid=123
Вышеупомянутая проблема — это форма фиксации Distributed Atomic, и 2PC — один из способов сделать это. Также обратите внимание, что у 2PC есть много недостатков, например, что произойдет, если после фазы ПОДГОТОВКИ произойдет сбой центрального банка. Кроме того, что делать, если шаг 4.c терпит неудачу, а шаг 4.b завершается успешно и т. д. Обсуждение этих вопросов само по себе является очень обширным исследованием, но о нем все же следует знать. Несмотря на множество недостатков, 2PC широко используется из-за своей простоты.
Нужно ли нам использовать службу TransactionManager как отдельную микрослужбу, чтобы обеспечить 2PC между многими микрослужбами?
Теоретически нет. Если вы внимательно наблюдаете, любой из банков (Банк1 или Банк2) также может выступать в качестве менеджера транзакций (ему просто нужна отдельная таблица базы данных Транзакция), но практически много времени он хранится как отдельный микросервис.
что вы подразумеваете под "много RM только из одного сервиса и одного TM"?