分布式服务架构-第二章 彻底解决分布式系统一致性的问题
1. 什么是一致性拆分:水平拆分:由于单一节点无法满足性能需求,需要扩展为多个节点,多个节点具有一致性的功能,组成一个服务池,一个节点服务一部分请求量,所有节点共同处理大规模高并发的请求量。垂直拆分:按照功能进行拆分,复杂的功能拆分为多个单一简单的功能,不同的单一功能组合在一起,和未拆分前完成的功能是一样的。一致性指:分布式服务化系统之间的弱一致性,包括应用系统的一致性和数据的一致性。2. 一致性
1. 什么是一致性
拆分:
- 水平拆分:由于单一节点无法满足性能需求,需要扩展为多个节点,多个节点具有一致性的功能,组成一个服务池,一个节点服务一部分请求量,所有节点共同处理大规模高并发的请求量。
- 垂直拆分:按照功能进行拆分,复杂的功能拆分为多个单一简单的功能,不同的单一功能组合在一起,和未拆分前完成的功能是一样的。
一致性指:分布式服务化系统之间的弱一致性,包括应用系统的一致性和数据的一致性。
2. 一致性问题
- 案例1:下订单和扣库存
- 案例2:同步调用超时
- 案例3:异步回调超时
- 案例4:掉单
- 案例5:系统间状态不一致
- 案例6:缓存和数据库不一致
- 案例7:本地缓存节点间不一致
- 案例8:缓存数据结构不一致
3.解决一致性问题的模式和思路
3.1酸碱平衡理论
3.1.1ACID(酸)
具有ACID的数据库具有强一致性,本身不会出现不一致
- A:Atomicity 原子性
- C:Consistency 一致性
- I:Isolation 隔离性
- D:Durability 持久性
3个典型是关系数据库 Oracle, Mysql, DB2 都保证强一致性,都是通过MVCC实现的
3.1.2CAP(帽子原理)
- C: Consistency 一致性
- A:Availability 可用性
- P: Partition tolerance 分区容忍性,尽管网络上有部分消息丢失,但系统仍然可继续工作
任何系统只可同时满足以上两点,必须在一致性和可用性之间权衡
3.1.3BASE(碱)
在不同场景下,可以分别利用acid和base来解决分布式服务一致性问题
BASE满足CAP原理,通过牺牲强一致性获得可用性
- BA: 基本可用
- S:软状态,状态可以在一段时间内不同步
- E:最终一致性
系统在每步操作时,通过记录每个临时状态,在系统出现故障时可以从这些中间状态继续处理,未完成的请求或者退回到原始状态,最终达到一致状态。
3.1.4对酸碱平衡的总结
实践经验
- 使用向上扩展并运行专业的关系型数据库能够保证强一致性,能用向上扩展解决的问题都不是问题
- 向上扩展成本高,可以对廉价硬件运行的开源关系数据库进行水平伸缩和分片。
- 业务规则现在,无法将相关数据分到同一个分片上,需事先最终一致性,记录事务软状态时出现不一致通过系统自动化或人工干预修复不一致。
3.2分布式一致性协议
分布式事务处理模型4种角色:应用程序,事务管理器,资源管理器,通信资源管理器。
- 事务管理器:通观全局的管理者
- 资源管理器和通信资源管理器是事务的参与者
协议
- TX协议:定义应用程序与事务管理器之间的接口
- XA协议:定义事务管理器与资源管理器之间的接口
3.2.1两阶段提交协议
XA协议根据两阶段提交来保证事务的完整性,实现分布式服务化的强一致性
两个阶段:两个阶段都是由事务管理器(协调者)发起的。资源管理器(参与者)
- 准备阶段:协调者向参与者发起指令,参与者评估自己的状态。
- 参与者评估指令可以完成 — 写redo或者undo日志,锁定资源,执行操作,但不提交
- 提交阶段:
- 每个参与者明确返回准备成功,即预留资源和执行操作成功,协调者向参与者发起提交指令,参与者提交资源变更事务,释放锁定的资源
- 有一个失败,即预留资源或者执行操作失败,则协调者向参与者发起中止指令,参与者取消已经变更事务,执行undo日志,释放锁定的资源。
准备阶段锁定资源,重量级操作,致命问题:
- 阻塞:
- 单点故障:
- 脑裂:
3.2.2三阶段提交协议
通过超时机制解决两阶段的阻塞问题
- 询问阶段:协调者询问参与者是否可以完成指令,协调者只需回到是或不是,不需要真正的操作,这个阶段超时会导致中止。
- 准备阶段:
- 所有参与者都返回可以执行操作,协调者向参与者发送执行请求,参与者写redo和undo日志。执行操作但不提交
- 询问阶段任何一个参与者不能执行操作的结果,则协调者向参与者发送中止请求。
- 提交阶段:
- 每个参与者在准备阶段返回准备成功,协调者向参与者发起提交指令,参与者提交资源变更的事务,释放锁定资源。
- 任何参与者返回准备失败,则协调者向参与者发起中止指令,参与者取消已经变更的事务,执行undo日志。释放锁定的资源。
三阶段和两阶段区别
- 增加了一个询问阶段
- 在准备阶段后,协调者和参与者执行的任务中都增加了超时,一旦超时,则协调者和参与者都会继续提交事务,默认为成功。
3.2.3TCC
将任务拆分成Try,Confirm,Cancel三个步骤。
3.3保证最终一致性的模式
3.3.1查询模式
向外部输出操作执行的状态,调查询接口获取服务操作执行状态,为了实现查询,每个服务都需要有唯一的流水号标识。
3.3.2补偿模式
为了让系统达到一致状态而做的努力叫做补偿。
- 自动恢复
- 通知运营
- 技术运营
3.3.3异步确保模式
补偿模式的典型案例。好处:能够对高并发流量削峰
实践中将要执行的异步操作封装后持久入库,通过定时捞取未完成任务补偿操作来实现异步确保模式。
3.3.4定期校对模式
如何发现需要补偿操作?
在操作主流程中的系统间执行校对操作,可以在事后异步地批量校对操作的状态,发现不一致,补偿。
实现定期校对的一个关键就是分布式系统中需要有一个自始至终唯一的ID
全局唯一ID:
- 持久型:
- 时间型:
分布式系统迅速定位问题,通过分布式系统的调用链跟踪系统进行,能够跟踪一个请求的调用链。
第三方定期核对系统,发现问题,补偿方式解决问题。
3.3.5可靠消息模式
- 消息的可靠发送:尽最大努力发送消息通知
- 发送消息前将消息持久到数据库,状态标记为待发送,发送,成功,修改为发送成功。定时任务捞取失败消息再发送
- 持久消息的数据库是独立的,不耦合在业务系统中。发送前先发送一个预消息给某个第三方的消息管理器,消息管理器将其持久到数据库,标记为待发送,发送成功,标记成功,定时任务处理失败。
- 消息处理器的幂等性:保证消息发出去会有重试机制,重试保证幂等性。
- 使用数据表的唯一键进行滤重,拒绝重复的请求
- 使用分布式表对请求进行滤重
- 使用状态流转的方向性滤重,通常使用数据库的行级锁来实现
- 根据业务特点,操作本身就是幂等性
3.3.6缓存一致性模式
常见需求:亿级的读需求–缓存抗住读流量
实践:
- 性能要求不高,尽量使用分布式缓存,不使用本地缓存
- 写缓存时数据一定要完整,
- 使用缓存牺牲了一致性,为了提高性能,数据库与缓存只需要保持弱一致性,不需要保持强一致性,
- 读的顺序是先读缓存,后读数据库,写的顺序先写数据库,后写缓存
4.超时处理模式
4.1微服务的交互模式
同步调用模式,接口异步调用模式,消息队列异步处理模式
- 同步调用模式:适用于大规模高并发的短小操作,不适合后端负载较高的场景
- 接口异步调用模式:非核心链路上负载较高的处理环节,耗时长且对时效性要求不高
- 消息队列异步处理模式:充分解耦,流量削峰,多用于非核心链路上负载较高的处理环节中,并且服务的上游不关心下游的处理结果,下游也不需要向上游返回处理结果。
4.2同步和异步的抉择
- 尽量使用异步来替换同步操作(从业务功能角度出发)
- 能用同步解决的问题,不要引入异步(从技术和架构角度出发)
4.3交互模式下超时问题的解决方案
4.3.1同步调用模式下的解决方案
返回状态的定义
- 成功和失败–两状态的同步接口
- 成功,失败和处理中–三状态的同步接口
-
两状态的同步接口
- 使用方调用此同步接口超时:使用方查询模式,异步查询处理结果,获得结果做响应处理
- 成功:下一步
- 失败:重试
- 如果查询返回的是未知请求,使用方超时,实际没有接收到或者还没有接收到一开始的处理请求,服务使用方需要使用同一请求id去重试,实现请求处理的幂等性。
- 内部服务1调用内部服务2超时
- 服务1对外接口的契约中包含成功和识别,也是对使用方来讲,使用快速失败的策略。服务2冲正接口,冲正接口可以判断之前是否接受到处理请求
- 收到且做了处理,应该做反向回滚操作
- 未收到,忽略冲正请求,实现幂等性
- 服务1对外接口的契约中包含成功和识别,也是对使用方来讲,使用快速失败的策略。服务2冲正接口,冲正接口可以判断之前是否接受到处理请求
注:冲正(chōng zhèng)是为系统认为可能交易失败时采取的补救手法。即一笔交易在终端已经置为成功标志,但是发送到主机的账务交易包没有得到响应,即终端交易超时,所以不确定该笔交易是否在主机端也成功完成,为了确保用户的利益,终端重新向主机发送请求,请求取消该笔交易的流水,如果主机端已经交易成功,则回滚交易,否则不处理,然后将处理结果返回给终端。
- 使用方调用此同步接口超时:使用方查询模式,异步查询处理结果,获得结果做响应处理
-
三状态的同步接口
- 使用方调用发生超时:使用服务1查询接口,后续补齐处理状态
- 内部服务1调用服务2的过程超时:通信问题
- 可以返回给使用方一个中间状态,也就是处理中的结果,变相把同步接口变成异步接口,达到最终一致效果-尽最大努力成功处理用户发来的请求,系统尽最大努力补偿执行出错的部分,
4.3.2异步调用模式下的解决方案
返回给使用方状态:受理和未受理
异步处理返回结果的通知:处理成功和处理失败
- 异步调用接口超时:使用方调用,查询状态来补齐,根据状态判断
- 异步调用内部超时:内部服务1调用服务2,查询获取,根据状态补偿后续的操作(处理成功,需异步回调通知使用方)
- 异步调用回调超时:服务1通过回调通知使用方,服务1需要保证通知一定可送达,遇到超时,服务1服务站重新继续补偿,通常会设计一个通知时间按一定间隔递增的策略。
4.3.3消息队列异步处理模式的解决方案
多用于疏松耦合的项目,处理流程分为两个阶段:生产者投递和消费者处理
-
消息队列的生产者超时:定时任务捞取
-
消息队列的消费者超时:
- 自动增长消费的偏移量
- 手工提交消费的偏移量
如果允许丢消息,用自动增长,并发量高,性能好;如果要求准确性好,用手工提交消费偏移量
4.4超时补偿规则
处理方法:快速失败和内部补偿
补偿方式:调用方补偿和接收方补偿
5.迁移开关的设计
新老项目共存时
更多推荐


所有评论(0)