|
1 | 1 | 以Saga的方式管理事务
|
2 | 2 | ================
|
| 3 | +- [以Saga的方式管理事务](#以saga的方式管理事务) |
| 4 | + - [跨服务的事务场景](#跨服务的事务场景) |
| 5 | + - [1. 为什么需要分布式事务?](#1-为什么需要分布式事务) |
| 6 | + - [2. 分布式事务的问题](#2-分布式事务的问题) |
| 7 | + - [2.1 什么是两阶段提交?](#21-什么是两阶段提交) |
| 8 | + - [2.2 CAP理论](#22-cap理论) |
| 9 | + - [3. 什么是Saga模式?](#3-什么是saga模式) |
| 10 | + - [3.1 什么是状态机(statemachine)?](#31-什么是状态机statemachine) |
| 11 | + - [3.1 如何使用Saga维持数据一致性?](#31-如何使用saga维持数据一致性) |
| 12 | + - [4. Saga管理事务的方式?](#4-saga管理事务的方式) |
| 13 | + - [5 如何实现“隔离性”?](#5-如何实现隔离性) |
| 14 | + - [5.1.1 更新丢失(lost updates)](#511-更新丢失lost-updates) |
| 15 | + - [5.1.2 脏读(Dity read)](#512--脏读dity-read) |
| 16 | + - [5.3 解决方法](#53-解决方法) |
| 17 | + |
| 18 | +## 跨服务的事务场景 |
| 19 | + |
| 20 | + |
| 21 | + |
| 22 | +1. Order Service — 创建订单并设置状态为APPROVAL_PENDING. |
| 23 | +2. ConsumerService — 验证客户是否可下单。 |
| 24 | +3. Kitchen Service — 验证订单信息,并创建状态为CREATE |
| 25 | +_PENDING的Ticket(也就是Kitchen Service自己的Order)。 |
| 26 | +1. Accounting Service — 授权客户的信用卡。 |
| 27 | +2. Kitchen Service — 更改Ticket的状态为AWAITING_ACCEPTANCE. |
| 28 | +3. Order Service — 更改订单的状态为APPROVED. |
3 | 29 |
|
4 | 30 | ## 1. 为什么需要分布式事务?
|
5 | 31 |
|
6 | 32 | ## 2. 分布式事务的问题
|
7 | 33 |
|
8 |
| -### 2.1 什么是两阶段提交? |
| 34 | +### 2.1 什么是[两阶段提交](https://zhuanlan.zhihu.com/p/35616810)? |
| 35 | +目的:保证原子性,即, 所有的参与者要么全部提交,要么全部回滚。 |
9 | 36 |
|
10 |
| -两阶段提交(2PC),所有的参与者要么全部提交,要么全部回滚。 |
| 37 | +两阶段提交(2PC),先投票,再提交。 |
11 | 38 |
|
12 | 39 | * NoSQL的数据库不支持2PC
|
13 | 40 | * Message queue 不支持2PC
|
14 | 41 | * 无法保证可用性
|
15 | 42 |
|
16 |
| -### 2.2 CAP理论 |
| 43 | +### 2.2 [CAP理论](https://cloud.tencent.com/developer/article/1860632) |
17 | 44 |
|
18 |
| -## 3. 什么是[Saga模式](http://microservices.io/ patterns/data/saga.html)? |
19 | 45 |
|
20 |
| -基于异步消息,协调一系列本地事务,以保证数据最终一次性。 |
| 46 | +一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance) |
| 47 | + |
| 48 | +## 3. 什么是[Saga模式](http://microservices.io/patterns/data/saga.html)? |
| 49 | + |
| 50 | +基于异步消息,协调一系列本地事务,以保证数据最终一次性。通常通过状态机的方式来实现。 |
| 51 | + |
| 52 | +### 3.1 什么是状态机(statemachine)? |
| 53 | + |
| 54 | +由一系列的状态和状态之间的transition(转换)组成,transition通过事件触发。 每个transition可以有操作。对Saga而言,就是调用对应的参与者(即服务) |
| 55 | + |
| 56 | + |
| 57 | + |
21 | 58 |
|
22 | 59 | ### 3.1 如何使用Saga维持数据一致性?
|
23 | 60 |
|
24 | 61 | * Pivot transactions
|
25 | 62 |
|
26 | 63 | * Compensating transactions
|
27 | 64 |
|
28 |
| -## Saga管理事务的方式? |
| 65 | +## 4. Saga管理事务的方式? |
29 | 66 |
|
30 |
| -* 分散 |
31 |
| -* 中心 |
| 67 | +* 分散(Choreography) |
| 68 | +  |
| 69 | +* 中心(Orchestration) |
| 70 | + |
| 71 | +  |
| 72 | + |
| 73 | +## 5 如何实现“隔离性”? |
| 74 | + |
| 75 | +ACID(原子性、~~一致性~~、隔离性、~~持久性~~) |
32 | 76 |
|
33 |
| -## 如何实现“隔离性”? |
34 | 77 |
|
35 | 78 | 在跨服务,没有数据库事务的情况,我们在微服务系统要面临:
|
36 | 79 |
|
37 |
| -* 更新丢失 |
38 |
| -* 脏读 |
| 80 | +### 5.1.1 更新丢失(lost updates) |
| 81 | + |
| 82 | +1. `Create Order Saga` 在第一步创建了一个订单。 |
| 83 | +2. 在其正在执行期间, `Cancel Order Saga`取消订单。 |
| 84 | +3. `Create Order Saga`的最后一步确定了订单。 |
| 85 | + |
| 86 | +两种办法解决这个问题: |
| 87 | + |
| 88 | +1. 在订单处于APPROVED_PENDING状态时,不取消订单,等待订单执行完后,再执行取消操作。 |
| 89 | + |
| 90 | +2. |
| 91 | +### 5.1.2 脏读(Dity read) |
| 92 | + |
| 93 | +在两个Saga的执行期间,一个读取到了另外的Saga的数据。比如`Cancel Order Saga`取消订单,会执行一下步骤。 |
| 94 | + |
| 95 | +* ConsumerService — 增加行用卡额度 |
| 96 | +* Order Service — 更改订单状态为Cancelled |
| 97 | +* DeliveryService — 取消配送 |
| 98 | + |
| 99 | +假设 `Create Order Saga` 和 `Cancel Order Saga`同时执行。 `Cancel order Saga`撤销了(可能应为是某种神奇的原因,订单不能被取消了),那么有可能: |
| 100 | + |
| 101 | +1. CancelOrderSaga — 增加行用卡额度 |
| 102 | +2. CreateOrderSaga — 减少行用卡额度 |
| 103 | +3. CancelOrderSaga — (Cancel Order Saga失败了)一个补偿性事务,减少信用卡额度。 |
| 104 | + |
| 105 | +在这种情况下, CreateOrderSaga就可能超过额度, 创建订单。 |
| 106 | + |
39 | 107 | * 不可重复读
|
40 | 108 |
|
41 |
| -解决方法 |
| 109 | +### 5.3 解决方法 |
| 110 | + |
| 111 | +* 语义化版本锁(Semantic lock) — 应用层锁 |
| 112 | +* 可交换更新(Commutative updates) — 以任何顺序执行操作, 比如 扣款和退款, 无论是先执行退款,还是扣款最终结果时一样的。 |
| 113 | + |
| 114 | +* Pessimistic view — 调整Saga中步骤的顺序,以最小化业务出错风险 |
| 115 | + |
| 116 | +* Reread value — 通过再次读取数据,确保仅在数据未改变的情况再写入数据。这其实一种乐观锁 |
| 117 | + |
| 118 | + `Optimistic Locking(乐观锁)` 在获取一条记录的时候,你记住它的版本,保存的时候,检查版本是否有变化,仅在没变化时,才写入。 |
| 119 | + |
| 120 | + `Pessimistic Locking(悲观锁)` 直接以独占的方式锁定这条记录,不让其它人访问他。 |
| 121 | + |
| 122 | +* Version file — 记录记录的变更,以便可调整顺序。 |
| 123 | +* |
| 124 | +* By value — 根据价值决定采用什么样的并发方式。 |
42 | 125 |
|
43 |
| -* 语义化版本锁(Semantic lock)— 应用层锁 |
44 |
| -* 可交换更新(Commutative updates)—Design update operations to be executable in any order. |
45 |
| -* Pessimistic view — Reorder the steps of a saga to minimize business risk. |
46 |
| -* Reread value — Prevent dirty writes by rereading data to verify that it’s unchanged before overwriting it. |
47 |
| -* Version file — Record the updates to a record so that they can be reordered. |
48 |
| -* By value — Use each request’s business risk to dynamically select the concurrency mechanism. |
49 | 126 |
|
50 |
| -## 示例 |
|
0 commit comments