分布式事务执行的三种方式
1 简介
本文结束分布式事物中的交易处理与并发控制。如2PC两阶段事务提交算法,以及是关于如何在web服务中实现分布式事务的指导,以及主要分布式事务控制方法的简介。
分布式事务控制:如两阶段提交协议。
在web服务中实现分布式事务是一项复杂的任务,涉及多个服务或数据库间的一致性保证。
实现分布式事务时,通常需要一个事务控制机制,例如 两阶段提交协议 (2PC)、三阶段提交协议 (3PC)、或现代的 Saga 模式。
2 分布式事务控制方法
- 两阶段提交协议 (2PC)
特点:
经典的分布式事务方法。
分两个阶段:准备阶段 和 提交阶段。
中心化的事务协调器控制所有事务分支。
优点:
保证一致性。
缺点:
阻塞性:资源可能长时间被锁住。
单点故障风险:事务协调器的故障可能导致事务卡住。
2. 三阶段提交协议 (3PC)
特点:
解决 2PC 阻塞问题。
增加了一个 "预提交阶段",在正式提交前进行一致性检查。
优点:
减少事务阻塞时间。
缺点:
增加了复杂性和延迟。
网络分区时可能仍会出现一致性问题。
3. Saga 模式
特点:
将事务拆分成一系列可补偿的小事务。
每个操作都有一个对应的补偿操作。
使用协调器或消息队列管理事务链。
优点:
非阻塞,适合长事务。
易于扩展,解耦。
缺点:
编程复杂度增加。
数据最终一致性而非强一致性。
在web服务中实现两阶段提交 (2PC)
以下是一个基于 MySQL 的分布式事务实现两阶段提交的示例。
依赖安装
go get -u github.com/gin-gonic/gin
go get -u github.com/go-sql-driver/mysql
go get -u github.com/sirupsen/logrus
4 实现示例
-
- 数据库表设计
在每个数据库中创建一个记录事务状态的表:
CREATE TABLE transaction_logs (
id VARCHAR(64) PRIMARY KEY, -- 事务ID
state ENUM('PREPARED', 'COMMITTED', 'ABORTED') NOT NULL, -- 事务状态
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-
-
服务代码实现
type DB struct { conn *sql.DB } var db1, db2 *DB func initDB(dsn string) *DB { conn, err := sql.Open("mysql", dsn) if err != nil { log.Fatalf("Failed to connect to database: %v", err) } return &DB{conn: conn} } func (db *DB) prepareTransaction(txID string) error { _, err := db.conn.Exec("INSERT INTO transaction_logs (id, state) VALUES (?, 'PREPARED')", txID) return err } func (db *DB) commitTransaction(txID string) error { _, err := db.conn.Exec("UPDATE transaction_logs SET state = 'COMMITTED' WHERE id = ?", txID) return err } func (db *DB) abortTransaction(txID string) error { _, err := db.conn.Exec("UPDATE transaction_logs SET state = 'ABORTED' WHERE id = ?", txID) return err } func main() { db1 = initDB("user:password@tcp(127.0.0.1:3306)/db1") db2 = initDB("user:password@tcp(127.0.0.1:3306)/db2") defer db1.conn.Close() defer db2.conn.Close() r := gin.Default() r.POST("/transaction", func(c *gin.Context) { txID := fmt.Sprintf("%d", time.Now().UnixNano()) // 第一阶段:准备 if err := db1.prepareTransaction(txID); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to prepare db1"}) return } if err := db2.prepareTransaction(txID); err != nil { db1.abortTransaction(txID) // 回滚 db1 c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to prepare db2"}) return } // 第二阶段:提交 if err := db1.commitTransaction(txID); err != nil { db1.abortTransaction(txID) // 回滚 db1 db2.abortTransaction(txID) // 回滚 db2 c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to commit db1"}) return } if err := db2.commitTransaction(txID); err != nil { db1.abortTransaction(txID) // 回滚 db1 db2.abortTransaction(txID) // 回滚 db2 c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to commit db2"}) return } c.JSON(http.StatusOK, gin.H{"message": "Transaction committed successfully"}) }) r.Run(":8080") }
-
-
在web服务中实现 Saga 模式
Saga 模式适用于非强一致性的场景,例如跨服务的支付与库存系统。
核心步骤
将事务拆分成多个小事务(每个服务单独完成一个事务)。
为每个事务设计补偿操作。
使用消息队列协调事务流程。
5 小结
分布式事务对比
方法 一致性 性能 适用场景 复杂性
2PC 强一致性 低 银行转账、核心交易 中等
3PC 强一致性 中 高可靠性场景 较高
Saga 最终一致性 高 电商订单、微服务系统 较高
通过选择适合的事务控制方法,并在web服务中结合合适的数据库和协调器,可以有效地实现分布式事务控制。
- 点赞
- 收藏
- 关注作者
评论(0)