Skip to content

Commit 602cded

Browse files
committed
blog: 64 为多处理器多任务管理
1 parent e14e159 commit 602cded

19 files changed

Lines changed: 515 additions & 15 deletions

File tree

blog/2024-12-23-distributed-transactions/index.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
slug: thinking-for-distributed-transactions
33
title: 对分布式事务的一些思考
44
authors: [OneCastle5280]
5-
tags: [分布式事务]
5+
tags: [分布式]
66
---
77

88
## 要求
@@ -24,7 +24,7 @@ tags: [分布式事务]
2424
6. 发起支付:系统调用第三方支付网关交互以完成实际的支付过程。
2525
7. 确认支付并减少库存:支付成功后,系统通知库存服务正式减少商品库存,通知积分服务正式减少可使用积分,并更新订单状态为“已支付”。
2626

27-
涉及的服务有:
27+
涉及的服务有
2828
1. 库存服务:负责管理商品的库存。
2929
2. 订单服务:负责处理用户的订单创建和对接第三方支付流程。
3030
3. 积分服务:负责处理用户的积分抵扣逻辑。
@@ -44,7 +44,7 @@ tags: [分布式事务]
4444
#### 事务协调方
4545
分布式事务的核心角色:负责管理和协调参与事务的各个服务或资源管理器;是分布式事务的发起方,需要确保所有参与者都能一致地提交或回滚事务。
4646
#### 资源方
47-
分布式事务中负责管理本地资源(例如对于库存服务来说,库存就是本地资源)、执行资源锁定、核销或回滚操作。资源方都需要实现 `Try()``Confirm()``Cancel()` 三个接口, 下面简述一下每个接口需要承担的责任;
47+
分布式事务中负责管理本地资源(例如对于库存服务来说,库存就是本地资源)、执行资源锁定、核销或回滚操作。资源方都需要实现 `Try()``Confirm()``Cancel()` 三个接口下面简述一下每个接口需要承担的责任;
4848

4949
> 1. Try(): 当分布式事务开启时,事务协调方会调用所有资源方的`Try()`进行「资源锁定」;资源方需要保证只要`Try()`调用成功,后续的`Confirm``Cancel()`能够对「被锁定的资源」进行核销或释放。
5050
> 2. Confirm(): 用于提交分布式事务,核销前面通过`Try()`锁定的资源。
@@ -71,7 +71,7 @@ tags: [分布式事务]
7171
> 1. 库存服务(资源方)释放锁定库存,库存状态标记为「已释放」;
7272
> 2. 积分服务(资源方)释放锁定积分,积分状态标记为「已释放」;
7373
>
74-
> 被释放出来的资源则可以继续被其他用户进行锁定-核销/释放
74+
> 被释放出来的资源则可以继续被其他用户进行锁定 - 核销/释放
7575
7676
### 2.3 异常场景
7777
上述都是各个服务都能够正常响应、正常处理业务逻辑的成功场景;一切都很美好,但实际上可能会存在各种各样的异常场景,例如:
@@ -83,20 +83,20 @@ tags: [分布式事务]
8383

8484
#### 2.3.1 Try 阶段
8585
##### 部分资源方返回成功,部分资源方返回失败
86-
情况1
86+
情况 1
8787
![alt text](img/image6.png)
8888
资源方明确返回资源不充足,此时事务无法开启,需要通知`Try()`返回成功的资源方进行资源释放,即调用 `Cancel()`.
8989

90-
情况2
90+
情况 2
9191
![alt text](img/image7.png)
9292
超时导致的失败,则此次`Try()`调用有可能成功到达了资源方,也有可能因为网络问题最终没有到达资源方;但是对于事务协调方来说,就是调用 `Try()` 失败了;需要对所有资源方调用 `Cancel()` 进行资源释放。
9393

94-
情况3
94+
情况 3
9595
![alt text](img/image8.png)
9696
`Try()` 最终因为网络原因没有到达积分服务,此时接收到 `Cancel()` 请求,对于积分服务来说,没有任何资源可以支持回滚。
9797
> 资源方的`Cancel()` 接口需要能够支持空回滚。
9898
99-
情况4
99+
情况 4
100100
![alt text](img/image9.png)
101101
1. 刚开始调用`Try()`超时了,事务协调方调用`Cancel()`进行资源释放。
102102
2. 在收到 `Cancel()` 之后,前面在网络中迷失的`Try()`请求又到达了积分服务;如果积分服务执行 `Try()` 成功,就会把资源给锁定了,并且对于事务协调方来说,分布式事务已经执行完成了,不会再有后续的 `Confirm()`/`Cancel()` 来对资源核销或者释放了;这个是因为网络原因导致的 **乱序问题**
@@ -110,9 +110,9 @@ tags: [分布式事务]
110110
![alt text](img/image10.png)
111111
对于事务协调方来说,调用结果是失败的,积分服务是否成功无法感知,但是事务协调方不可能一直等待某个资源方的 `Confirm()` 响应成功。
112112

113-
此时,可以通过引入消息队列组件, 利用消息队列能够确保消息最低能够被消费一次的特性,让资源方自行监听消息,收到`Confirm`的消息,自行调用 `Confirm()` 逻辑, 完成`Confirm`阶段。如下图所示:
113+
此时,可以通过引入消息队列组件利用消息队列能够确保消息最低能够被消费一次的特性,让资源方自行监听消息,收到`Confirm`的消息,自行调用 `Confirm()` 逻辑,完成`Confirm`阶段。如下图所示:
114114
![alt text](img/image11.png)
115-
这里同样有一个问题:订单服务(事务协调方)和消息队列 Broker同样是部署在不同的节点上,同样存在不确定性,如何确保消息一定发送出来呢?例如下列场景:
115+
这里同样有一个问题:订单服务(事务协调方)和消息队列 Broker 同样是部署在不同的节点上,同样存在不确定性,如何确保消息一定发送出来呢?例如下列场景:
116116

117117
> 1. Try 阶段完成,库存锁定成功、用户积分锁定成功、对应的订单创建成功,并且订单状态为「未支付」。
118118
> 2. 用户完成支付,此时事务要进入`Confirm` 阶段,开始调用资源方的 `Confirm()` 接口进行事务提交。
@@ -124,7 +124,7 @@ tags: [分布式事务]
124124

125125
![alt text](img/image12.png)
126126

127-
> 1. 在调用资源方 `Confirm()` 接口出现异常的时候,借助消息队列最少能消费一次的特性,发送「补偿」消息,延后通知资源方进行核销, 实现最终一致性;并且此时订单状态更新为「已支付」。
127+
> 1. 在调用资源方 `Confirm()` 接口出现异常的时候,借助消息队列最少能消费一次的特性,发送「补偿」消息,延后通知资源方进行核销实现最终一致性;并且此时订单状态更新为「已支付」。
128128
> 2. 如果发送「补偿」消息失败,则生成一条状态为「待发送」的消息记录到数据库,标识事务还有一个「补偿」消息没有完成发送;并且将存储「补偿」消息的动作和更新订单状态为「已支付」放到**同一个本地事务**里,要么一起成功、要么就一起失败;
129129
> 3. 然后另起一个定时任务来扫描「本地消息表」里「待发送」的消息记录,然后去做补偿发送消息。
130130
File renamed without changes.
71.4 KB
Loading
Lines changed: 1 addition & 0 deletions
Loading

blog/2025-11-06-x86-mcmt/img/03.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)