面试官:亿级流量架构分布式事务如何实现?我懵了..
发布于 2021-11-24 11:16 ,所属分类:2021面试经验技巧分享
作者:等不到的口琴
来源:www.cnblogs.com/Courage129/p/14433462.html
相关阅读:深圳一普通中学老师工资单曝光,秒杀程序员,网友:敢问是哪个学校毕业的?
面试官:亿级流量架构分布式事务如何实现?我懵了。。
什么是分布式事务
原子性(Atomic)
在化学中,分子构成的物质,分子是保持化学特性的最小单位,如 H2O,CO2H2O,CO2 等,由原子构成的物质,原子保持物质特性,像 FeFe 啥的,意思就是不可分割,再分成质子中子啥的就不是我们认为的物质了,这儿的原子性也是这个道理,就是事务不可以再拆分,例如上面的事务,看着可以是由两个过程组成的事务,但是你拆开就不是我们认为该有的过程,所以,事务不可再分,具有原子性。搜索gongzhong号互联网架构师回复“2T”,送你一份惊喜礼包。
一致性(Consistency)
隔离性(Isolation)
事务1 = (A账号扣除500,B账号增加500)
事务2 = (B账号扣除1000,C账号增加1000)
这两个事务之间不会产生影响,也就是不会发生A转出的500块到达C账号这种情况。另外,分布式系列面试题和答案全部整理好了,搜索互联网架构师,在后台发送:2T,可以在线阅读。
持久性(Durability)
持久化,一般是意味着将数据写入磁盘,不会轻易改变的意思,这儿是事务提交之后,会影响到数据库,不会丢失。这也就意味着,随着系统越来越庞大,我们为了提高可用性、维护性、吞吐量等等技术指标,就算改善原有架构,业务计算的问题解决后,数据库还是会成为整个系统中的瓶颈。
一致性的讨论
强一致性
弱一致性
最终一致性
三种一致性中,强一致性数据更加可靠,但是由于时时刻刻要求所有数据库保持数据一致,所以效率低下,数据没有统一完,请求就没法得到响应,高并发场景下,体验不太好,所以在实际使用中,根据不同的业务选择是一致性也不同,购物时账号付钱肯定是强一致性,但是商品库存数据就不一定非要强一致性,至于商品下面的评论啥的,甚至可以选择弱一致性。
分库分表
垂直拆分
垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。做法与大系统拆分为多个小系统类似,按业务分类进行独立划分。与"微服务治理"的做法相似,每个微服务使用单独的一个数据库。如图:
第一个表只包含基本信息(姓名、身份证、性别、身高、体重);
第二个表包含籍贯信息(省、市、区、村);
第三个表包含学习信息(专业、G点)。
垂直拆分优缺点
垂直切分的优点:
解决业务系统层面的耦合,业务清晰
与微服务的治理类似,也能对不同业务的数据进行分级管理、维护、监控、扩展等
高并发场景下,垂直切分一定程度的提升IO、数据库连接数、单机硬件资源的瓶颈
部分表无法join,只能通过接口聚合方式解决,提升了开发的复杂度
分布式事务处理复杂
依然存在单表数据量过大的问题(需要水平切分)
水平拆分
除了上面按照用户ID区间拆分,也可以做Hash运算拆分,这儿就不详细展开了。另外,分库分表系列面试题和答案全部整理好了,搜索互联网架构师,在后台发送:2T,可以在线阅读。
水平拆分优缺点
水平拆分优点在于:
单表大小可控 天然便于水平扩展,后期如果想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移 使用分片字段进行范围查找时,连续分片可快速定位分片进行快速查询,有效避免跨分片查询的问题。
水平拆分缺点:
热点数据成为性能瓶颈。连续分片可能存在数据热点,例如按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则很少被查询
分库分表带来的问题
跨分片事务也是分布式事务,没有简单的方案,一般可使用"XA协议"和"两阶段提交"处理。
分布式事务能最大限度保证了数据库操作的原子性。但在提交事务时需要协调多个节点,推后了提交事务的时间点,延长了事务的执行时间。导致事务在访问共享资源时发生冲突或死锁的概率增高。随着数据库节点的增多,这种趋势会越来越严重,从而成为系统在数据库层面上水平扩展的枷锁。
最终一致性
对于那些性能要求很高,但对一致性要求不高的系统,往往不苛求系统的实时一致性,只要在允许的时间段内达到最终一致性即可,可采用事务补偿的方式。与事务在执行中发生错误后立即回滚的方式不同,事务补偿是一种事后检查补救的措施,一些常见的实现方法有:对数据进行对账检查,基于日志进行对比,定期同标准数据来源进行同步等等。事务补偿还要结合业务系统来考虑。
分布式事务解决思路
讲这个之前需要先简单回顾CAP原则和Base理论,因为分布式事务不同于 ACID 的刚性事务,在分布式场景下基于 BASE 理论,提出了柔性事务的概念。要想通过柔性事务来达到最终的一致性,就需要依赖于一些特性,这些特性在具体的方案中不一定都要满足,因为不同的方案要求不一样;但是都不满足的话,是不可能做柔性事务的。
CAP原则
相当于是对之前三选二说法进行修正,CAP中P(分区容错性)是必须具备的,在满足P的前提下,很难同时满足A(可用性)和C(一致性),但是在之后,又有一篇文章: Harvest, yield, and scalable tolerant systems ,这篇论文是基于上面那篇“CAP 12年后”的论文写的,它主要提出了 Harvest 和 Yield 概念,并把上面那篇论文中所讨论的东西讲得更为仔细了一些。简单来说就是满足P之后,C和A在放宽约束后可以得到兼顾,并不是非此即彼的关系,说远了。搜索gongzhong号互联网架构师回复“2T”,送你一份惊喜礼包。
为什么P是必须的?
为什么CAP原则中分区容错性是必须的呢,首先要理解什么是分区容错性,分区,这儿说的是网络,网络集群设计到很多的服务器,某一瞬间网络不稳定,那么相当于将网络分成了不同的区,假设分成了两个区,这时候如果有一笔交易:
对分区一发出消息:A给B转账100元,对分区二发出消息:A给B转账200元
那么对于两个分区而言,有两种情况:
a)无可用性,即这两笔交易至少会有一笔交易不会被接受;
b)无一致性,一半看到的是 A给B转账100元而另一半则看到 A给B转账200元。
所以,分区容忍性必须要满足,解决策略是一个数据项复制到多个节点上,那么出现分区之后,这一数据项就可能分布到各个区里。容忍性就提高了。
Base理论
BASE理论是Basically Available(基本可用),Soft State(软状态)和Eventually Consistent(最终一致性)三个短语的缩写。
基本可用
假设系统,出现了不可预知的故障,但还是能用,相比较正常的系统而言:
响应时间上的损失:正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在2秒作用返回结果。
功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单。但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
软状态
最终一致性
Base其核心思想是:
既然无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。有了Base理论就可以开始讲述分布式事务的处理思路了。
二阶段提交协议
第一阶段:投票
该阶段的主要目的在于打探数据库集群中的各个参与者是否能够正常的执行事务,具体步骤如下:
协调者向所有的参与者发送事务执行请求,并等待参与者反馈事务执行结果; 事务参与者收到请求之后,执行事务但不提交,并记录事务日志; 参与者将自己事务执行情况反馈给协调者,同时阻塞等待协调者的后续指令。
第二阶段:事务提交
在经过第一阶段协调者的询盘之后,各个参与者会回复自己事务的执行情况,这时候存在 3 种可能性:
所有的参与者都回复能够正常执行事务。 一个或多个参与者回复事务执行失败。 协调者等待超时。
协调者向各个参与者发送 commit 通知,请求提交事务; 参与者收到事务提交通知之后执行 commit 操作,然后释放占有的资源; 参与者向协调者返回事务 commit 结果信息。
对于第 2 和第 3 种情况,协调者均认为参与者无法成功执行事务,为了整个集群数据的一致性,所以要向各个参与者发送事务回滚通知,具体步骤如下:
协调者向各个参与者发送事务 rollback 通知,请求回滚事务; 参与者收到事务回滚通知之后执行 rollback 操作,然后释放占有的资源; 参与者向协调者返回事务 rollback 结果信息。
两阶段提交协议解决的是分布式数据库数据强一致性问题,实际应用中更多的是用来解决事务操作的原子性,下图描绘了协调者与参与者的状态转换。
站在协调者的角度,在发起投票之后就进入了 WAIT 等待状态,等待所有参与者回复各自事务执行状态,并在收到所有参与者的回复后决策下一步是发送 commit提交 或 rollback回滚信息。
站在参与者的角度,当回复完协调者的投票请求之后便进入 READY 状态(能够正常执行事务),接下去就是等待协调者最终的决策通知,一旦收到通知便可依据决策执行 commit 或 rollback 操作。
两阶段提交协议原理简单、易于实现,但是缺点也是显而易见的,包含如下:
单点问题
协调者在整个两阶段提交过程中扮演着举足轻重的作用,一旦协调者所在服务器宕机,就会影响整个数据库集群的正常运行。比如在第二阶段中,如果协调者因为故障不能正常发送事务提交或回滚通知,那么参与者们将一直处于阻塞状态,整个数据库集群将无法提供服务。
同步阻塞
两阶段提交执行过程中,所有的参与者都需要听从协调者的统一调度,期间处于阻塞状态而不能从事其他操作,这样效率极其低下。
数据不一致性
两阶段提交协议虽然是分布式数据强一致性所设计,但仍然存在数据不一致性的可能性。比如在第二阶段中,假设协调者发出了事务 commit 通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了commit 操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
针对上述问题可以引入 超时机制 和 互询机制在很大程度上予以解决。
超时机制
对于协调者来说如果在指定时间内没有收到所有参与者的应答,则可以自动退出 WAIT 状态,并向所有参与者发送 rollback 通知。对于参与者来说如果位于 READY 状态,但是在指定时间内没有收到协调者的第二阶段通知,则不能武断地执行 rollback 操作,因为协调者可能发送的是 commit 通知,这个时候执行 rollback 就会导致数据不一致。
互询机制
此时,我们可以介入互询机制,让参与者 A 去询问其他参与者 B 的执行情况。如果 B 执行了 rollback 或 commit 操作,则 A 可以大胆的与 B 执行相同的操作;如果 B 此时还没有到达 READY 状态,则可以推断出协调者发出的肯定是 rollback 通知;如果 B 同样位于 READY 状态,则 A 可以继续询问另外的参与者。只有当所有的参与者都位于 READY 状态时,此时两阶段提交协议无法处理,将陷入长时间的阻塞状态。
三阶段提交协议
第一阶段:预询盘
该阶段协调者会去询问各个参与者是否能够正常执行事务,参与者根据自身情况回复一个预估值,相对于真正的执行事务,这个过程是轻量的,具体步骤如下:
协调者向各个参与者发送事务询问通知,询问是否可以执行事务操作,并等待回复; 各个参与者依据自身状况回复一个预估值,如果预估自己能够正常执行事务就返回确定信息,并进入预备状态,否则返回否定信息。
第二阶段:预提交
本阶段协调者会根据第一阶段的询盘结果采取相应操作,询盘结果主要有 3 种:
所有的参与者都返回确定信息。 一个或多个参与者返回否定信息。 协调者等待超时。
针对第 1 种情况,协调者会向所有参与者发送事务执行请求,具体步骤如下:
协调者向所有的事务参与者发送事务执行通知; 参与者收到通知后执行事务但不提交; 参与者将事务执行情况返回给客户端。
在上述步骤中,如果参与者等待超时,则会中断事务。针对第 2 和第 3 种情况,协调者认为事务无法正常执行,于是向各个参与者发出 abort 通知,请求退出预备状态,具体步骤如下:
协调者向所有事务参与者发送 abort 通知; 参与者收到通知后中断事务。
第三阶段:事务提交
如果第二阶段事务未中断,那么本阶段协调者将会依据事务执行返回的结果来决定提交或回滚事务,分为 3 种情况:
所有的参与者都能正常执行事务。 一个或多个参与者执行事务失败。 协调者等待超时。
针对第 1 种情况,协调者向各个参与者发起事务提交请求,具体步骤如下:
协调者向所有参与者发送事务 commit 通知; 所有参与者在收到通知之后执行 commit 操作,并释放占有的资源; 参与者向协调者反馈事务提交结果。
协调者向所有参与者发送事务 rollback 通知; 所有参与者在收到通知之后执行 rollback 操作,并释放占有的资源; 参与者向协调者反馈事务回滚结果。
在本阶段如果因为协调者或网络问题,导致参与者迟迟不能收到来自协调者的 commit 或 rollback 请求,那么参与者将不会如两阶段提交中那样陷入阻塞,而是等待超时后继续 commit,相对于两阶段提交虽然降低了同步阻塞,但仍然无法完全避免数据的不一致。两阶段提交协议中所存在的长时间阻塞状态发生的几率还是非常低的,所以虽然三阶段提交协议相对于两阶段提交协议对于数据强一致性更有保障,但是因为效率问题,两阶段提交协议在实际系统中反而更加受宠。
TCC模式
Try:负责预留资源(比如新建一条状态=PENDING的订单);
做业务检查,简单来说就是不能预留已经被占用的资源;
隔离预留资源。
Confirm:负责落地所预留的资源
真正的执行业务使用try阶段预留的资源,幂等。
Cancel:负责撤销所预留的资源
需要用户根据自己的业务场景实现 Try、Confirm 和 Cancel 三个操作;事务发起方在一阶段执行 Try 方式,在二阶段提交执行 Confirm 方法,二阶段回滚执行 Cancel 方法。
关于预留资源要多说两句,资源都是有限的,因此预留资源都是有时效的,如果当预留资源迟迟得不到Confirm——我们将这种情况称为timeout——参与方会自行将其Cancel。也就是说参与方对于资源具有自我管理能力,这样可以避免因发起方的问题导致资源被长期占用。
TCC增加了业务检查和撤销事务的功能。同时,TCC将2PC数据库层面的动作提升到了服务层面,不同的是TCC的所有动作都是一个本地事务,每个本地事务都在动作完成后commit到数据库:
Try相当于2PC的Commit request phase,外加了业务检查逻辑 Confirm相当于2PC的Commit phase的commit动作 Cancel相当于2PC的Commit phase的rollback动作
流程步骤:
发起方发送Try到所有参与方 每个参与方执行Try,预留资源 发起方收到所有参与方的Try结果 发起方发送Confirm/Cancel到所有参与方 每个参与方执行Confirm/Cancel 发起方收到所有参与方的Confirm/Cancel结果
流程和两阶段提交非常类似。
1、985副教授工资曝光
2、心态崩了!税前2万4,到手1万4,年终奖扣税方式1月1日起施行~
3、雷军做程序员时写的博客,很强大!
4、人脸识别的时候,一定要穿上衣服啊!
5、清华大学:2021 元宇宙研究报告!
6、绩效被打3.25B,员工将支付宝告上了法院,判了
相关资源