спередистатья, мы представили связанные концепции компонента распределенных транзакций Ali с открытым исходным кодом Seata, сосредоточив внимание на режиме AT Seata. А на примере Spring-Cloud-JPA демонстрируется использование режима AT. В этой статье будет объединен случай Spring-Cloud-JPA, чтобы получить более глубокое понимание рабочего процесса режима Seata AT. Эта статья основана на v0.8.1.
Режим AT и режим TCC
Режим Seata AT разработан на основе режима двухэтапной фиксации и решает проблему распределенных транзакций, возникающую в сценарии микросервиса, эффективным и ненавязчивым способом. Это позволяет коду приложения использовать распределенные транзакции, такие как локальные транзакции, полностью скрывая основные детали Различия между режимом Seata AT и режимом Seata MT (TCC) заключаются в следующем:
- С точки зрения использования, TCC опирается на три метода, реализуемых пользователем с большими затратами; AT опирается на глобальные аннотации транзакций и прокси-источники данных, а остальную часть кода в основном не нужно изменять, без вмешательства в бизнес и минимальные затраты на доступ;
- Область действия TCC находится на прикладном уровне, который, по сути, предназначен для реализации прямых и обратных методов для определенной бизнес-логики; область действия режима AT заключается в базовом источнике данных, который выполняется путем сохранения моментальных снимков до и после записей строк операций. и создание обратных операторов SQL.Операцию компенсации сложно реализовать, и преимущество состоит в том, что она прозрачна для приложения верхнего уровня;
- TCC попробуйте только фазовую логику, независимую компенсационную логику между последующей транзакцией; в Globallock нуждается в справке глобального блокировки и записи аннотаций для разрешения конфликтов между различной глобальной транзакцией, если транзакция является успешным отделением ступени двухступенчатого начала глобального блокировки. И или надо оставаться до тех пор, пока филиал не пройдет двухступенчатая транзакция, чтобы завершить до выпуска глобального блокировки.
В режиме AT каждая база данных рассматривается как ресурс, который в Seata называется DataSource Resource. Когда бизнес обращается к ресурсам базы данных через стандартный интерфейс JDBC, платформа Seata перехватывает все запросы и выполняет некоторые операции. Когда каждая локальная транзакция фиксируется, Seata RM (менеджер ресурсов, менеджер ресурсов) регистрирует транзакцию филиала в TC (координатор транзакций, координатор транзакций). Когда вызов запроса связи завершен, инициатор уведомляет TC о необходимости отправить или откатить распределенную транзакцию и перейти к процессу вызова второй фазы. В этот момент TC перезвонит соответствующему участнику для выполнения второго этапа соответствующего ресурса в соответствии с ранее зарегистрированной транзакцией перехода. Как TC находит соответствие между транзакциями филиала и ресурсами? Каждый ресурс имеет глобально уникальный идентификатор ресурса, и этот идентификатор используется для регистрации ресурса в TC во время инициализации. Во время выполнения каждая транзакция филиала регистрируется со своим идентификатором ресурса. Таким образом, TC может правильно найти соответствующий ресурс во время вызова второй фазы.
Что касается использования режима AT, я не буду здесь вдаваться в подробности, в основном отмечу следующие моменты:
- Добавить глобальные аннотации транзакций
@GlobalTransactional
: Добавлен бизнес-метод всего распределенного инициатора транзакции; - Настроить прокси-источник данных: настроить прокси-источник данных Seata.
- Создайте новую таблицу UNDO_LOG: Новая таблица Undo_log в базе данных, участвующая в ссылке транзакции, для хранения информации об отмене, используемой для двухэтапной операции отката, таблица, содержащая информацию о ключевых полях, такую как XID, BRANCHID, ROLLBACK_INFO.
Введение в архитектуру и принципы реализации режима AT
Распределенная транзакция — это глобальная транзакция, состоящая из нескольких транзакций филиалов.Режим Seata AT включает в себя следующие два этапа:
- Фаза 1: выполнение форк (локальной) транзакции. Локальная транзакция используется как ветка распределенной транзакции, поэтому несколько локальных транзакций, распределенных по разным микросервисам, вместе образуют глобальную транзакцию, структура ее следующая.
- Фаза 2: транзакция ветки фиксируется или откатывается. Фаза 2 завершает окончательную фиксацию или откат глобальной транзакции. Когда все транзакции ветвей в глобальной транзакции завершены и выполнены успешно, TM инициирует фиксацию глобальной транзакции. После того, как TC получит сообщение о фиксации глобальной транзакции, он уведомит каждую Транзакция ответвления фиксируется; аналогичным образом, когда все транзакции ответвления в глобальной транзакции завершаются, а транзакция ответвления терпит неудачу, TM уведомляет TC о необходимости координировать откат глобальной транзакции, а затем TC уведомляет каждую транзакцию ответвления о выполнении отката. назад.
В процессе запуска бизнес-приложения, благодаря внедрению клиента Seata, RmRpcClient будет запущен вместе с приложением. RmRpcClient реализован в Netty и может получать сообщения TC и отправлять сообщения TC. Поэтому RmRpcClient ключевой модуль для отправки и получения сообщений с ТС.
Общий процесс реализации распределенных транзакций в Seata выглядит следующим образом:
- TM Уведомить TC начать новую глобальную транзакцию. TC XID генерируется от имени глобальной транзакции.
- XID распространяется по цепочке вызовов микрослужбы.
- RM регистрирует локальную транзакцию как ответвление соответствующей глобальной транзакции XID для TC.
- TM уведомляет TC о необходимости фиксации или отката глобальной транзакции, соответствующей XID.
- TC управляет всеми транзакциями ветвей в соответствии с соответствующей глобальной транзакцией XID для завершения фиксации или отката ветвления.
одностадийный процесс
На первом этапе Seata перехватит бизнес-SQL, сначала проанализирует семантику SQL, найдет бизнес-данные для обновления с помощью бизнес-SQL и сохранит бизнес-данные какbefore image
, а затем выполните бизнес-SQL для обновления бизнес-данных. После обновления бизнес-данных сохраните их какafter image
и, наконец, генерируйте блокировку строки. Вышеуказанные операции все завершены в рамках транзакции базы данных, что обеспечивает атомность одноступенчатых операций.
Конкретная работа отраслевой транзакции в одну фазу выглядит следующим образом:
- Создайте соответствующий SqlRecognizer в соответствии с типом SQL (UPDATE, INSERT, DELETE), который необходимо выполнить.
- Создайте соответствующий SqlExecutor
- Введите базовую логику для запроса моментальных снимков данных до и после, таких как часть, отмеченная красным на рисунке, после получения моментальных снимков измененной строки данных до и после, объедините их для создания UndoLog и попытайтесь отправить это и модификация бизнеса в одной и той же сделке.
С точки зрения реализации, Seata инкапсулирует источник данных в качестве прокси, а затем операция обработки источника данных завершается внутренней логикой Seata. Как и в конфигурации загрузки источника данных в нашем предыдущем примере:
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Primary
@Bean("dataSource")
public DataSource dataSource(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}
Мы видим, мы используем DataSourceProxyproxyproxyproxyproxyProxyproxyprox. Когда инициализация данных DataSourceProxy будет Resouce Registranting:
private void init(DataSource dataSource, String resourceGroupId) {
this.resourceGroupId = resourceGroupId;
Connection connection = dataSource.getConnection()
jdbcUrl = connection.getMetaData().getURL();
dbType = JdbcUtils.getDbType(jdbcUrl, null);
DefaultResourceManager.get().registerResource(this);
}
На самом деле существует три типа прокси в прокси-части источника данных.Помимо инкапсуляции DataSource базы данных, Seata также инкапсулирует прокси Connection и Statement, а именно ConnectionProxy и StatementProxy.
Двухэтапный процесс фиксации
Второй этап режима AT будет решать, выполнять ли глобальную фиксацию или глобальный откат в соответствии с ситуацией на первом этапе. Для сервера, после завершения первого этапа и отсутствия исключения, инициатор глобальной транзакции обратится к серверу с просьбой отправить глобальную транзакцию, и сервер заблокирует и закроет глобальную транзакцию после запроса глобальной транзакции в соответствии с xid Последующие ветки транзакции продолжают регистрироваться, и в то же время ее статус меняется с Begin на Committing.
Затем определяется, являются ли типы ветвей в рамках глобальной транзакции всеми типами AT.Если это так, сервер выполнит асинхронную отправку, поскольку данные, завершенные на следующем этапе режима AT, уже поступили. Сервер только изменяет статус глобальной транзакции на AsyncCommitting, а затем будет создан пул синхронизированных потоков для запроса журнала глобальных транзакций, который будет отправлен на носитель данных (файл или базу данных) для отправки.Если глобальная транзакция успешно отправлена, глобальная блокировка будет снята, и транзакция будет удалена. Весь процесс показан на рисунке ниже:
Если все ответвления RM выполнены успешно, выполните глобальную фиксацию. Поскольку на данный момент нам не нужно выполнять откат, а работа с локальной базой данных каждой ветки завершена, то главное, что мы фактически делаем, — это удаляем локальный Undolog.
Для клиента сначала получите запрос на фиксацию ветки, отправленный сервером, затем клиент найдет соответствующий ResourceManager в соответствии с resourceId, а затем инкапсулирует запрос на фиксацию ветки в Phase2Context и вставит его в очередь памяти ASYNC_COMMIT_BUFFER, у клиента будет пул временных потоков, к которому нужно перейти. Запросите очередь для асинхронного удаления UndoLog.
Как только клиент не сможет отправить или истечет время ожидания RPC, сервер установит глобальный статус транзакции в CommitRetrying, а затем другой пул потоков с синхронизацией будет повторять эти транзакции до тех пор, пока они не завершатся успешно.
Двухэтапный процесс отката
Если второй этап представляет собой откат, Seata необходимо выполнить откат бизнес-SQL, который был выполнен на первом этапе, чтобы восстановить бизнес-данные. Метод отката заключается в использованииbefore image
Восстановите бизнес-данные, но перед восстановлением вы должны сначала проверить грязные записи, сравнить текущие бизнес-данные в базе данных иafter image
, если две части данных полностью согласованы, это означает, что грязные записи отсутствуют, и бизнес-данные можно восстановить.
Откат относительно сложный. Если инициатор бросает исключение в одном этапе, он запросит сервер, чтобы отбросить глобальную транзакцию. Сервер будет запрашивать глобальную транзакцию в соответствии с XID, и блокировать транзакцию, чтобы закрыть транзакцию, так что В будущем больше нет ветвей. В то же время изменить его состояние начинает откатиться, а затем выполнить синхронный откат, чтобы обеспечить консистенцию данных. За исключением точки синхронного отката, другие процессы аналогичны Commit. Если синхронный откат успешна, глобальный замок будет выпущен, и журнал транзакций будет удален. Если это не удастся, он будет получен асинхронно.
Клиент получает от сервера запрос на откат ветки, сначала получает соответствующий агент источника данных в соответствии с идентификатором ресурса, затем запрашивает запись UndoLog в соответствии с идентификатором xid и идентификатором ветки и десериализует поле отката, чтобы получить моментальный снимок до и после данных. Мы называем эту глобальную транзакцию для A.
Создайте соответствующий UndoExecutor в соответствии с конкретным типом SQL и проверьте, согласуются ли снимки до и после в данных UndoLog или предыдущий снимок согласуется с текущими данными (здесь требуется SELECT). требуется операция отката. Обратный SQL компенсирует это. Прежде чем отправлять локальную транзакцию, он определяет, успешно ли получена локальная блокировка базы данных. Если это не удается, это означает, что существует другая глобальная транзакция (при условии, что она называется B), которая изменение одной и той же строки в одну фазу, но из-за первичного ключа этих строк. Сервер был заблокирован глобальной транзакцией A, которая в настоящее время выполняет двухэтапный откат. Таким образом, первая фаза пытается получить глобальную блокировку до того, как локальная фиксация должна завершиться неудачно, и глобальная транзакция B снимет локальную блокировку, когда глобальная блокировка истечет, так что глобальная транзакция A сможет продолжить отправку локальной транзакции и удалить локальную запись UndoLog после успеха.
резюме
В этой статье в основном представлен рабочий процесс клиента и сервера Seata в режиме AT. Первая фаза, вторая фаза фиксации и откат режима AT автоматически генерируются платформой Seata. Пользователям нужно только написать бизнес-SQL, чтобы легко получить доступ к распределенным транзакциям. Режим AT — это решение для распределенных транзакций без какого-либо вмешательства в бизнес. . В начале следующей статьи будет подробно объяснена реализация режима AT в сочетании с исходным кодом.