Что такое распределенная транзакция

Обработка распределенных транзакций в микросервисной архитектуре

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

Приятного чтения!

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

Что такое распределенная транзакция?

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

Вот монолитная система интернет-магазина, в которой используются транзакции:

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция

Рис. 1: Транзакция в монолите

Если в вышеприведенной системе пользователь отправляет к платформе запрос на заказ (Checkout), то платформа создает локальную транзакцию в базе данных, и эта транзакция охватывает множество таблиц базы данных, чтобы обработать (Process) заказ и зарезервировать (Reserve) товары со склада. Если любой из этих шагов совершить не удастся, то транзакция может откатиться, что означает отказ как от самого заказа, так и от зарезервированных товаров. Этот набор принципов называется ACID (атомарность, согласованность, изоляция, долговечность) и гарантируется на уровне системы базы данных.

Вот декомпозиция системы интернет-магазина, построенной из микросервисов:

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция

Рисунок 2: Транзакции в микросервисе

В чем проблема при совершении распределенных транзакций в микросервисах?

С внедрением микросервисной архитектуры базы данных утрачивают свою ACID-природу. В силу возможного распространения транзакций между множеством микросервисов и, следовательно, баз данных, приходится иметь дело со следующими ключевыми проблемами:

Как поддерживать атомарность транзакции?

Как обрабатывать конкурентные запросы?

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

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

Возможные решения

Две вышеупомянутые проблемы весьма критичны в контексте проектирования и создания приложений на основе микросервисов. Для их решения применяется два следующих подхода:

1. Двухфазная фиксация

Как понятно из названия, такой способ обработки транзакций предполагает два этапа: фазу подготовки и фазу фиксации. Важную роль в данном случае играет координатор транзакций, организующий жизненный цикл транзакции.

Как это работает

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

Вновь рассмотрим для примера систему интернет-магазина:

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция

Рисунок 3: успешная двухфазная фиксация в микросервисной системе

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция
Рисунок 4: Неудавшаяся двухфазная фиксация при работе с микросервисами

Преимущества

Недостатки

2. Согласованность в конечном счете и компенсация / SAGA

Одно из лучших определений согласованности в конечном счете дается на сайте microservices.io: каждый сервис публикует событие всякий раз, когда обновляет свои данные. Другие сервисы подписываются на события. При получении события сервис обновляет свои данные.

При таком подходе распределенная транзакция выполняется как совокупность асинхронных локальных транзакций на соответствующих микросервисах. Микросервисы обмениваются информацией через шину событий.

Как это работает

Опять же, давайте рассмотрим в качестве примера систему, работающую в интернет-магазине:

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция

Рисунок 5: Согласованность в конечном счете / SAGA, успешный исход

В примере выше (рисунок 5), клиент требует, чтобы система обработала заказ. При этом запросе Choreographer порождает событие Create Order (создать заказ), чем начинает транзакцию. Микросервис OrderMicroservice слушает это событие и создает заказ – если эта операция прошла успешно, то он порождает событие Order Created (Заказ создан). Координатор Choreographer слушает это событие и переходит к заказу товаров, порождая событие Reserve Items (зарезервировать товары). Микросервис InventoryMicroservice слушает это событие и заказывает товары; если это событие прошло успешно, то он порождает событие Items Reserved (товары зарезервированы). В данном примере это означает, что транзакция закончена.

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

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция

Рисунок 6: Согласованность в конечном счете / SAGA, неудачный исход

Если по какой-то причине InventoryMicroservice не удалось зарезервировать товары (рисунок 6), он порождает событие Failed to Reserve Items (Не удалось зарезервировать товары). Координатор Choreographer слушает это событие и запускает компенсирующую транзакцию, порождая событие Delete Order (удалить заказ). Микросервис OrderMicroservice слушает это событие и удаляет ранее созданный заказ.

Преимущества

Серьезное преимущество такого подхода заключается в том, что каждый микросервис сосредотачивается лишь на собственной атомарной транзакции. Работа микросервисов не блокируется, если на работу другого сервиса требуется сравнительно много времени. Это также означает, что не требуется блокировать и базу данных. При помощи такого подхода можно обеспечить хорошую масштабируемость системы при работе под высокой нагрузкой, поскольку предлагаемое решение асинхронное и основано на работе с событиями.

Недостатки

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

Заключение

Более распространен подход, когда система создается в виде монолита, после чего по краям от нее постепенно начинают отсекаться микросервисы. При таком подходе в сердце микросервисной архитектуры остается крупное монолитное ядро, но большинство новых разработок приходится на микросервисы, а монолит остается относительно нетронутым. — Мартин Фаулер

Источник

Проблематика распределенных транзакций в контексте микросервисной архитектуры

Всем привет. Уже в сентябре OTUS открывает набор в новую группу курса «Highload Architect». В связи с этим я продолжаю серию своих публикаций, написанных специально для этого курса, а также приглашаю вас на свой бесплатный вебинар, в рамках которого я подробно расскажу о программе курса и формате обучения в OTUS. Записаться на вебинар можно тут.

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция

Введение

Согласованность

Достаточно тонким моментом является то, что согласованность в контексте распределенных систем отличается от согласованности в контексте баз данных. Далее под согласованностью мы будем понимать именно первое: незавершенная (ошибочная) операция не вносит никаких эффектов и не меняет данные, при конкурентном доступе к данным все операции рассматриваются как атомарные (нельзя увидеть промежуточный результат операции), если у данных имеется несколько копий (репликация), то последовательность применения операций на всех копиях одна и та же. То есть на самом деле мы хотим получить ACID транзакцию, но только распределенную.

Причина проблемы

Почему обеспечение согласованности затруднено именно в микросервисной архитектуре? Дело в том, что данный архитектурный стиль зачастую предполагает применение паттерна database per service. Позволю себе напомнить, что этот паттерн заключается в том, что у каждого микросервиса своя независимая база или базы (базы, потому что помимо первичного источника данных может использоваться, например, кеш). Такой подход позволяет с одной стороны не добавлять неявные связи по формату данных между микросервисами (микросервисы взаимодействуют только явно через API), с другой стороны по максимуму использовать такое преимущество микросервисной архитектуры как technology agnostic (мы можем выбирать подходящую под особую нагрузку на микросервис технологию хранения данных). Но при всем при этом мы потеряли гарантию согласованности данных. Посудите сами, монолит общался с одной большой базой, которая предоставляла возможности по обеспечению ACID — транзакций. Теперь баз данных стало много, а вместо одной большой ACID — транзакции у нас много небольших ACID — транзакций. Нашей задачей будет объединение всех этих транзакций в одну распределенную.

Оптимистичная согласованность

Первое что может прийти в голову — это концепция оптимистичной согласованности: мы совершаем столько транзакций сколько хотим на столько механизмов хранения сколько нужно. При этом мы ждем, что все будет хорошо, а если все плохо, то говорим, что все будет хорошо в итоге. Если все плохо в итоге, то говорим: «Да, такое случается, но с крайне низкой вероятностью».

Если без шуток, то пренебрежение обеспечением согласованности в случае ее некритичности для бизнеса является хорошим решением, особенно если учесть то, каких усилий нам будет стоить ее обеспечение (в чем, как я надеюсь, вы убедитесь несколько позже).

Варианты обеспечения консистентности

Если для бизнеса все-таки согласованность является критичной, можно попытаться ее обеспечить несколькими способами. Если мы говорим о ситуации, когда данные обновляются одним сервисом (например имеет место репликация базы данных), то можно применить стандартные алгоритмы обеспечения консистентности такие как Paxos или Raft. Такие транзакции называются гомогенными. Если данные обновляются несколькими сервисами (то есть имеет место гетерогенная транзакция), то как тут как раз и начинаются сложности, о которых мы говорили выше.

С одной стороны мы можем все-таки обойти необходимость обеспечения распределенной транзакции путем стремления к service-based архитектуры (объединяем сервисы таким образом, чтобы транзакция была гомогенная). Такое решение не очень каноничное с точки зрения принципов микросервисной архитектуры, но зато оно технически намного проще из-за чего часто применяется на практике. С другой стороны мы можем оставить каноничные микросервисы, но при этом применить один из механизмов обеспечения распределенных транзакций: двухфазный коммит или сагу. В этой статье будет изучен первый вариант, а второй мы обсудим в следующий раз.

Двухфазный коммит

Механизм предельно прост: есть некоторый transaction manager, который собственно оркестрирует транзакцию. На первом этапе (prepare) transaction manager подает соответствующую команду для resource manager’ов, по которой они в свои журналы записывают данные, которые будут закоммичены. Получив подтверждение ото всех resource manager’ов об успешном завершении первого этапа, transaction manager начинает второй этап и подает следующую команду (commit), по которой resource manager’ы применяют принятые ранее изменения.

Несмотря на кажущуюся простоту, такой подход обладает рядом недостатков. Во-первых, если хотя бы один resource manager даст сбой на втором этапе, вся транзакция должна быть отменена. Таким образом, нарушается один из принципов микросервисной архитектуры — устойчивость к отказам (когда мы приходили к распределенной системе, мы сразу закладывались на то, что отказ в ней является нормой а не исключительной ситуацией). Более того, если отказов будет много (а их будет много), то процесс отмены транзакций необходимо будет автоматизировать (в том числе и писать транзакции, откатывающие транзакции). Во-вторых, сам transaction manager является единой точкой отказа. Он должен уметь транзакционно выдавать id-шники транзакциям. В-третьих, поскольку хранилищу подаются специальные команды, логично предположить, что хранилище должно уметь это делать, то есть соответствовать стандарту XA, а не все современные технологии ему соответствуют (такие брокеры как Kafka, RabbitMQ и NoSQL решения как MongoDB и Cassandra не поддерживают двухфазные коммиты).

Вывод, напрашивающийся из всех этих факторов, был отлично сформулирован Крисом Ричардсоном: «2PC not an option» (двухфазный коммит — не вариант).

Вывод

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

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

Источник

Недавно, на одном интервью меня спросили, а работал ли я с распределенными транзакциями, в том смысле, что нужно было делать вставку/обновление таких записей при условии:

Опция №1. Приложение С++ и ODBC драйвер (вызов Координатора распределенных транзакций Microsoft (MSDTC) для SQL Server по-владению)

Координатор распределенных транзакций Microsoft (MSDTC) позволяет приложениям расширять или распределять транзакции по двум или более экземплярам SQL Server. Распределенная транзакция работает, даже если два экземпляра размещены на разных компьютерах.

MSDTC работает для Microsoft SQL Server только локально, и недоступен для облачной службы базы данных Microsoft Azure SQL.

MSDTC вызывается драйвером собственного клиента SQL Server для Open Database Connectivity (ODBC), когда ваша программа C++ управляет распределенной транзакцией. Драйвер ODBC для собственного клиента имеет диспетчер транзакций, совместимый со стандартом XA Open Distributed Transaction Processing (DTP). Это соответствие требуется MSDTC. Как правило, все команды управления транзакциями отправляются через этот драйвер ODBC для собственного клиента. Последовательность следующая:

Приложение ODBC для собственного клиента C ++ запускает транзакцию, вызывая SQLSetConnectAttr с отключенным режимом автоматической фиксации.
Приложение обновляет некоторые данные на SQL Server X на компьютере A.
Приложение обновляет некоторые данные на SQL Server Y на компьютере B.
В случае сбоя обновления на SQL Server Y все незафиксированные обновления в обоих экземплярах SQL Server откатываются.
Наконец, приложение завершает транзакцию, вызывая SQLEndTran (1) с параметром SQL_COMMIT или SQL_ROLLBACK.

(1) MSDTC может быть вызван без ODBC. В таком случае MSDTC становится менеджером транзакций, и приложение больше не использует SQLEndTran.

Только одна распределенная транзакция.

Предположим, что ваше приложение ODBC для собственного клиента C ++ зачислено в распределенную транзакцию. Затем приложение зачисляется во вторую распределенную транзакцию. В этом случае драйвер ODBC собственного клиента SQL Server покидает исходную распределенную транзакцию и включается в новую распределенную транзакцию.

Подробнее о MSDTC можно прочитать тут.

Опция №2. Приложение C# как альтернатива для базы данных SQL в облаке Azur

MSDTC не поддерживается ни для базы данных SQL Azure, ни для хранилища данных SQL Azure.

В следующем примере показано, как использовать класс TransactionScope для определения блока кода для участия в транзакции.

Опция №3. Приложения C# и Entity Framework Core для распределенных транзакций.

По умолчанию, если поставщик базы данных поддерживает транзакции, все изменения в одном вызове SaveChanges () применяются в транзакции. Если какое-либо из изменений не выполняется, транзакция откатывается, и ни одно из изменений не применяется к базе данных. Это означает, что SaveChanges () гарантированно либо полностью завершится успешно, либо оставит базу данных неизменной в случае возникновения ошибки.

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

Вы можете использовать API DbContext.Database для запуска, фиксации и отката транзакций. В следующем примере показаны две операции SaveChanges () и запрос LINQ, выполняемый в одной транзакции.

Не все поставщики баз данных поддерживают транзакции. Некоторые провайдеры могут выдавать или не выполнять операции при вызове API транзакций.

А раз так, то делаем собственный home-made координатор распределенных транзакций (КРТ).

Один из вариантов реализации это распределенные транзакции основанные на микросервисах (смотрим тут). Этот вариант не плох, но он требует серьезной доработки Web API для всех систем вовлеченных в транзакцию.

А потому, нам нужен немного другой механизм. Ниже приведен общий подход к разработке КРТ.

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакция

Как видно из схемы главной идеей является создание и хранение с обновляемым статусом записи транзакции хранящейся в мастер-базе (или таблице). Даная модель КРТ позволяет реализовать распределенные транзакции соответствующие требованиям:

Таким образом, КРТ в простой форме может быть успешно реализован как часть приложения, или как отдельное настраиваемое и независимое решение (что лучше).

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

Источник

Сравнение подходов к реализации распределенных транзакций для микросервисов

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

Текст насыщен терминами, которые сложно переводимы на русский язык и обычно употребляются как есть. Сначала была мысль оставить английские названия, но в результате текст становится на 30% англоязычным, так что в итоге все термины я постарался перевести. Если есть комментарии по переводу отдельных терминов, напишите в личку.

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

Примечание: если вас интересует двойная запись, посмотрите мою сессию Red Hat Summit 2021, где я подробно рассмотрел особенности двойной записи. Вы также можете просмотреть слайды из моей презентации. В настоящее время я работаю с Red Hat OpenShift Streams для Apache Kafka, полностью управляемой службы Apache Kafka. Для запуска требуется меньше минуты, а в течение пробного периода он полностью бесплатен. Попробуйте и помогите нам сформировать его с помощью ваших ранних отзывов. Если у вас есть вопросы или комментарии по поводу этой статьи, напишите мне в Twitter @bibryam, и приступим.

Проблема двойной записи

Вы выбрали лучшие инструменты для каждой задачи, и теперь вам нужно обновить базу данных NoSQL, поисковый индекс и кеш в рамках одной бизнес-транзакции;

Созданная вами служба должна обновить свою базу данных, а также отправить уведомление об изменении в другую службу;

У вас есть бизнес-операции, которые затрагивают несколько других сервисов;

Возможно, вам нужно реализовать идемпотентность для сервиса, потому что конечные пользователи должны повторять неудачные вызовы.

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакцияРисунок 1: Проблема двойной записи в микросервисах

Небольшое, но важное уточнение ниже объясняет, почему у этой проблемы нет простых решений. Если служба A записывает данные в свою базу, а затем отправляет уведомление в очередь для службы B (назовем это подходом «локальная фиксация затем публикация»), все равно существует вероятность, что приложение не будет работать надежно. Пока служба A записывает в свою базу данных, а затем отправляет сообщение в очередь, существует небольшая вероятность сбоя приложения после сохранения в базе данных и до второй операции, что оставит систему в несогласованном состоянии. Если сообщение отправляется до записи в базу данных (назовем этот подход «публикация затем локальная фиксация»), существует вероятность сбоя записи в базу данных или проблем с синхронизацией, в результате чего служба B получит событие до того, как служба A зафиксирует изменение в своей база данных. В любом случае этот сценарий включает двойную запись в базу данных и в очередь, что является основной проблемой, которую мы собираемся исследовать. В следующих разделах я расскажу о различных подходах, доступных сегодня для решения этой актуальной проблемы.

Модульный монолит

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

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

Архитектура модульного монолита

При таком подходе вам необходимо преобразовать микросервисы (сервис A и сервис B) в библиотечные модули, которые можно развернуть в общую среду выполнения. Затем вы настраиваете оба микросервиса для совместного использования одной базы данных. Поскольку службы написаны и развернуты как библиотеки в общей среде выполнения, они могут использовать один и тот же механизм транзакций. Поскольку модули совместно используют экземпляр базы данных, вы можете использовать локальную транзакцию для одновременной фиксации или отката всех изменений. Мы также должны по-иному развертывать эти модули, поскольку мы хотим, чтобы модули развертывались как библиотеки в более крупном развертывании и использовали общий механизм локальных транзакций.

Даже в монолитной архитектуре есть способы изолировать код и данные. Например, вы можете разделить модули на отдельные пакеты, модули сборки и репозитории исходного кода, которые могут принадлежать разным командам. Вы можете выполнить частичную изоляцию данных, сгруппировав таблицы по соглашению об именах, схемам, экземплярам базы данных или даже по серверам баз данных. Диаграмма на рисунке 2, вдохновленная докладом Акселя Фонтейна о величественных модульных монолитах, иллюстрирует различные уровни изоляции кода и данных в приложениях.

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакцияРисунок 2: Уровни изоляции кода и данных для приложений

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

В нашем примере, показанном на рисунке 3, мы преобразовали службу A и службу B в библиотеки и развернули их в общую среду выполнения, ну или одна из служб могла бы действовать как общая среда выполнения. Таблицы из баз данных также используют единый экземпляр базы данных, разделенный на группы таблиц, управляемых соответствующими библиотечными службами.

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакцияРисунок 3: Модульный монолит с общей базой данных

Преимущества и недостатки модульного монолита

Оказывается, в некоторых отраслях преимущества такой архитектуры гораздо важнее, чем более быстрая доставка и скорость изменений, которые так высоко ценятся в других местах. В таблице 1 приведены преимущества и недостатки модульной монолитной архитектуры.

Преимущества

Простая семантика транзакций с локальными транзакциями, обеспечивающая согласованность данных, чтение и запись, откаты и т. д.

Недостатки

Общая среда выполнения не позволяет нам независимо развертывать и масштабировать модули и изолировать сбои отдельного модуля.

Логическое разделение таблиц в единой базе данных не является сильным. Со временем база данных может превратиться в общий уровень интеграции.

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

Примеры

Такие среды выполнения, как Apache Karaf и WildFly, которые позволяют модульное и динамическое развертывание служб.

Apache Camel direct и direct-vm компоненты позволяют открывать операции для вызовов в памяти и сохранять контексты транзакций в процессе JVM.

Двухфазная фиксация

Распределенные транзакции обычно являются спасением, используемым во множестве случаев:

Когда запись в разрозненные ресурсы должна быть строго согласованной;

Когда нам нужно писать в разнородные источники данных;

Когда требуется однократная обработка сообщения, и мы не можем провести рефакторинг системы и сделать ее операции идемпотентными;

При интеграции со сторонними системами «черного ящика» или устаревшими системами, реализующими спецификацию двухфазной фиксации.

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

Реализация архитектуры двухфазной фиксации

Как пример реализации вы можете использовать на контроллер восстановления Snowdrop, который использует шаблон Kubernetes StatefulSet для гарантии наличия одного элемента и постоянные тома для хранения журналов транзакций. В эту категорию я также включаю такие спецификации, как атомарные транзакции веб-служб (WS-AtomicTransaction) для веб-служб SOAP. Все эти технологии объединяет то, что они реализуют спецификацию XA и имеют центральный координатор транзакций.

В нашем примере, показанном на рисунке 4, служба A использует распределенные транзакции для фиксации всех изменений в своей базе данных и сообщения в очереди, не оставляя никаких шансов дублированию или потере сообщений. Точно так же служба B может использовать распределенные транзакции для приема сообщений и фиксации в базе данных B в одной транзакции без каких-либо дубликатов. Или служба B может решить не использовать распределенные транзакции, а использовать локальные транзакции и реализовать шаблон идемпотентного потребителя. Прошу заметить, подходящим примером для этого раздела было бы использование WS-AtomicTransaction для координации записи в базу данных A и базу данных A в одной транзакции и избежать согласованности в целом. Но в наши дни такой подход встречается еще реже, чем то, что я описал.

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакцияРисунок 4: Двухэтапная фиксация между базой данных и брокером сообщений

Преимущества и недостатки архитектуры двухфазной фиксации

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

В таблице 2 суммированы преимущества и недостатки этого подхода.

Преимущества

Стандартный подход с готовыми менеджерами транзакций и вспомогательными источниками данных.

Сильная согласованность данных для успешных сценариев.

Недостатки

Возможные сбои восстановления при сбое диспетчера транзакций.

Ограниченная поддержка источников данных.

Требования к хранилищу и наличие единого центрального координатора транзакций в динамических средах.

Примеры

Брокеры сообщений, такие как Apache ActiveMQ

Реляционные источники данных, реализующие спецификацию XA; хранилища данных в памяти, такие как Infinispan

Оркестровка

Реализация архитектуры оркестровки

Что такое распределенная транзакция. Смотреть фото Что такое распределенная транзакция. Смотреть картинку Что такое распределенная транзакция. Картинка про Что такое распределенная транзакция. Фото Что такое распределенная транзакцияРисунок 5: Организация распределенных транзакций между двумя сервисами

В нашем примере диаграммы, показанном на рисунке 5, у нас есть служба A, действующая как оркестратор с отслеживанием состояния, ответственный за вызов службы B и восстановление после сбоев с помощью операции компенсации, если это необходимо. Важнейшей характеристикой этого подхода является то, что служба A и служба B имеют локальные границы транзакций, но служба A обладает знаниями и обязанностью управлять общим потоком взаимодействия. Вот почему его граница транзакции касается конечных точек службы B. Что касается реализации, мы могли бы использовать синхронный подход, как показано на диаграмме, или асинхронный с помощью очереди сообщений между службами (в этом случае вы также можете использовать двухфазную фиксацию).

Преимущества и недостатки оркестровки

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

Преимущества

Координирует состояние разнородных распределенных компонентов.

Нет необходимости в транзакциях XA.

Известное распределенное состояние на уровне координатора.

Недостатки

Сложная модель распределенного программирования.

Может потребоваться идемпотентность и компенсационные операции от участвующих служб.

Возможны неисправимые отказы при компенсациях.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *