在支付、交易、订单等强一致性系统中,我们需要使用分布式事务来保证各个数据库或各个系统之间的数据一致性。
举个简单的例子来描述一下这里数据一致性的含义。
程序员小张向女友小丽转账100人民币,转账过程是:先扣除小张100元,再为小丽的账户添加100元。
如果在转帐过程中,扣款操作和打款操作要么同时执行,要么同时都不执行,我们就认为转帐过程保证了数据一致性。
上面的例子中,如果我们不使用分布式来保证转账过程中数据的一致性,就有可能出现小张账户上的钱被扣除,而小丽账户上的钱却没被添加的情况,其结果大家可以自行脑补。
事务是数据库特有的概念,分布式事务最初起源于处理多个数据库之间的数据一致性问题,但随着IT技术的高速发展,大型系统中逐渐使用SOA服务化接口替换直接对数据库操作,所以如何保证各个SOA服务之间的数据一致性也被划分到分布式事务的范畴。
单数据库事务
先来看看我们需要实现的交易系统:游戏中的玩家使用金币购买道具,交易系统需要负责扣除玩家金币并为玩家添加道具。
我们把交易系统的一次交易流程归纳为两步:
扣除玩家金币
为玩家添加道具
需求并不复杂,我们为金币系统在数据库中添加金币表,为道具系统在数据库中添加道具表,扣除金币与添加道具的操作只需执行相应的SQL即可。
这里我们假设金币表与道具表都在同一个数据库中,于是可以简单地使用单数据库事务来保证数据的一致性。
下面是使用单数据库事务进行一次正常交易的时序图: 此时哪一步步骤出错,都会进行回滚操作,
- 在步骤[2]执行SQL扣除金币时出现异常,回滚事务即可保证数据一致
- 在步骤[4]执行SQL添加道具时出现异常,回滚事务即可保证数据一致
- 在步骤[6]提交事务时出现异常,回滚事务即可保证数据一致从而不会出现数据不一致的问题。
注意这里执行成功还没有落盘持久化,commit提交,也只是执行下面四步操作,刷redo日志是保证这时候数据库g了,磁盘上也有操作记录复原数据库。所以commit操作也可能会失败。
-
清理undo段信息,对于innodb存储引擎的更新操作来说,undo段需要purge,这里的purge主要职能是,真正删除物理记录。在执行delete或update操作时,实际旧记录没有真正删除,只是在记录上打了一个标记,而是在事务提交后,purge线程真正删除,释放物理页空间。因此,提交过程中会将undo信息加入purge列表,供purge线程处理。 -
释放锁资源,mysql通过锁互斥机制保证不同事务不同时操作一条记录,事务执行后才会真正释放所有锁资源,并唤醒等待其锁资源的其他事务; -
刷redo日志,前面我们说到,mysql实现事务一致性和持久性的机制。通过redo日志落盘操作,保证了即使修改的数据页没有即使更新到磁盘,只要日志是完成了,就能保证数据库的完整性和一致性; -
清理保存点列表,每个语句实际都会有一个savepoint(保存点),保存点作用是为了可以回滚到事务的任何一个语句执行前的状态,由于事务都已经提交了,所以保存点列表可以被清理了。
分布式事务
分布式事务 分布式事务 seata 阅读此人博客 敖丙也有一篇文章,结合书 2021.10.19完成分布式事物的学习
|