一僧凤、如何理解分布式事務
在傳統(tǒng)的關系型數(shù)據(jù)庫中畜侦,事務是一個標準組件,幾乎所有成熟的關系型數(shù)據(jù)庫都提供了對本地事務的原生支持躯保。本地事務提供了 ACID 事務特性旋膳。基于本地事務途事,為了保證數(shù)據(jù)的一致性验懊,我們先開啟一個事務后,才可以執(zhí)行數(shù)據(jù)操作尸变,最后提交或回滾就可以了义图。更進一步,借助于 Spring 等集成化框架召烂,開發(fā)人員只需關注引起數(shù)據(jù)改變的業(yè)務即可碱工。
但在分布式環(huán)境下,事情就會變得比較復雜奏夫。假設系統(tǒng)中存在多個獨立的數(shù)據(jù)庫怕篷,為了確保數(shù)據(jù)在這些獨立的數(shù)據(jù)庫中保持一致,我們需要把這些數(shù)據(jù)庫納入同一個事務中桶蛔。這時本地事務就無能為力了匙头,我們需要使用分布式事務。
業(yè)界關于如何實現(xiàn)分布式事務也有一些通用的實現(xiàn)機制仔雷,例如支持兩階段提交的 XA 協(xié)議以及以 Saga 為代表的柔性事務蹂析。針對不同的實現(xiàn)機制,也存在一些供應商和開發(fā)工具碟婆。因為這些開發(fā)工具在使用方式上和實現(xiàn)原理上都有較大的差異性电抚,所以開發(fā)人員的一大訴求在于,希望能有一套統(tǒng)一的解決方案能夠屏蔽這些差異竖共。同時蝙叛,我們也希望這種解決方案能夠提供友好的系統(tǒng)集成性。
ShardingSphere 作為一款分布式數(shù)據(jù)庫中間件公给,勢必要考慮分布式事務的實現(xiàn)方案借帘。而在設計上,ShardingSphere 從一開始就充分考慮到了開發(fā)人員的這些訴求淌铐。
二肺然、ShardingJdbc 分布式事務
sharding-jdbc分布式事務支持:官網(wǎng)https://shardingsphere.apache.org/document/current/cn/features/transaction/
ShardingSphere 中的分布式事務
在 ShardingSphere 中,除本地事務之外腿准,還提供針對分布式事務的兩種實現(xiàn)方案际起,分別是 XA 事務和柔性事務。這點可以從事務類型枚舉值 TransactionType 中得到驗證:
public enum TransactionType {
LOCAL, XA, BASE
}
1、本地事務
在不開啟任何分布式事務管理器的前提下街望,讓每個數(shù)據(jù)節(jié)點各自管理自己的事務校翔。 它們之間沒有協(xié)調以及通信的能力,也并不互相知曉其他數(shù)據(jù)節(jié)點事務的成功與否灾前。 本地事務在性能方面無任何損耗防症,但在強一致性以及最終一致性方面則力不從心。
2豫柬、兩階段提交:
XA協(xié)議最早的分布式事務模型是由 X/Open 國際聯(lián)盟提出的 X/Open Distributed Transaction Processing (DTP) 模型告希,簡稱 XA 協(xié)議。
基于XA協(xié)議實現(xiàn)的分布式事務對業(yè)務侵入很小烧给。 它最大的優(yōu)勢就是對使用方透明燕偶,用戶可以像使用本地事務一樣使用基于XA協(xié)議的分布式事務。 XA協(xié)議能夠嚴格保障事務 ACID 特性础嫡。
嚴格保障事務 ACID 特性是一把雙刃劍指么。 事務執(zhí)行在過程中需要將所需資源全部鎖定,它更加適用于執(zhí)行時間確定的短事務榴鼎。 對于長事務來說伯诬,整個事務進行期間對數(shù)據(jù)的獨占,將導致對熱點數(shù)據(jù)依賴的業(yè)務系統(tǒng)并發(fā)性能衰退明顯巫财。 因此盗似,在高并發(fā)的性能至上場景中,基于XA協(xié)議的分布式事務并不是最佳選擇平项。
3赫舒、柔性事務
如果將實現(xiàn)了 ACID 的事務要素的事務稱為剛性事務的話,那么基于 BASE 事務要素的事務則稱為柔性事務闽瓢。 BASE 是基本可用接癌、柔性狀態(tài)和最終一致性這三個要素的縮寫。
基本可用(Basically Available):允許響應時間拉長扣讼,允許功能上的損失缺猛,允許降級頁面(系統(tǒng)繁忙,稍后重試等)椭符,即分布式系統(tǒng)在出現(xiàn)故障時荔燎,允許損失部分可用功能,保證核心功能可用销钝。如湖雹,電商網(wǎng)站交易付款出現(xiàn)問題了,商品依然可以正常瀏覽曙搬。
柔性狀態(tài)(Soft state):是指允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認為該中間狀態(tài)的存在不會影響系統(tǒng)的整體可用性。如訂單的"支付中"纵装、“數(shù)據(jù)同步中”等狀態(tài)征讲,待數(shù)據(jù)最終一致后狀態(tài)改為“成功”狀態(tài)。
最終一致性(Eventually consistent):本質就是需要保證最終數(shù)據(jù)能夠達到一致性橡娄,而不需要實時保證系統(tǒng)數(shù)據(jù)的強一致性诗箍。如訂單的"支付中"狀態(tài),最終會變?yōu)椤爸Ц冻晒Α被蛘?支付失敗"挽唉,使訂單狀態(tài)與實際交易結果達成一致滤祖,但需要一定時間的延遲、等待瓶籽。
在 ACID 事務中對隔離性的要求很高匠童,在事務執(zhí)行過程中,必須將所有的資源鎖定塑顺。 柔性事務的理念則是通過業(yè)務邏輯將互斥鎖操作從資源層面上移至業(yè)務層面汤求。通過放寬對強一致性要求,來換取系統(tǒng)吞吐量的提升严拒。
三扬绪、ShardingJdbc 分布式事務使用
3.1 不使用Spring
3.1.1 引入Maven依賴
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
<!-- 使用XA事務時,需要引入此模塊 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- 使用BASE事務時裤唠,需要引入此模塊 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
3.1.2 基于Java編碼方式使用分布式事務
TransactionTypeHolder.set(TransactionType.XA); // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
try (Connection connection = dataSource.getConnection()) { // dataSource的類型為ShardingDataSource
connection.setAutoCommit(false);
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO t_order (user_id, status) VALUES (?, ?)");
preparedStatement.setObject(1, i);
preparedStatement.setObject(2, "init");
preparedStatement.executeUpdate();
connection.commit();
}
3.2 使用Spring-namespace
3.2.1 引入Maven依賴
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- 使用XA事務時挤牛,需要引入此模塊 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- 使用BASE事務時,需要引入此模塊 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
3.2.2 配置spring-namespace的事務管理器
<!-- 進行ShardingDataSource的相關配置 -->
...
<!-- 開啟自動掃描@ShardingTransactionType注解种蘸,使用Spring原生的AOP在類和方法上進行增強 -->
<sharding:tx-type-annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="shardingDataSource" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="shardingDataSource" />
</bean>
<tx:annotation-driven />
3.2.3 業(yè)務代碼中使用分布式事務
@Transactional
@ShardingTransactionType(TransactionType.XA) // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
public void insert() {
jdbcTemplate.execute("INSERT INTO t_order (user_id, status) VALUES (?, ?)", (PreparedStatementCallback<Object>) preparedStatement -> {
preparedStatement.setObject(1, i);
preparedStatement.setObject(2, "init");
preparedStatement.executeUpdate();
});
}
3.3 使用Spring-boot
3.3.1 引入Maven依賴
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- 使用XA事務時墓赴,需要引入此模塊 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-xa-core</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- 使用BASE事務時,需要引入此模塊 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>${sharding-sphere.version}</version>
</dependency>
3.3.2 配置spring-boot的事務管理器
@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
@Bean
public PlatformTransactionManager txManager(final DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
3.3.3 業(yè)務代碼中使用分布式事務
@Transactional
@ShardingTransactionType(TransactionType.XA) // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
public void insert() {
jdbcTemplate.execute("INSERT INTO t_order (user_id, status) VALUES (?, ?)", (PreparedStatementCallback<Object>) preparedStatement -> {
preparedStatement.setObject(1, i);
preparedStatement.setObject(2, "init");
preparedStatement.executeUpdate();
});
}
分布式事務管理器的特有配置
XA事務管理器參數(shù)配置(可選)
ShardingSphere默認的XA事務管理器為Atomikos劈彪,在項目的logs目錄中會生成xa_tx.log
, 這是XA崩潰恢復時所需的日志竣蹦,請勿刪除。
也可以通過在項目的classpath中添加jta.properties
來定制化Atomikos配置項沧奴。具體的配置規(guī)則請參考Atomikos的官方文檔痘括。
BASE柔性事務管理器(SEATA-AT配置)
1、按照seata-work-shop中的步驟滔吠,下載并啟動seata server纲菌,參考 Step6 和 Step7即可。
2疮绷、在每一個分片數(shù)據(jù)庫實例中執(zhí)創(chuàng)建undo_log表(以MySQL為例)
CREATE TABLE IF NOT EXISTS `undo_log`
(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'increment id',
`branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(100) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` DATETIME NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME NOT NULL COMMENT 'modify datetime',
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
- 3翰舌、在classpath中增加seata.conf
client {
application.id = example ## 應用唯一id
transaction.service.group = my_test_tx_group ## 所屬事務組
}
- 4、根據(jù)實際場景修改seata的file.conf和registry.conf文件
注意:
shardingjdbc對數(shù)據(jù)庫的訪問有一些限制:
官方站的說明:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/unsupported-items/
四冬骚、 ShardingSphere集成Nacos配置中心
4.1 集成配置中心
為了集成配置中心椅贱,第一步需要引入 ShardingSphere 中與編排治理相關的依賴包懂算。在 Spring Boot 環(huán)境中,這個依賴包是 sharding-jdbc-orchestration-spring-boot-starter:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-orchestration-spring-boot-starter</artifactId>
</dependency>
引入Nacos配置相關依賴
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-orchestration-reg-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
如果是ZooKeeeper作為配置中心的話庇麦,需引入相關依賴
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-orchestration-reg-zookeeper-curator</artifactId>
</dependency>
4.2 掌握配置項
針對配置中心计技,ShardingSphere 提供了一系列的 DataSource,包括用于數(shù)據(jù)分片的 OrchestrationShardingDataSource山橄、用于讀寫分離的 OrchestrationMasterSlaveDataSource 以及用于數(shù)據(jù)脫敏的 OrchestrationEncryptDataSource垮媒。圍繞這些 DataSource,也存在對應的 DataSourceFactory 工廠類航棱。這里以 OrchestrationMasterSlaveDataSourceFactory 為例來看創(chuàng)建 DataSource 所需要的配置類:
public final class OrchestrationMasterSlaveDataSourceFactory {
public static DataSource createDataSource(final Map<String, DataSource> dataSourceMap, final MasterSlaveRuleConfiguration masterSlaveRuleConfig,
final Properties props, final OrchestrationConfiguration orchestrationConfig) throws SQLException {
if (null == masterSlaveRuleConfig || null == masterSlaveRuleConfig.getMasterDataSourceName()) {
return createDataSource(orchestrationConfig);
}
MasterSlaveDataSource masterSlaveDataSource = new MasterSlaveDataSource(dataSourceMap, new MasterSlaveRule(masterSlaveRuleConfig), props);
return new OrchestrationMasterSlaveDataSource(masterSlaveDataSource, orchestrationConfig);
}
…
}
可以看到睡雇,這里存在一個治理規(guī)則配置類 OrchestrationConfiguration,而在其他的 DataSourceFactory 中所使用的也是這個配置類:
public final class OrchestrationConfiguration {
//治理規(guī)則名稱
private final String name;
//注冊(配置)中心配置類
private final RegistryCenterConfiguration regCenterConfig;
//本地配置是否覆寫服務器配置標志位
private final boolean overwrite;
}
在 OrchestrationConfiguration 中我們看到了用于指定本地配置是否覆寫服務器配置的 overwrite 標志位饮醇,也看到了一個注冊中心的配置子類 RegistryCenterConfiguration它抱。RegistryCenterConfiguration 包的含內容比較多,我們截取最常見最通用的部分配置項:
public final class RegistryCenterConfiguration extends TypeBasedSPIConfiguration {
//配置中心服務器列表
private String serverLists;
//命名空間
private String namespace;
…
}
這里包含了配置中心服務器列表 serverLists 以及用于標識唯一性的命名空間 namespace驳阎。因為 RegistryCenterConfiguration 繼承了 TypeBasedSPIConfiguration抗愁,所以也就自動帶有 type 和 properties 這兩個配置項。
4.3 在Nacos創(chuàng)建配置
spring.shardingsphere.datasource.names=dsmaster,dsslave0,dsslave1
spring.shardingsphere.datasource.dsmaster.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.dsmaster.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.dsmaster.jdbc-url=jdbc:mysql://localhost:3306/dsmaster
spring.shardingsphere.datasource.dsmaster.username=root
spring.shardingsphere.datasource.dsmaster.password=root
spring.shardingsphere.datasource.dsslave0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.dsslave0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.dsslave0.jdbc-url=jdbc:mysql://localhost:3306/dsslave0
spring.shardingsphere.datasource.dsslave0.username=root
spring.shardingsphere.datasource.dsslave0.password=root
spring.shardingsphere.datasource.dsslave1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.dsslave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.dsslave1.jdbc-url=jdbc:mysql://localhost:3306/dsslave1
spring.shardingsphere.datasource.dsslave1.username=root
spring.shardingsphere.datasource.dsslave1.password=root
spring.shardingsphere.masterslave.load-balance-algorithm-type=random
spring.shardingsphere.masterslave.name=health_ms
spring.shardingsphere.masterslave.master-data-source-name=dsmaster
spring.shardingsphere.masterslave.slave-data-source-names=dsslave0,dsslave1
spring.shardingsphere.props.sql.show=true
4.4 ShardingSphere配置開關
- spring.shardingsphere.orchestration.overwrite=true:采用本地配置呵晚。
- spring.shardingsphere.orchestration.overwrite=false:只從配置中心讀取配置蜘腌。
選擇使用阿里巴巴的 Nacos來構建配置中心服務器
spring.shardingsphere.orchestration.name=health_ms
spring.shardingsphere.orchestration.overwrite=false
spring.shardingsphere.orchestration.registry.type=nacos
spring.shardingsphere.orchestration.registry.server-lists=localhost:8848
spring.shardingsphere.orchestration.registry.namespace=
如果采用其他配置配置中心需修改spring.shardingsphere.orchestration.registry.type并提供對應的 server-lists即可。
參考:
https://shardingsphere.apache.org/document/legacy/4.x/document/cn/features/transaction/
https://segmentfault.com/a/1190000023379017