分布式事务

场景

分布式系统中,服务之间存在相互调用,一个分布式事务会包含多个本地事务(数据库事务)。
举个常见的例子:支付宝余额还花呗操作,余额账户还款花呗账户人民币100元,存在一个扣款操作,一个还款操作。余额账户和花呗账户存在不同的数据库中,是不同的事务,如何保证还款操作的事务一致性?如何处理扣款事务和还款事务?

理论

要理解分布式事务,首先要先了解一下事务。
事务:一组操作,要么全部执行,要么都不执行。
事务的 ACID 是通过 InnoDB 日志和锁来保证。事务的隔离性是通过数据库锁的机制实现的,持久性通过 Redo Log(重做日志)来实现,原子性和一致性通过 Undo Log 来实现
事务的四个特性:ACID
A原子性:事务最小单位,不可分割
C一致性:事务只能从一个一致性的状态转移到另外一个一致性的状态
I隔离型:事务之间不能互相干扰,事务提交之前对其他事务是不可见的
D持久性:事务一旦提交,数据的改变是永久的

再说一下分布式系统
百度百科的定义:分布式系统(distributed system)是建立在网络之上的软件系统。通俗一点的解释:一个系统拆分成多个子系统,部署在不同的服务器上,通过约定的协议进行通信。
这就涉及到不同的子服务之间沟通协作的问题。这些问题是什么,如何解决这些问题,分布式计算领域有一个公认的CAP原理。另一个BASE理论是对CAP中一致性和可用性的权衡的结果。

CAP理论

在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。
C一致性:对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。
A可用性:非故障的节点在合理的时间内返回合理的响应
P分区容错性:当出现网络分区后,系统能够继续“履行职责”
分布式系统中CAP中的P是必选项,所以分布式系统只能选择CP架构或者AP架构

BASE理论

BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency),核心思想是权衡一致性和可用性,舍弃强一致性,通过适合的方式达到最终一致性。
基本可用:分布式系统出故障之后,允许部分可用。响应时间延长,功能上做适当的降级。
软状态:允许出现中间状态,但中间状态不会影响系统的整体可用。与CAP中的C一致性理论不符合
最终一致性:系统所有数据节点,经过一段时间之后,都可以达到一致的状态

一致性和可用性之间作权衡。于是就出现了很多一致性协议

基于XA的两阶段提交

XA协议是一个分布式事务协议,规定了事务管理器和本地资源管理器的接口。由两部分组成,事务管理器和本地资源管理器。
第一阶段为投票阶段:事务管理器会向所有的本地资源管理器发起CanCommit(预备)请求,本地资源管理器会执行事务操作,记录日志,但不提交,成功则向事务管理器回复YES(就绪)消息,同意操作;如果不成功,则发送NO(失败)消息,终止操作。第二阶段,如果事务管理器收到YES消息,则向本地资源管理器发送DoCommit请求,本地资源管理器提交事务,将结果返回;如果收到No,则回滚,将结果返回。
xa
缺点是性能不理想,无法满足高并发需求。

三阶段提交

TCC补偿型事务

Try阶段:尝试执行,完成所有业务检查,锁定必须的资源
Confirm阶段:确认业务执行,不做检查,正常情况下一定成功的,confirm接口需要满足幂等,失败后尝试
Cancel阶段:取消执行,释放锁定的资源,cancel接口也需要保证幂等性。
举个例子:10元购买一瓶水,
Try阶段:完成所有业务检查,锁定账户的10元和一瓶水的库存
Confirm阶段:检查通过,执行下单操作,重试保证成功
Cancel阶段:检查失败,释放锁定资源

本地消息表

将需要分布式处理的事务通过消息或者日志的方式异步执行,消息或日志可以存到本地文件、数据库或消息队列中,再通过业务规则进行失败重试,需要保证各服务的接口是幂等的。
本地消息表和业务数据处于同一个本地事务中,所以一定可以提交成功。

可靠消息最终一致性

基于MQ实现。支持事务消息的MQ:rocketmq
在这里插入图片描述
1.A服务向MQ发送一条prepared消息
2.A服务执行本地事务
3.A服务向MQ发送提交消息,MQ发送消息到B服务,B服务执行本地事务
4.如果B事务执行失败,返回MQ异常信息,MQ会重新发送消息

失败的情况
1失败,直接回滚
2失败,直接回滚。A服务需要实现一个mq的回调,用于检查2是否成功,如果失败,会回滚prepared消息。
3失败,消息会重投,保证B执行成功

实践

可靠消息最终一致性
安装启动rocketmq

docker run -d -p 9876:9876 -v `pwd`/data/namesrv/logs:/root/logs -v `pwd`/data/namesrv/store:/root/store --name rmqnamesrv -e "MAX_POSSIBLE_HEAP=100000000" rocketmqinc/rocketmq sh mqnamesrv
docker run -d -p 10911:10911 -p 10909:10909 -v `pwd`/data/broker/logs:/root/logs -v `pwd`/data/broker/store:/root/store --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" -e "MAX_POSSIBLE_HEAP=200000000" rocketmqinc/rocketmq sh mqbroker

控制台

docker run -e "JAVA_OPTS=-Drocketmq.namesrv.addr=172.17.0.3:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" -p 8080:8080 -t styletang/rocketmq-console-ng

总结

业务服务接口很多都涉及到幂等
下次总结一下实现接口幂等性的注意点

第一篇学习记录,实践部分没完成,半成品,相当于笔记。有问题感谢指出,会尽快修复掉。
感受:真正花时间把知识汇总起来实在是太难了,要坚持,下次找个熟悉的知识点。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章