Каковы наиболее часто используемые распределенные транзакции? Что я должен использовать?

Java задняя часть Архитектура распределенный
Каковы наиболее часто используемые распределенные транзакции? Что я должен использовать?

Эта статья является первой подписанной статьей сообщества Nuggets, и ее перепечатка без разрешения запрещена.

распределенныйCAPТеория должна быть хорошо известна и она описывает непротиворечивость (C), доступность (A), допуск разделения (P) ряд компромиссов. Много раз нам приходится балансировать между согласованностью и доступностью, и распределенные транзакции должны максимально соответствовать требованиям согласованности в рамках этой большой предпосылки.

Цели маленькие, проблемы большие, а подходы разные.

«Как реализовать распределенные транзакции в микросервисах?» Обычно на такой вопрос я отвечаю «постарайтесь избегать использования распределенных транзакций», что такжеMartin Fowlerрекомендуемые. Но реальность всегда жестока.После разделения микросервисов распределенные транзакции являются очень жесткими требованиями, и их нельзя избежать.Мы все еще должны найти способ их реализовать. Однако распределенная среда сложна, и она также сопровождается тайм-аутами, вызванными состоянием сети, поэтому очень сложно добиться согласованного состояния транзакций.

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

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

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

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

1. Одноэтапная фиксация (1PC)

Давайте сначала рассмотрим простейший случай фиксации транзакции.

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

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

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

2. Двухэтапная фиксация (2PC)

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

2.1 Важные игроки

  1. Coordinator (координатор), то есть нам нужно построить свой менеджер транзакций, обычно в реальной системе он один
  2. Участники транзакции (участники) относятся к тому, что мы называем ресурсами, обычно их будет больше одного, иначе это не будет называться распределенной транзакцией

2.2 Процесс

В широком смысле, 2PC (двухфазная фиксация), что это за две фазы?

  1. clientИнициатор распределенной транзакции
  2. commit-request/votingэтап подготовки
  3. commit/rollbackфиксация или откат

image-20210910145356739.png

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

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

Двухфазную фиксацию на самом деле довольно легко понять. Вы можете думать о выполнении каждого участника как об обычном операторе обновления SQL. они были挂在Подождите, пока координатор не выдаст точное сообщение о фиксации или откате, и все будет выполнено в обычном режиме.

2.3 Проблемы

  1. проблема с блокировкой. Самая большая проблема с двухфазной фиксацией заключается в том, что это блокирующий протокол и он неэффективен. Если координатор выйдет из строя навсегда, некоторые участники никогда не смогут завершить свою транзакцию.
  2. Проблема единой точки отказа. Поскольку координатор играет очень важную роль во всем процессе, как только это происходитSPOF, вся система станет недоступной, что невыносимо
  3. Проблемы с целостностью транзакций. В некоторых случаях, например, после того, как координатор отправляет команду фиксации, возникает исключение, и часть выполнения завершается успешно, что приводит к несогласованности всей транзакции. Потому что, можно ли это представить или нет, решается на первом этапе, второй этап - это просто уведомление, вы должны представить его мне, даже если вы умрете.
  4. Не все ресурсы поддерживают 2PC (или XA)

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

2.4 Структура

2PC также называют транзакцией XA.Большинство баз данных, таких как MySQL, поддерживают протокол XA. В Java JTA (не JPA) является реализацией протокола XA. Spring также имеет диспетчер транзакций для JTA.

  • Atomikos и bitronix реализуют JTA, и им нужно только предоставить пакеты jar. Базы данных или очереди сообщений, реализующие протокол XA, имеют возможность подготовки, отправки и отката.
  • Используя такие фреймворки, как Seata, вам необходимо запустить независимый узел координатора службы Seata. AT, используемый Seata, с помощью внешнего менеджера транзакций, концепция аналогична XA.

3. Трехэтапная фиксация (3PC)

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

3.1 Важные игроки

3PC и 2PC одинаковы.

3.2 Процесс

3PC имеет на один шаг больше, чем 2PC, который является фазой запроса.

  1. Этап запроса CanCommit
  2. Предкоммитный этап подготовки
  3. Фаза фиксации DoCommit

image-20210914163846278.png

На этапе отправки это не что иное, как отправка команды фиксации или отката.Важная обработка все еще находится в стадии подготовки.3PC разделил ее на 2.

Обратите внимание на следующую переписку, 2PC и 3PC имеют этап подготовки, но их роли разные.

3PC					2PC
CanCommit			commit-request/voting
PreCommit 
DoCommit 			commit

Этап запроса 3PC соответствует этапу подготовки 2PC, он заключается в том, чтобы спросить, готовы ли участники, но в процессе выполнения будут некоторые отличия.

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

Например, есть 5 участников, таких как ABCDE, E на самом деле является проблемным ресурсом участника. Однако 2PC каждый раз будет выполнять предварительную отправку ABCD, при запросе E выясняется, что есть проблема, а затем по очереди выполняется откат ABCD и других участников. В этом случае ABCD выполняет бесполезную предварительную обработку транзакций и откат, что очень расточительно расходует ресурсы.

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

Кроме того, 3PC представила механизм тайм-аута. Если на этапе PreCommit истечет время ожидания, считается, что оно не выполнено; на этапе DoCommit, если время ожидания истекло, выполнение продолжится. Но в любом случае все дело не собирается ждать вечно.

3.3 Вопросы

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

3PC также не идеален, потому что этап PreCommit и DoCommit не являются атомарными, и, как и в 2PC, все еще есть проблемы с согласованностью.

4. TCC

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

2PC и 3PC кажутся простыми в концепции, но в распределенной среде, учитывая всевозможные проблемы с тайм-аутом и простоем, если их рассмотреть внимательно, это действительно смертельно опасно.

Фреймворков 2PC еще много, но 3PC перерыл всю сеть и обнаружил, что известных реализаций почти нет.

Не расстраивайтесь, мы распределили транзакции, которые проще для понимания и более интуитивно понятны. Это TCC, винтаж 2007 года.

TCC — это известная компенсационная транзакция, которая является наиболее часто используемой распределенной транзакцией в среде Интернета. Его основная идея заключается в следующем: для каждой операции подготовьте действие подтверждения и соответствующее действие компенсации, всего 3 метода.

Вместо того, чтобы полагаться на базу данных, полагайтесь на свой собственный код! 2PC, 3PC — все привязаны к базе данных, TCC — фаворит кодеров (это означает, что вам нужно писать больше кода).

image-20210914162640227.png

Как показано на рисунке, TCC также разделен на три этапа, но очень грубо!

  • попробуй попробуй этап Попытка заблокировать ресурс
  • подтвердить Этап подтверждения Попытка зафиксировать заблокированный ресурс
  • cancel Стадия отмены Одна из ссылок не может быть выполнена, и будет инициировано действие по отмене транзакции

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

TCC					2PC
Try					业务逻辑
Confirm 			commit-request/voting + commit
Cancel  			rollback

Как видно из вышеизложенного, 2PC — это разделение процесса транзакции, а TCC — это компенсация за представление нормальных условий и нештатных условий. По сравнению с традиционным кодом комбинация «попробуй» и «подтверди» представляет собой настоящую бизнес-логику.

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

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

Да, ему тоже нужно записывать какую-то информацию, даже в HashMap, иначе он откатывается по какому?

4.1 Вопрос

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

Команда должна быть в состоянии спроектировать интерфейс TCC, разделить его на правильные фазы Try и Confirm и внедрить классификацию бизнес-логики.

4.2 Структура

ByteTCC, tcc-транзакция, Seata и т. д.

5. SAGA

SAGA также является гибким делом.

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

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

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

Например, мы разделяем транзакцию T на T1, T2, T3 и T4. Затем мы должны предоставить соответствующие подтранзакции执行逻辑и补偿逻辑. Да, то же, что и TCC, но на один шаг меньше, чем TCCTry动作, что также требует, чтобы эти операции были идемпотентными.

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

Если вам нужно следовать его сути, то она заключается в том, что SAGA, как и TCC, сначала записывает траекторию выполнения, а затем достигает конечного состояния посредством непрерывных повторных попыток.

saga.png

Картинка вышеrob vettorНарисована типичная диаграмма разделения транзакций SAGA. На рисунке черная линия — обычный бизнес-процесс, а красная — компенсационный бизнес-процесс. Это простой процесс оформления заказа в электронной коммерции.Вся транзакция охватывает 5 микросервисов, что можно назвать очень большой и долгой транзакцией.

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

5.1 Вопрос

Этот вопрос более интересен.

  1. Вложенная проблема. SAGA допускает только два уровня вложенности, потому что очень сложно полагаться на поток сообщений, а уровень глубокой вложенности не допускается с точки зрения производительности и времени.
  2. Если ваша транзакция содержит много подтранзакций, очень вероятно, что на каком-то этапе выполнение завершится ошибкой. Но что, если операция компенсации тоже пошла не так? В крайних случаях требуется участие человека. Во многих случаях необходимо записывать журнал (журнал саги), чтобы сотрудничать с завершением.
  3. Поскольку эти небольшие транзакции не отправляются одновременно, в процессе выполнения будут генерироваться грязные данные, что совпадает с концепцией незафиксированного чтения в базе данных.

5.2 Структура

В четвертой главе «Шаблоны проектирования микросервисной архитектуры» объясняются конкретные примеры использования SAGA, и большинство статей в Интернете теперь основано на этом. Но, насколько я знаю, не так много интернет-компаний используют SAGA, а больше используют TCC (возможно, встречающиеся распределенные транзакции не являются длинными транзакциями).

Seata также предоставляет метод SAGA, в основном с использованием управляемого машиной состояния.编排模式. Для поддержки управления транзакциями Seata предоставляет специальный редактор процессов (онлайн).

http://seata.io/saga_designer/index.html

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

Хотя bytetcc называется tcc, он также поддерживает SAGA.

5.3 SAGA vs TCC

Как было сказано выше, в своей повседневной работе я использую TCC чаще, чем SAGA, что также определяется бизнес-сценарием. Ниже простое сравнение.

  1. Сложность развития. Сложность разработки TCC выше, чем у SAGA, потому что для замораживания ресурсов необходимо обрабатывать фазу Try, в то время как SAGA напрямую выполняет локальные транзакции.
  2. Проблема с грязным чтением. У TCC нет грязных чтений, потому что фаза попытки не влияет на данные; у SAGA будут грязные чтения между небольшими транзакциями или между отменами.
  3. вопросы эффективности. Вне зависимости от успеха или неудачи TCC, ему необходимо дважды взаимодействовать с участниками; SAGA взаимодействует один раз в нормальных условиях и дважды в ненормальных, поэтому эффективность выше.
  4. Бизнес-процесс. TCC подходит для небольшого количества распределенных транзакционных процессов, иначе писать будет кошмар; SAGA подходит для бизнесов с длинными бизнес-процессами и множеством участников, или бизнесов, которые нельзя трансформировать в TCC, например устаревшие системы
  5. означает. TCC решает технические проблемы с помощью бизнес-моделирования, SAGA решает вопросы согласования транзакций с помощью технических средств.

6. Локальная таблица сообщений

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

image-20210914152951547.png

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

  • 1.1 Запись в базу данных в обычном режиме
  • 1.2 Напишите локальную таблицу сообщений во время записи в базу данных. Эта таблица, используемая для записи состояния обработки сообщений MQ, может иметь发送中и已完成два состояния. Поскольку таблица сообщений и обычная бизнес-таблица находятся в одной БД, это может быть достигнуто本地транзакций, обеспечивающих одновременное завершение
  • 2 После успешной записи таблицы сообщений сообщение MQ может быть отправлено асинхронно, и вам не нужно заботиться об успешной доставке.
  • 3 Последующие службы подписываются на сообщения MQ. После успешного потребления статус успешного выполнения будет отправлен через MQ. Локальный бизнес подписывается на это состояние выполнения и изменяет соответствующее состояние записи в таблице сообщений на завершенное; если потребление не выполняется, не выполняйте слишком большую обработку.
  • 4 Существует заданная по времени задача, которая постоянно сканирует локальную таблицу сообщений, и состояние发送中сообщения (обратите внимание на задержку) и снова отправьте эти сообщения в MQ, повторите процесс 2

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

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

6.1 Вопрос

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

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

7. Вознаграждение за лучшие усилия

Компенсация наилучших усилий — это затухающий механизм компенсации.

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

Оплата WeChat + обработка результатов вашего платежа может рассматриваться как крупная распределенная транзакция. Система с участием WeChat также включает в себя вашу собственную систему.

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

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

messageDelayLevel = 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

Приведенная выше формула означает, что если Chen Gong не может быть обработан все время, он попытается повторить попытку через 1 с..., максимум через 2 часа. Если вы не вносите вклад, вы можете войти только в канал ручной обработки.

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

8. Резюме

В этой статье, начиная с местных дел, мы рассказали о 2PC, 3PC, TCC, SAGA, локальной таблице сообщений, компенсации лучших усилий и т. д., а также узнали о некоторых сценариях применения и решениях различных решений.

Фреймворк распределенных транзакций, основанный на этих теоретических основах, был более или менее пересмотрен, а также появилось много нововведений. Например, фреймворк LCN (блокировка, подтверждение, уведомление) абстрагирует понятия контроллера и инициатора, и те, кому это интересно, могут разобраться в нем сами.

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

Что касается фреймворка, широко используется сеата Али (в первые годы называвшаяся fescar), поддерживаются режимы XA, TCC, SAGA и др. Если вам нужна эта функция, вы можете интегрировать ее и попробовать.

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

Эта статья является первой подписанной статьей сообщества Nuggets, и ее перепечатка без разрешения запрещена.