Двухфазная фиксация в распределенных транзакциях | OTUS

Двухфазная фиксация в распределенных транзакциях

При разработке бэкенда высоконагруженных сервисов часто применяют распределенные транзакции. О проблемах, с которыми можно столкнуться при совершении данных транзакций в микросервисах, мы уже говорили. Пришло время поговорить о способах их решения. Один из способов -- двухфазная фиксация.

Двухфазный метод транзакций предполагает наличие 2-х этапов: фазы подготовки и фазы фиксации. Немаловажную роль играет координатор транзакций, который, по сути, организует жизненный цикл транзакции. Рассмотрим, как это работает на практике.

Уже на подготовительном этапе микросервисы, которые участвуют в работе, подготавливаются к фиксации, а также уведомляют координатора о готовности завершить транзакцию. На следующем этапе фиксация либо происходит, либо координатор транзакции выдает команду микросервисам выполнить откат.

В качестве примера можно привести работу интернет-магазина. Ниже -- как раз таки пример успешной 2-фазной фиксации в микросервисной системе:

1-20219-3d9a48.png

Мы видим, что когда пользователь направляет запрос на заказ, TransactionCoordinator, обладающий полной информацией о контексте, сначала начинает глобальную транзакцию. Он отправляет команду подготовиться микросервису OrderMicroservice, что необходимо для создания заказа. Потом он отправляет команду подготовиться к InventoryMicroservice, что необходимо для резервирования товаров. Когда оба эти сервиса готовы внести изменения, происходит блокировка объектов от последующих изменений, о чем уведомляется TransactionCoordinator. И в тот момент, когда TransactionCoordinator подтвердит, что микросервисы готовы применить изменения, поступит команда микросервисам эти изменения сохранить путем запроса фиксации транзакции. В тот самый момент все объекты будут разблокированы.

Для полноты картины можно рассмотреть и пример неудавшейся 2-фазной фиксации:

2-20219-606d68.png

В сценарии отказа, который показан на рисунке выше, все работает следующим образом: если в любую секунду отдельно взятый микросервис приготовиться не успеет, то TransactionCoordinator отменит транзакцию, запустив процесс отката. К примеру, на нашей схеме OrderMicroservice по каким-то причинам заказ создать не смог, однако InventoryMicroservice при этом откликнулся, что создать заказ он готов. В результате координатор TransactionCoordinator запросит отмену на InventoryMicroservice, ну а далее сервис откатит все выполненные изменения и разблокирует объекты БД.

Плюсы и минусы

Подход имеет как преимущества, так и недостатки.

Плюсы:

  • гарантируется атомарность транзакции. Транзакция завершится либо при успешной сработке обоих микросервисов, либо в том случае, если микросервисы не внесут вообще никаких изменений;
  • изолируется чтение от записи. Изменения не видны в объектах до тех пор, пока координатор транзакций эти изменения не зафиксирует;
  • подход является синхронным вызовом, при котором клиент уведомляется или об успехе, или о неудаче.

Минусы:

  • 2-фазные фиксации протекают относительно медленно, если сравнивать их с операциями над одним микросервисом. Также они существенно зависят от координатора транзакций, что иногда замедляет работу системы, особенно в период повышенной загруженности;
  • блокируются строки базы данных. Такая блокировка может становиться узким местом, где затрудняется производительность, мало того, не исключена взаимная блокировка, когда 2 транзакции намертво застопорят друг друга.

Highload_970x90-1801-fc90a0.png

По материалам "Handling Distributed Transactions in the Microservice world".

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
Популярное
Сегодня тут пусто