TCC的基本原理与常见问题

一、TCC基础介绍

TCC 模式是最经典的分布式事务解决方案,它将分布式事务分为两个阶段来执行,try 阶段对每个分支事务进行预留资源,如果所有分支事务都预留资源成功,则进入 commit 阶段提交全局事务,如果有一个节点预留资源失败则进入 cancel 阶段回滚全局事务。

以传统的订单、库存、账户服务为例,在 try 阶段尝试预留资源,插入订单、扣减库存、扣减金额,这三个服务都是要提交本地事务的,这里可以把资源转入中间表。在 commit 阶段,再把 try 阶段预留的资源转入最终表。而在 cancel 阶段,把 try 阶段预留的资源进行释放,比如把账户金额返回给客户的账户。

注意:try 阶段必须是要提交本地事务的,比如扣减订单金额,必须把钱从客户账户扣掉,如果不扣掉,在 commit 阶段客户账户钱不够了,就会出问题。

二、TCC模型的工作流程

在分布式事务中,TCC(Try-Confirm-Cancel)是一种常见的事务控制机制,用于确保在分布式系统中事务的一致性和完整性。TCC 模型主要由以下三个角色组成:

TM(Transaction Manager):事务管理器
RM(Resource Manager):资源管理器
TC(Transaction Coordinator):事务协调器

1. TM(Transaction Manager)- 事务管理器

事务管理器负责管理整个事务的生命周期。它主要负责以下任务:

  • 启动事务
  • 协调事务的执行
  • 决定事务的提交或回滚

在 TCC 模型中,事务管理器会调用各个资源管理器的 Try、Confirm 和 Cancel 接口来控制事务的执行。

2. RM(Resource Manager)- 资源管理器

资源管理器负责具体资源的管理和操作。它主要负责以下任务:

  • 实现 Try、Confirm 和 Cancel 接口
  • 执行实际的业务操作

在 TCC 模型中,每个资源管理器负责一个或多个资源(例如数据库、文件系统等)的操作,并通过 Try、Confirm 和 Cancel 接口来参与事务的控制。

3. TC(Transaction Coordinator)- 事务协调器

事务协调器负责协调多个资源管理器,以确保分布式事务的一致性和完整性。它主要负责以下任务:

  • 协调各个资源管理器的操作
  • 确保所有资源管理器成功执行 Try 操作后,才能执行 Confirm 操作
  • 如果任何一个资源管理器的 Try 操作失败,则执行 Cancel 操作

三、示例

假设有一个分布式事务,需要在两个系统中分别扣减库存和扣减余额。以下是 TCC 模型的工作流程:

Try 阶段:

  • 事务管理器(TM)调用库存系统的 Try 接口,预留库存。
  • 事务管理器(TM)调用余额系统的 Try 接口,预留余额。

Confirm 阶段:

  • 如果库存系统和余额系统的 Try 操作都成功,事务管理器(TM)调用库存系统的 Confirm 接口,正式扣减库存。
  • 事务管理器(TM)调用余额系统的 Confirm 接口,正式扣减余额。

Cancel 阶段:

  • 如果库存系统或余额系统的 Try 操作失败,事务管理器(TM)调用库存系统的 Cancel 接口,取消预留的库存。
  • 事务管理器(TM)调用余额系统的 Cancel 接口,取消预留的余额。

Demo代码

1. 定义资源管理器(RM)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package main

import (
"fmt"
"sync"
)

// RM 接口定义了资源管理器的 Try、Confirm 和 Cancel 操作
type RM interface {
Try() error
Confirm() error
Cancel() error
}

// InventoryManager 模拟库存管理器
type InventoryManager struct {
mu sync.Mutex
stock int
reserve int
}

func NewInventoryManager(stock int) *InventoryManager {
return &InventoryManager{stock: stock}
}

func (im *InventoryManager) Try() error {
im.mu.Lock()
defer im.mu.Unlock()
if im.stock > 0 {
im.reserve++
im.stock--
fmt.Println("Inventory Try: reserved 1 item")
return nil
}
return fmt.Errorf("Inventory Try: out of stock")
}

func (im *InventoryManager) Confirm() error {
im.mu.Lock()
defer im.mu.Unlock()
if im.reserve > 0 {
im.reserve--
fmt.Println("Inventory Confirm: confirmed 1 item")
return nil
}
return fmt.Errorf("Inventory Confirm: no item to confirm")
}

func (im *InventoryManager) Cancel() error {
im.mu.Lock()
defer im.mu.Unlock()
if im.reserve > 0 {
im.reserve--
im.stock++
fmt.Println("Inventory Cancel: canceled 1 item")
return nil
}
return fmt.Errorf("Inventory Cancel: no item to cancel")
}

// BalanceManager 模拟余额管理器
type BalanceManager struct {
mu sync.Mutex
balance int
reserve int
}

func NewBalanceManager(balance int) *BalanceManager {
return &BalanceManager{balance: balance}
}

func (bm *BalanceManager) Try() error {
bm.mu.Lock()
defer bm.mu.Unlock()
if bm.balance > 0 {
bm.reserve++
bm.balance--
fmt.Println("Balance Try: reserved 1 unit")
return nil
}
return fmt.Errorf("Balance Try: insufficient balance")
}

func (bm *BalanceManager) Confirm() error {
bm.mu.Lock()
defer bm.mu.Unlock()
if bm.reserve > 0 {
bm.reserve--
fmt.Println("Balance Confirm: confirmed 1 unit")
return nil
}
return fmt.Errorf("Balance Confirm: no unit to confirm")
}

func (bm *BalanceManager) Cancel() error {
bm.mu.Lock()
defer bm.mu.Unlock()
if bm.reserve > 0 {
bm.reserve--
bm.balance++
fmt.Println("Balance Cancel: canceled 1 unit")
return nil
}
return fmt.Errorf("Balance Cancel: no unit to cancel")
}

2. 定义事务管理器(TM)和事务协调器(TC)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// TransactionManager 负责管理事务的生命周期
type TransactionManager struct {
rms []RM
}

func NewTransactionManager(rms []RM) *TransactionManager {
return &TransactionManager{rms: rms}
}

func (tm *TransactionManager) Execute() error {
// Try 阶段
for _, rm := range tm.rms {
if err := rm.Try(); err != nil {
// 如果 Try 失败,执行 Cancel 阶段
tm.Cancel()
return fmt.Errorf("Transaction failed in Try phase: %v", err)
}
}

// Confirm 阶段
for _, rm := range tm.rms {
if err := rm.Confirm(); err != nil {
// 如果 Confirm 失败,执行 Cancel 阶段
tm.Cancel()
return fmt.Errorf("Transaction failed in Confirm phase: %v", err)
}
}

fmt.Println("Transaction succeeded")
return nil
}

func (tm *TransactionManager) Cancel() {
// Cancel 阶段
for _, rm := range tm.rms {
if err := rm.Cancel(); err != nil {
fmt.Printf("Error during Cancel phase: %v\n", err)
}
}
}

运行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func main() {
// 创建资源管理器
inventoryManager := NewInventoryManager(10)
balanceManager := NewBalanceManager(10)

// 创建事务管理器
rms := []RM{inventoryManager, balanceManager}
transactionManager := NewTransactionManager(rms)

// 执行事务
if err := transactionManager.Execute(); err != nil {
fmt.Printf("Transaction failed: %v\n", err)
}
}

这个示例展示了一个简单的 TCC 模型实现,其中包括事务管理器(TM)、资源管理器(RM)和事务协调器(TC)。通过这种方式,可以确保分布式事务的一致性和完整性。


TCC的基本原理与常见问题
https://smartmalphite.github.io/2024/05/13/SystemDesign/tcc/
作者
Enbo Wang
发布于
2024年5月13日
许可协议