分布式系统中数据库的事务如何处理?
转:分布式系统中数据库的事务如何处理?再等三分钟的博客-CSDN博客分布式数据库如何保证事务
1、数据库拆分有垂直和水平两种方式
数据库垂直拆分会带来的影响:
a、单机的ACID保证被打破。数据到了多机后,原来单机中通过事务进行处理逻辑会有很大影响,要么放弃原来的单机事务,修改实现,要么引入分布式事务。
b、一些join操作会变得比较困难,因为数据可能已经在两个数据库中了。
c、靠外键去进行约束的场景会受到影响。
水平拆分会带来的影响:
a、同样有可能ACID被打破。
b、同样有可能join操作被影响。
c、靠外键去进行约束的场景会有影响。
d、依赖单库的自增序列生成唯一ID会受影响。
e、针对单个逻辑意义上的表的查询就要跨库了。
2、单机变成多机后,事务如何处理
a、分布式事务模型与规范
上图显示AP和RM时候一定需要的,而事务管理器TM是我们额外引入的,之所以要引入事务管理器,因为在分布式系统中,两台机器理论上无法达到一致的状态,需要引入一个单点进行协调,事务管理器控制着全局事务,管理事务的生命周期,并协调资源。
b、两阶段提交
two phase commitment protocol (2pc)两阶段提交协议,是相对于单库的事务提交方式来说的,在单库上完成相应的数据操作后,就会直接提交或者回滚,而在分布式系统中,在提交之前增加了准备阶段。
image.png image.png
实际中,由于事务管理器自身稳定性,可用性,以及网络通信中可能产生的问题,出现情况会比较复杂,此外,事务管理器在多个资源之间进行协调,它自身要进行很多日志记录的工作。使两个阶段提交协议使用分布式事务开销增大。因此,在进行垂直和水平拆分后,要想清楚是否一定要引入两个阶段分布式事务,必要情况才建议使用。
c、大型网站一致性的基础理论---CAP/BASE
C:consistency:一致性,是当数据写入成功后,所有的节点都会同时看到这个数据。
A:availability:可用性,无论成功或失败,每个请求都收到一个反馈,重点是系统一定要有响应。
P:partition-tolerance分区容忍,也就是在系统一部分出现问题时,系统仍能继续工作。
image.png
3、比两阶段提交更轻量一些的Paxos协议
Paxos协议有一个前提就是有一个可靠的通信环境(就是不存在拜占庭将军问题),也就是消息都是准确的,没有被篡改。
首先把议员角色分为Proposer、Acceptor、Learners,议员可以身兼数职。
Proposer:提出议案者
Acceptors:收到议案后进行判断的角色,Acceptors收到议案后要选择是否接受议案,若议案获得多数acceptors接受,则该议案被批准(chosen)
Learners:只能“学习”被批准的议案,相当于对通过的议案进行观察的角色、
Proposal:议案,有Proposer提出,被Acceptors批准或否决
Value:决议,议案的内容,每个议案都是有一个{编号,决议}对组成。
决议(value)只有被proposers提出后才能被批准(未经批准的决议是“议案proposal”)
在Paxos中,一次只能批准(chosen)一个value
Learners只能获得被批准(chosen)的value。
4、多级的sequence问题与处理
当转为水平分库时,原来单库中的sequence以及自增id的做法需要改变。
mysql中,提供Auto Increament字段的支持,这样很容易实现一个自增的不重复的id的序列。在分库分表后,这就成了一个难题。下面从两个方向考虑和解决:唯一性、连续性
如果只是考虑id的唯一性的话,可以参考UUID的生成方式,或者根据自己的业务(不同维度的标识,例如ip,机器名,时间等)来生成唯一的id,这样生成的id虽然保证了唯一性,但是整个分布式系统的连续性不好。
连续性是指在整个分布式环境生成的id连续性,在单机环境中,其实就是一个单点来完成这个任务,在分布式系统中,可以用一个独立的系统来完成这个工作。
这里提供一个方案:就是把所有id都集中放在一个地方进行管理,对每个id序列独立管理,每台机器使用id都从这个id生成器上取。
但有几个问题需要解决:性能问题:每次都远程取id会有资源浪费,改进方案是一次取一段id,然后缓存在本地,如果应用取了一段id,正使用时宕机了,那么一些id号就浪费不可用了。
生成器的稳定性问题。id生成器作为一个无状态的集群存在,其可用性要靠整个集群来保证。
存储问题:
image.png
上面是在底层使用一个独立的存储来记录每个id序列当前的最大值,并控制并发更新,这样id生成器逻辑就很简单。
image.png
上面是直接把id生成器舍掉,把相关的逻辑放到需要生成id的应用本身就可以了。
5、分库查询
我们现在采用的是corbar分库,并没有把表进行拆分,是根据entityid%128进行路由,这样得到的值是唯一的。所以分页是没有问题的。这是用数据量还不是很大的时候。