前言
隨着互聯化的蔓延,各種項目都逐漸向分佈式服務做轉換。如今微服務已經普遍存在,本地事務已經無法滿足分佈式的要求,由此分佈式事務問題誕生。
1.常見的一些分佈式事務場景
案例 1:下訂單和扣庫存
案例 2:同步調用超時
案例 3:異步回調超時
案例 4:系統間狀態不一致
案例 5:緩存和數據庫不一致
案例 6:本地緩存節點間不一致
2.分佈式事務理論
分佈式事務被稱爲世界性的難題,目前分佈式事務存在兩大理論依據:CAP定律 BASE理論。
2.1CAP定律
這個定理的內容是指的是在一個分佈式系統中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),三者不可得兼。比如zookeeper保證了CP;
2.1.1一致性(C)
在分佈式系統中的所有數據備份,在同一時刻是否同樣的值。(等同於所有節點訪問同一份最新的數據副本)
2.1.2可用性(A)
在集羣中一部分節點故障後,集羣整體是否還能響應客戶端的讀寫請求。(對數據更新具備高可用性)
2.1.3分區容錯性(P)
以實際效果而言,分區相當於對通信的時限要求。系統如果不能在時限內達成數據一致性,就意味着發生了分區的情況,必須就當前操作在C和A之間做出選擇。
2.2BASE理論
BASE是Basically Available(基本可用)、Soft state(軟狀態)和 Eventually consistent(最終一致性)三個短語的縮寫。BASE理論是對CAP中一致性和可用性權衡的結果,其來源於對大規模互聯網系統分佈式實踐的總結, 是基於CAP定理逐步演化而來的。BASE理論的核心思想是:即使無法做到強一致性,但每個應用都可以根據自身業務特點,採用適當的方式來使系統達到最終一致性。
2.2.1基本可用(Basically Available)
基本可用是指分佈式系統在出現不可預知故障的時候,允許損失部分可用性。注意,這絕不等價於系統不可用。比如:
(1)響應時間上的損失。正常情況下,一個在線搜索引擎需要在0.5秒之內返回給用戶相應的查詢結果,但由於出現故障,查詢結果的響應時間增加了1~2秒
(2)系統功能上的損失:正常情況下,在一個電子商務網站上進行購物的時候,消費者幾乎能夠順利完成每一筆訂單,但是在一些節日大促購物高峯的時候,由於消費者的購物行爲激增,爲了保護購物系統的穩定性,部分消費者可能會被引導到一個降級頁面
2.2.2軟狀態(Soft State)
軟狀態指允許系統中的數據存在中間狀態,並認爲該中間狀態的存在不會影響系統的整體可用性,即允許系統在不同節點的數據副本之間進行數據同步的過程存在延時
2.2.3最終一致性(Eventually Consistent)
最終一致性強調的是所有的數據副本,在經過一段時間的同步之後,最終都能夠達到一個一致的狀態。因此,最終一致性的本質是需要系統保證最終數據能夠達到一致,而不需要實時保證系統數據的強一致性。
2.3ACID(補充)
ACID 指如下內容 。
• A: Atomicity,原子性 。
• C: Consistency , 一致性。
• I: Isolation,隔離性。
• D: Durability,持久性。
具有 ACID 特性的數據庫支持強一致性,強一致性代表數據庫本身不會出現不一致, 每個事務都是原子的,或者成功或者失敗,事物間是隔離的,互相完全不受影響,而且最終狀態是持久落盤的。因此,數據庫會從一個明確的狀態過渡到另外一個明確的狀態,中間的臨時狀態是不會出現的,如果出現也會及時地自動修復,因此是強一致的 。
3TX-LCN介紹
名詞說明:
DTX:分佈式事務 (Distributed Transaction)
LTX:本地事務 (Local Transaction)
RTX:遠程事務 (Remote Transaction)(被調方本地事務)
TM: DTX協調服務器 (TXManager)
TC:DTX協調客戶端 (TXClient)
事務發起方:一個用戶請求下最先執行業務的服務
事務參與方:被事務發起方調用的服務
框架定位
LCN並不生產事務,LCN只是本地事務的協調工
TX-LCN定位於一款事務協調性框架,框架其本身並不操作事務,而是基於對事務的協調從而達到事務一致性的效果
- 事務模式
- TCC模式
TCC 分別對應 Try 、 Confirm 和 Cancel 三種操作,這三種操作的業務含義如下:
• Try:預留業務資源
• Confirm:確認執行業務操作
• Cancel:取消執行業務操作
在一個跨服務的業務操作中,首先通過 Try鎖住服務中的業務資源進行資源預留,只有資源預留成功了,後續的操作才能正常進行。 Confirm 操作是在 Try 之後進行的操作,對Try 階段鎖定的資源進行業務操作。 Cancel 則是在所有操作失敗時用於回滾。
相對於傳統事務機制(X/Open XA Two-Phase-Commit),其特徵在於它不依賴資源管理器(RM)對XA的支持,而是通過對(由業務系統提供的)業務邏輯的調度來實現分佈式事務。
3.1.2TXC模式
TXC(Taobao Transaction Constructor),命名來源於淘寶,實現原理是在執行SQL之前,先查詢SQL的影響數據,然後保存執行的SQL快照信息和創建鎖。當需要回滾的時候就採用這些記錄數據回滾數據庫。
3.1.3LCN模式
LCN模式是通過代理Connection的方式實現對本地事務的操作,然後在由TxManager統一協調控制事務。當本地事務提交回滾或者關閉連接時將會執行假操作,最後由協調器TM通知各參與方commit/rollback本地事務。該代理的連接將由LCN連接池管理。
LCN分別對應Lock、Confirm和notify三種操作,含義分別如下:
鎖定事務單元(lock),確認事務模塊狀態(confirm),通知事務(notify)
LCN分佈式事務框架的核心功能是對本地事務的協調控制,框架本身並不創建事務,只是對本地事務做協調控制。因此該框架與其他第三方的框架兼容性強,支持所有的關係型數據庫事務,支持多數據源,支持與第三方數據庫框架一塊使用(例如 sharding-jdbc),在使用框架的時候只需要添加分佈式事務的註解即可,對業務的侵入性低。
3.2框架
兼容dubbo、springcloud框架,支持RPC框架拓展,支持各種ORM框架、NoSQL、負載均衡、事務補償
3.3工作原理
LCN的工作原理圖:(請參考https://www.txlcn.org/zh-cn/docs/principle/control.html)
核心步驟
1、創建事務組
是指在事務發起方開始執行業務代碼之前先調用TxManager創建事務組對象,然後拿到事務標示GroupId的過程。
2、加入事務組
添加事務組是指參與方在執行完業務方法以後,將該模塊的事務信息通知給TxManager的操作。
3、通知事務組
是指在發起方執行完業務代碼以後,將發起方執行結果狀態通知給TxManager,TxManager將根據事務最終狀態和事務組的信息來通知相應的參與模塊提交或回滾事務,並返回結果給事務發起方。
3.4流程分析
假如有三個微服務A、B和C,服務A使用LCN模式實現,服務B使用TXC模式,服務C使用TCC模式。調用關係爲Service A->Service B->Service C
首先有個事務協調器TM,它支持集羣方式
執行流程:
①ServiceA執行的時候,首先會向TM發起創建分佈式事務組;TM側把事務組信息緩存在Redis中。
②接着調用service B,service B在執行操作sql之前會先查詢並保存受影響的數據,然後執行操作,操作成功後並不提交,而是加入事務組。若失敗則直接執行本地回滾,分佈式事務也進行回滾。
③調用Service C時,需分別實現Try、confirm和Cancel對應的方法,servce C調用try方法進行操作,若成功加入事務組, 失敗則執行對應的cancel函數。
④service A得到成功的響應後,執行完本地業務邏輯後將給TM發送Notify Group消息,並commit/rollback本地事務,TM接收到Notify Group消息後通知各參與方commit/rollback各自本地事務。
⑤若所有TC都返回執行成功,事務協調器TM則會通知各參與方。Service B收到以後刪除保留的鏡像數據,失敗則利用鏡像進行回滾並釋放鎖;Service C收到以後成功執行Confirm方法,否則執行Cancel方法。
3.5快速入門
3.5.1啓動TM
①依賴
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
②增加註解
在主類上標註 @EnableTransactionManagerServer
③配置
spring.application.name=TransactionManager
server.port=7970
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=test
spring.datasource.password=1234
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
3.5.2TC微服務
①依賴
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-tc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>com.codingapi.txlcn</groupId>
<artifactId>txlcn-txmsg-netty</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
②TC開啓分佈式事務註解
在啓動類中添加@EnableDistributedTransaction
@SpringBootApplication
@EnableDiscoveryClient
@EnableDistributedTransaction
public class SpringServiceAApplication {
public static void main(String[] args) {
SpringApplication.run(SpringServiceAApplication.class, args);
}
}
業務方法配置:
LCN模式,
添加註解@LcnTransaction和@Transactional
TXC模式
添加註解@TxcTransaction和@Transactional
TCC模式
添加註解@TccTransaction和@Transactional
③配置
spring.application.name=txlcn-demo-spring-service-x
server.port=12102
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
## TODO 你的配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/txlcn-demo?characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=test
spring.datasource.password=1234
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true
## tx-manager 配置
tx-lcn.client.manager-address=127.0.0.1:8070
eureka.client.serviceUrl.defaultZone=http://localhost:12001/eureka/
3.6性能測試參數
(官方)
框架 |
模式 |
一致性 |
樣本數 |
KO |
平均時間(ms) |
最低時間(ms) |
最高時間(ms) |
90%時間(ms) |
95%時間(ms) |
吞吐量 |
dubbo |
all |
success |
43020 |
0 |
55.46231985123175 |
26 |
1052 |
52.0 |
66.0 |
358.61953984661557 |
dubbo |
lcn |
success |
46414 |
0 |
51.37234455121358 |
23 |
1231 |
52.0 |
65.0 |
386.89295300335095 |
dubbo |
local |
success |
67491 |
3253 |
35.26322028122323 |
9 |
444 |
116.0 |
160.0 |
562.6735141354097 |
dubbo |
tcc |
success |
48156 |
0 |
49.541095605946666 |
24 |
1175 |
53.0 |
62.0 |
401.4304649010929 |
dubbo |
txc |
success |
43123 |
0 |
55.338566426269196 |
26 |
1135 |
57.0 |
68.0 |
359.2206320910318 |
spring |
all |
success |
37473 |
0 |
63.68598724414947 |
26 |
1051 |
63.0 |
72.0 |
312.36350299251455 |
spring |
lcn |
success |
38941 |
613 |
61.027939703653814 |
7 |
611 |
62.0 |
75.0 |
324.6300696094369 |
spring |
local |
error |
49602 |
6816 |
47.26015080037109 |
7 |
525 |
147.0 |
164.0 |
413.28111981336446 |
spring |
tcc |
success |
38946 |
1369 |
60.97386124377325 |
7 |
1180 |
66.0 |
89.0 |
324.6852855356399 |
spring |
txc |
success |
36113 |
0 |
66.08238030626066 |
30 |
1152 |
64.0 |
73.0 |
301.0244483899739 |