Транзакция относится к объединению всех операций в неделимую исполнительную единицу.Все операции в транзакции либо выполняются, либо не выполняются вообще.Это популярное понимание транзакции.
Вообще говоря, транзакции предназначены для баз данных, но это не так. Некоторые очереди сообщений, такие как RocketMq, kafka и т. д., также будут включать транзакции.Эти компоненты имеют специальный термин, называемый диспетчером ресурсов (RM).
Распределенная транзакция - это новая концепция, полученная в результате все более широкого применения распределенных систем. Обычно она относится к RM на разных узлах. Сегодня, когда популярны микросервисы, распределенные транзакции становятся все более и более достойными использования, которым придается большое значение.
местные дела
В этой статье мы хотим представить распределенные транзакции, но если говорить о распределенных транзакциях, локальные транзакции — это еще одна тема, которой нельзя избежать, поэтому давайте быстро рассмотрим концепции локальных транзакций.
ACID
ACID — это четыре характеристики, которыми должна обладать транзакция, среди них:
1. A是指原子性. 是指一个操作必须是一个不可分割的单元, 要么执行要么不执行, 不能存在指执行了一半,另外一半没执行的状态
2. C是指一致性. 是指事务执行前后,系统都处在一个一致性的状态.
3. I是指隔离性. 隔离性是指不同事务之间应该互相隔离,不受影响
4. D是持久性, 表示事务的执行应该是永久性的, 不能因为系统重启或奔溃就丢失
В общем, I в ACID ведет к другому набору понятий: проблемам видимости и уровням изоляции.
Проблемы видимости относятся к проблемам, вызванным видимостью операций в рамках одной транзакции в другой транзакции.Вообще говоря, чем выше видимость, тем больше вероятность возникновения проблем.
От высокой до низкой видимости проблемы следующие:
1. 读未提交. 一个事务能读到另外一个事务未提交的更改.这是最严重的问题的,未提交的数据都是脏数据.
2. 不可重复读. 所谓的不可重复读是指一个事务第一次读某条记录
和第二次读同一条记录时会读到不一样的内容.
原因是该事务在这两次读之间, 有另外一个事务更新了这条记录,并且提交了.
3. 幻读. 所谓幻读是指一个事务在两次读同一份数
据时, 第一次和第二次读到的数量不一样. 原因是该事务在这两次读之间,
有另外一个事务新增/删除了记录, 并提交了.
可以看到, 其实不可重复读和幻读都是由于另外一个事务更改了数据造成的.
两者的差别是另外一个事务的操作是update还是insert/delete
Уровень изоляции и проблема видимости находятся в гармонии, и каждый уровень изоляции существует для решения проблемы видимости.
Уровни изоляции следующие:
1. 读未提交. 这是最低级别的隔离等级, 很明显,什么可见性问题都没解决.
2. 读已提交. 解决了"读未提交"的问题
3. 可重复读. 解决"不可重复读"的问题
4. 串行化, 解决了"幻读"的问题.
Конечно, более высокий уровень изоляции означает более низкую пропускную способность для обработки данных.
транзакции в mysql
В mysql вы можете использовать три инструкции: начало, фиксацию и откат для реализации транзакций.
1. begin用来开始一个事务.
2. commit 用来提交一个事务
3. rollback用来回滚一个事务
Транзакции MySQL автоматически фиксируются по умолчанию.Вы можете использовать
set autocommit = 0
或
set autocommit = 1
отключить/включить автокоммит.
Стоит отметить, что уровень изоляции mysql по умолчанию — «повторяемое чтение», но более высокая версия innodb (mysl5.7) фактически достигает стандарта «сериализации» за счет блокировок пробелов.
сделки весной
Если Spring поддерживает операции транзакций, но операции транзакций в Spring на самом деле являются просто агентами, которые в конечном итоге реализуются, полагаясь на начало, фиксацию и откат базы данных.
Программные транзакции
Программные транзакции относятся к транзакциям, которые вручную управляют фиксацией и откатом через transactionTemplate и TransactionManager.
По сравнению с декларативными транзакциями программные транзакции более гибкие, например, их можно зафиксировать или откатить для определенного сегмента кода.
Декларативные транзакции (прокси)
В общем, декларативные транзакции являются аннотационными транзакциями.Транзакция объявляется путем добавления аннотации Spring @Transactional к методу или классу, отсюда и название «декларативная транзакция».
Обычно используемые параметры @Transactional:
1. propagation, 指定事务的传播等级
2. isolation, 指定隔离等级
3. norollback for, 指定不回滚事务的异常
4. rollback for, 指定需要回滚事务的异常
5. timeout, 指定事务的超时时间
Принцип декларативной транзакции — это динамический прокси и АОП, проще говоря, это добавление логики начала, фиксации и отката до и после выполнения конкретных методов.
Самым большим преимуществом декларативных транзакций является то, что они просты и менее навязчивы для кода.Соответствующий недостаток заключается в том, что степень детализации нелегко контролировать, и к методу необходимо добавить наименьшую степень детализации.
Распространение транзакций (вложенные транзакции)
Вообще говоря, распространение транзакций — это цепочка вызовов нескольких методов.Если задействована вложенность транзакций, как Spring должен с этим справиться.
Эта концепция также вытекает из принципа декларативной транзакции Принцип декларативной транзакции заключается в добавлении логики открытия транзакции и фиксации транзакции до и после метода с помощью динамического прокси.
Предположим, что существует один из следующих сценариев:
@Transational
public void A(){
B();
// do something
}
@Transational
public void B(){
//dosomething
int a = 1/0
}
Вышеупомянутые два метода объявляют об открытии транзакции. Очевидно, B выдаст исключение, и транзакция B будет отброшена. Затем также будет откатан A. Это должно быть решено механизмом распространения транзакции .
В Spring существует 7 типов механизмов распространения транзакций:
1. propagation_require. 默认的传播类型. 表示当前方法需要再一个事务中执行, 如果没有开启事务, 则需要开启一个
2. propagation_support. 表示当前方法不需要事务, 但是如果事务存在,则在事务中执行
3. propagation_mandatory. 表示当前方法必须要在事务中执行, 如果不存在,则抛出异常.
4. propagation_requireNew. 表示当前方法需要在新的事务中执行.当前方法执行时, 如果已经存在一个事务, 则先挂起该事务
5. propagation_not_support. 表示当前方法不支持事务, 如果已经存在事务, 那就先挂起该事务.
6. propagation_never. 表示当前方法不应该在事务中执行, 如果存在事务, 则抛异常.
7. propagation_nested. 如果存在嵌套的事务, 那么各个方法在各自独立的方法里面提交和回滚.
Распределенная транзакция
DTP, XA и JTA
Модель ПДП
DTP (распределенная обработка транзакций) — это модель распределенных транзакций, предложенная организацией x/open.
Модель DTP содержит как минимум три следующих элемента:
1. AP, 应用程序,用于定义事务开始和结束的边界. 说人话就是我们开启事务的代码所以的应用.
2. RM, 资源管理器. 理论上一切支持持久化的数据库资源都可以是一个资源管理器.
3. TM, 事务管理器, 负责对事务进行协调,监控. 并负责事务的提交和回滚.
ХА Спецификация
XA — это спецификация распределенных транзакций, предложенная x/open и не зависящая от языка.
Спецификация XA определяет интерфейс для взаимодействия между RM и TM, например, TM может управлять RM через следующие интерфейсы:
1. xa_open和xa_close, 用于跟RM建立连接
2. xa_star和xa_end, 开始和结束一个事务
3. xa_prepare, xa_commit和xa_rollback, 用于预提交, 提交和回滚一个事务
3. xa_recover 用于回滚一个预提交的事务
Спецификация JTA
Спецификация JTA — это спецификация, которую можно рассматривать как версию реализации языка Java спецификации XA.
JTA определяет серию интерфейсов, связанных с распределенными транзакциями:
1. javax.transaction.Status: 定义了事务的状态,例如prepare, commit rollback等等等
2. javax.transaction.Synchronization:同步
3. javax.transaction.Transaction:事务
4. javax.transaction.TransactionManager:事务管理器
5. javax.transaction.UserTransaction:用于声明一个分布式事务
6. javax.transaction.TransactionSynchronizationRegistry:事务同步注册
7. javax.transaction.xa.XAResource:定义RM提供给TM操作的接口
8. javax.transaction.xa.Xid:事务id
Вышеуказанные разные интерфейсы реализуются разными ролями (RM, RM и т. д.).
Двухэтапная фиксация (2PC)
Двухфазная фиксация — это простейшее решение для распределенных транзакций, которое делит транзакцию на две фазы: фиксация запроса и фиксация/откат.
Первый этап - это этап запроса. Координатор спрашивает всех RM, можно ли отправить транзакцию. Если она может быть отправлена, он ответит ДА, в противном случае он ответит НЕТ.
Вторая фаза - фаза фиксации.Координатор решает, может ли распределенная транзакция быть зафиксирована в соответствии с ответами всех RM.Если все RM ответили ДА, транзакция может быть зафиксирована, в противном случае транзакция откатывается.
Хотя идея двухфазного коммита проста, у него много проблем.
- Задача координатора с одной точкой
- Проблема блокировки первой ступени
- На втором этапе из-за проблем с сетью RM не получил команду фиксации/отката, что привело к несогласованности данных.
Трехфазная фиксация (3PC)
Для решения проблем, существующих в двухфазном алгоритме, предлагается трехфазная фиксация, которая делит фиксацию транзакции на три фазы:
1. cancommit阶段, 和2PC中的请求阶段类似
2. precommit阶段. 如果cancommit阶段不是全部响应YES或者有RM超时, 那么回滚整个事务.
否则, 发送precommit指令, 让各个RM执行事务操作,执行完后响应ACK.
3. docommit阶段.如果precommit阶段由RM没有响应ACK或者超时, 那么回滚整个事务.
否则发送docommit指令, 让各个RM真正提交事务.
TCC
TCC расшифровывается как try-comfirm-cancel и представляет собой гибкое решение для распределенных транзакций, популярное на протяжении многих лет.
Так называемые «гибкие» относятся к «жестким транзакциям», таким как 2PC и 3PC. Гибкие транзакции больше не преследуют строгой согласованности вслепую, а требуют только возможной согласованности.
TCC разделяет распределенную транзакцию на следующие три этапа:
1. try阶段. 各个事务参与者检查业务一致性, 预留系统资源.例如锁定库存
2. comfirm阶段. 事务参与者使用try阶段预留的资源,执行业务操作.
3. cancel阶段. 如果try阶段任意一个事务参与者try失败, 则做cancel操作. cancel包括释放资源和反向补偿
На самом деле, если присмотреться, T-C-C как раз соответствует запросу-фиксации-откату в 2PC один к одному, с этой точки зрения TCC по сути является решением 2PC.
В TCC также есть две концепции: главная бизнес-служба и подчиненная бизнес-служба.
Под основной бизнес-службой обычно понимается служба, которая инициирует транзакцию. Например, служба покупки вызывает соответственно службу инвентаризации и службу заказа. Тогда службу покупки можно рассматривать как основную бизнес-службу.
Соответственно, упомянутые выше «служба инвентаризации» и «служба заказа» относятся к бизнес-службам.
Зачем различать эти две службы в первую очередь, потому что их обязанности различны:
1. 从业务服务必须要提供try, comfirm, cancel方法.
2. 主业务服务需要记录事务日志, 并在事务管理器的协调下, 适当地调用从业务服务的tcc三个方法.
Модель TCC показана на следующем рисунке:
Изображение извоооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо, а также очень рекомендую этот блог, много пользы.
очередь сообщений
Использование очередей сообщений для достижения конечной согласованности — еще одна идея гибких распределенных транзакций.Его основная идея заключается в асинхронном завершении распределенной транзакции через очереди сообщений в сочетании с синхронизированными задачами для повторных попыток и компенсации и требует ручного вмешательства при необходимости.
Подводя итог, можно сказать, что есть три идеи: «уведомление о лучших усилиях», «локальная таблица сообщений» и «сообщение о транзакции MQ».
сделать все возможное, чтобы уведомить
Уведомление с наилучшими усилиями означает, что активная уведомляющая сторона сделает все возможное, чтобы уведомить получателя о результате обработки.Если уведомление не удалось, оно попытается повторить не более X раз.Если в конце все еще не удается, активная сторона предоставляет интерфейс для запроса, который может быть инициирован получателем.
Этот тип мышления является самым простым, и на самом деле он применяется во многих случаях.Типичные из них:
1. 运营商短信发送状态回传
2. 微信和支付宝支付状态回传
локальная таблица сообщений
Как следует из названия, локальная таблица сообщений использует локальную базу данных для поддержания промежуточного состояния завершения транзакции.Во время выполнения распределенной транзакции все участники транзакции обновляют состояние таблицы сообщений после завершения операции и постепенно завершают общее состояние. сделка.
В нештатных ситуациях незавершенная транзакция в таблице сообщений регулярно обнаруживается системой планирования времени и инициируется повторная попытка.6 поз для выполнения задач на время в Java
Если в конце концов одна из сторон не сможет завершить транзакционную операцию, это будет компенсировано ручным вмешательством.
Если есть картинка выше:
1. 生产者先写本地消息表和业务数据, 用本地事务保证成功.再发送MQ消息.
2. 消费者消费数据,同样是执行本地事务. 成功后更新本地消息表的状态. 失败怎么办呢? 可以发送消息给生产者进行回滚, 但是那样复杂度
就高了(要求生产者也要实现TCC, 那就还不如用TCC了). 所以更现实的方案是重现+人工补偿
3. 生产者可能会写业务数据成功, 但是发送MQ消息失败, 这个时候本地消息表还是会有对应未完成的事务, 那么定时任务会扫描出来, 重试.最终还是能完成整个分布事务.
Конечно, картинка выше не идеальна на 100%. Однако локальная таблица сообщений — это скорее идея, и конкретная реализация может быть другой, и ее следует реализовывать в сочетании с конкретными бизнес-сценариями и бизнес-требованиями.
Сообщение транзакции MQ
Схема локальной таблицы сообщений была предложена, когда MQ вообще не реализовывал сообщения о транзакциях, но теперь и kafka, и RocketMQ начали поддерживать сообщения о транзакциях.
Фактически, в случае сообщений о транзакциях работа локальных таблиц и задач синхронизации выполняется механизмом транзакций MQ.
НапримервооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооОписанные в нем программы.
Платформа распределенных транзакций
В практических приложениях сценарии распределенных транзакций можно разделить на два типа.Если взять в качестве примера услугу покупки, то эти два сценария распределенных транзакций могут быть:
- Первый заключается в использовании нескольких RM в одном сервисе.
- Во-вторых, служба вызывает несколько служб через RPC, косвенно управляя несколькими RM.
Сегодня, с ростом популярности микросервисов, подбиблиотека по бизнесу должна быть основным принципом для большинства компаний при построении своей архитектуры, поэтому с этой точки зрения второй сценарий кажется более реалистичным.
Конечно, первый сценарий все еще должен существовать.Например, в решении «локальной таблицы сообщений» выше необходимо взаимодействовать с несколькими RM в одном и том же сервисе.
На самом деле существует довольно много фреймворков с открытым исходным кодом для распределенных транзакций, таких как tcc-transactio и т. д. Здесь мы рассмотрим атомикос и сеата.
atomikos
atomikos — очень известный фреймворк с открытым исходным кодом для распределенных транзакций.Он имеет реализацию спецификации JTA/XA и реализацию механизма TCC.Первый бесплатный и с открытым исходным кодом, а второй — коммерческая платная версия.
Вот введение в реализацию спецификации JTA/XA.
В разделе спецификации JTA выше упоминалось, что JTA определяет серию интерфейсов, и эти интерфейсы реализуются разными ролями Роль атомикоса — это менеджер транзакций, а интерфейсы, которые он реализует, в основном включают:
1. javax.transaction.UserTransaction
对应的实现是com.atomikos.icatch.jta.UserTransactionImp,用户只需要直接操作这个类就是实现一个JTA分布式事务
2. javax.transaction.TransactionManager
对应的实现是com.atomikos.icatch.jta.UserTransactionManager, atomikos使用这个实现类来对事务进行管理
3. javax.transaction.Transaction
对应的实现是com.atomikos.icatch.jta.TransactionImp
Простой пример применения атомикоса (опять же извоооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо):
- импортировать зависимости
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>4.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
- демонстрационный экземпляр
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
public class AtomikosExample {
private static AtomikosDataSourceBean createAtomikosDataSourceBean(String dbName) {
// 连接池基本属性
Properties p = new Properties();
p.setProperty("url", "jdbc:mysql://localhost:3306/" + dbName);
p.setProperty("user", "root");
p.setProperty("password", "your password");
// 使用AtomikosDataSourceBean封装com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
//atomikos要求为每个AtomikosDataSourceBean名称,为了方便记忆,这里设置为和dbName相同
ds.setUniqueResourceName(dbName);
ds.setXaDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
ds.setXaProperties(p);
return ds;
}
public static void main(String[] args) {
AtomikosDataSourceBean ds1 = createAtomikosDataSourceBean("db_user");
AtomikosDataSourceBean ds2 = createAtomikosDataSourceBean("db_account");
Connection conn1 = null;
Connection conn2 = null;
PreparedStatement ps1 = null;
PreparedStatement ps2 = null;
UserTransaction userTransaction = new UserTransactionImp();
try {
// 开启事务
userTransaction.begin();
// 执行db1上的sql
conn1 = ds1.getConnection();
ps1 = conn1.prepareStatement("INSERT into user(name) VALUES (?)", Statement.RETURN_GENERATED_KEYS);
ps1.setString(1, "tianshouzhi");
ps1.executeUpdate();
ResultSet generatedKeys = ps1.getGeneratedKeys();
int userId = -1;
while (generatedKeys.next()) {
userId = generatedKeys.getInt(1);// 获得自动生成的userId
}
// 模拟异常 ,直接进入catch代码块,2个都不会提交
// int i=1/0;
// 执行db2上的sql
conn2 = ds2.getConnection();
ps2 = conn2.prepareStatement("INSERT into account(user_id,money) VALUES (?,?)");
ps2.setInt(1, userId);
ps2.setDouble(2, 10000000);
ps2.executeUpdate();
// 两阶段提交
userTransaction.commit();
} catch (Exception e) {
try {
e.printStackTrace();
userTransaction.rollback();
} catch (SystemException e1) {
e1.printStackTrace();
}
} finally {
try {
ps1.close();
ps2.close();
conn1.close();
conn2.close();
ds1.close();
ds2.close();
} catch (Exception ignore) {
}
}
}
}
Очевидно, что этот пример относится к распределенной транзакции сценария 1. Таким образом, если есть распределенная транзакция сценария 1, вы можете использовать атомикос напрямую, что просто, прямолинейно и эффективно.
Но опять же, распределенные транзакции в реальном сценарии больше похожи на сценарий 2. Очевидно, что простая транзакция JTA не может обрабатывать распределенную транзакцию в сценарии 2. Распределенная транзакция в сценарии 2 должна быть Решениями, такими как TCC или очередь сообщений. гибкие транзакции для реализации.
seata
Seata — это платформа решения для распределенных транзакций с открытым исходным кодом после интеграции Fescar (TXC/GTC/FESCAR) и tcc-transaction.
Официальный адрес сайтаЦвет ах хе.IO/this-talent/docs/…, документация относительно неполная, но ее достаточно для понимания.Вот краткое введение.
период, термин
TC - координатор сделки Поддерживайте состояние глобальных транзакций и транзакций филиалов, а также управляйте фиксацией или откатом глобальных транзакций.
ТМ – Менеджер транзакций Определите область действия глобальной транзакции: запустите глобальную транзакцию, зафиксируйте или откатите глобальную транзакцию.
РМ - менеджер ресурсов Управляйте ресурсами для обработки транзакций филиала, общайтесь с TC, чтобы регистрировать транзакции филиала и сообщать о состоянии транзакций филиала, а также управлять фиксацией или откатом транзакций филиала.
В режиме
АТ это Автоматическая Транзакция, так называемый АВТО, что означает, что этот режим ненавязчив к бизнесу и не требует трансформации бизнеса.Но к бизнесу есть требования:
1. 基于支持本地 ACID 事务的关系型数据库。
2. Java 应用,通过 JDBC 访问数据库。
Общая логика режима АТ следующая:
Режим AT также принимает идею 2PC, добавляя механизм компенсации, аналогичный журналу отмен в innodb.
Журнал отмен на самом деле является обратной компенсацией, такой как оператор вставки, когда транзакция откатывается, будет выполнен соответствующий оператор удаления
Перевод шаблона на местный язык (мое понимание):
1. 第1阶段, 先生成undo日志, undo日志和业务的操作在本地事务中一并提交
2. 第2阶段, 在TC的协调下, 如果可以提交则迅速提交. 需要回滚时根据回滚日志做反向补偿.
Конечно, конкретное приложение не так просто, больше справкиОфициальный сайт
режим ТСС
Режим TCC - это идея TCC, представленная выше. Режим tcc SEATA выглядит следующим образом:
Режим TCC на самом деле похож на режим AT. Это также усовершенствованная версия 2PC. Под координацией координатора транзакций (TC) фиксируются и откатываются несколько подтранзакций.
Разница заключается в том, что откат в режиме AT является компенсацией на уровне ресурсов базы данных (выполнение журнала отката), а TCC — вызов пользовательской логики для отката (выполнение логики кода отката).
Режим САГА
Saga — это решение для долгосрочных транзакций.В режиме Saga каждый участник бизнес-процесса отправляет локальную транзакцию, а в случае отказа участника предыдущие успешные участники получают компенсацию.Переадресация на первом этапе и компенсация на втором этапе услуги реализуются по развитию бизнеса
Хотя идея саги была выдвинута в 1987 году, модель саги сеата была официально поддержана в августе этого года.Я недостаточно глубоко в ней разбираюсь, поэтому на уроках в нее не играю.Просто знайте.
Суммировать
Распределенные системы никогда не были простой концепцией, особенно распределенные транзакции в распределенных системах.
Возможно, идея распределенных транзакций относительно проста, но действительно есть много деталей и трудностей в реализации, на которые необходимо обратить внимание и преодолеть.Поэтому большинство компаний, работающих с данными, будут использовать разные практики в соответствии с их реальными условиями ведения бизнеса, а не полностью копировать идеи.
Другой стороной этого является то, что на рынке действительно нет полного распределенного решения, и мы можем просто скопировать его. Сеата Али скоро будет с открытым исходным кодом. Я надеюсь, что однажды она действительно сможет объединить реки и озера. проблема распределенных транзакций в режиме «одного окна» и «одного окна».
Цитировать
воооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо