分布式服务架构 - 彻底解决分布式系统一致性的问题

2.1 什么是一致性

指分布式服务化系统之间的 弱一致性,包括 应用系统的一致性 和 数据的一致性。

2.2 一致性问题

同步调用超时、异步回调超时、系统间状态不一致、缓存和数据库不一致、本地缓存节点不一致等

2.3 解决一致性问题的模式和思路

2.3.1 酸碱平衡理论

    1. ACID(酸)
    1. CAP(帽子原理)
      一致性、可用性、分区容忍性。只能同时满足2点。而分布式服务化需要满足 分区容忍性, 所以需要在 C和A间权衡。
    1. BASE(碱)
      解决了CAP的A和P不可兼得的问题。
      其满足CAP原理,但是通过牺牲强一致性获得可用性。
      软状态:
      是实现BASE思想的方法,基本可用和最终一致是目标。
      系统在进行每步操作时,通过记录每个临时状态,在系统出现故障时可以从这些中间状态继续处理未完成的请求或者退回到原始状态,最终达到一致状态。
      例如:
      持久化执行的状态和环境信息,通过定时任务捞取未执行的数据。一般采用DB来记录中间的 软状态
  • 4.对酸碱平衡的总结
    记录事务的软状态(中间状态、临时状态),若出现不一致,则系统自动化捞取修复。

2.3.2 分布式一致性协议

    1. 两阶段提交
      存在的问题:单点阻塞、单点故障、数据不一致
    1. 三阶段提交
      改进:增加了询问(较少了锁定冲突)、增加了超时机制
      问题:数据不一致问题依然存在,只是减少了点而已。
    1. TCC
      问题:复杂

2.3.3 保证最终一致性的 通用模式

引言:TCC也是过于复杂的,要实现t,c,c多个接口,略显臃肿。现实系统的底线是 仅仅需要达到最终一致性,而不是需要复杂的一致性协议。以下是一些非常有效,并且简单的模式。

    1. 查询模式
    1. 补偿模式
      补偿:
      为了让系统最终达到一致状态而做出的努力都叫做 补偿。
      补偿操作根据发起形式分为:
      自动恢复:程序根据发生不一致的环境,通过继续进行未完成的操作,或者回滚已经完成的操作,来自动达到一致状态。
      通知运营:
      技术修复:
    1. 异步确保模式
      是补偿模式的一个典型案例,应用在对响应要求不高的场景。
    1. 定期校对
      问题:如何发现需要补偿的操作
      答案:通过唯一ID串联所有记录
      问题:唯一ID怎么生成
    1. 可靠消息模式
      引言:为什么需要
      回答:即使消息系统,如kafka可以通过设定发送方式为同步发送来实现消息发送的同步性和ack。但是如果kafka短暂不可用,咋整?还是需要业务方通过DB先存储一份,等kafka可用后再发送,这样,无论如何都能保证消息可靠发送。
      当然,如果公司有kafka可以通过集群冗余+同步发送模式,那么应该可以保证消息发送后的不丢失,但是还是保证不了消息的可靠发送!!!
      a. 消息的可靠发送
      a.1 在发送消息之前将消息持久到数据库,状态标记为 待发送,然后发送消息,如果发送成功,则将消息改为发送成功。定时任务定时捞取异常数据。
      当然,也可以由第三方来持久化消息+捞取
      b. 消息处理器的幂等性
  • 6.缓存一致性模式
    用分布式缓存,不要使用本地缓存。
    数据库与缓存只需要保持 弱一致性,而不需要强一致性(此观点再议。。。。)

2.4 超时处理模式

2.4.1 微服务的交互模式 - 分为3类

  • 同步调用
    适用于 大规模、高并发 的 短小 操作,而不适用于 后端负载较高(即处理逻辑较重、耗时)的场景。
    正例如:jdbc都是阻塞型的同步调用,因为都是大规模、高并发、短小(sql耗时短)。
  • 异步调用:异步回调
    适用于非核心链路的 负载较高的环节,这个环节经常耗时较长、并对时效性要求不高。
  • 消息队列异步处理模式
    适用于 上游不关心下游的处理结果,下游也不需要向上游返回处理结果的场景。例如发布人员入职消息,供各方监听。

2.4.2 同步与异步的 抉择

如果性能不是问题,或者处理的都是高并发短小操作,那么选择同步比较理想,也能避免引入异步回调的复杂性。
如果业务允许、产品交互允许、处理耗时等,可以选择异步。

2.4.3 交互模式下 超时问题 的解决方案

A:同步调用的超时
  • 引言:一般有2种方案
    两状态:成功、失败
    三状态:成功、失败 和 处理中
  • 两状态的同步接口
    快速失败的方式。在失败时,可采用重试,但要主要幂等
  • 三状态的同步接口
    返回给使用方一个中间状态。
    倾向于给用户更好的体验,后台尽最大努力成功处理用户请求。
    超时解决方案是:
    等待使用方查询,使用方可能采取重试,这样服务方保证幂等。服务方不需要通知,也实现不了。
B:异步调用模式下的解决方案
  • 引言:返回状态一般有2种: 受理 和 未受理。 异步处理返回结果的通知也是2种:处理成功和失败

  • 异步调用接口超时
    超时解决方案:
    跟同步的两状态、三状态一样:通过 查询 来补齐状态,并根据状态来判断是继续重试还是咋地。

  • 异步调用内部超时
    超时解决方案:
    除了跟三状态的一样外,还需要在 处理成功后,异步回调通知使用方。

  • 异步调用回调超时
    超时解决方案:补偿兜底,确保回调通知一定可送达(以回调结果为准)。回调频率可采用 指数回退。

C:消息队列异步处理模式的解决方案
  • 生产者超时
    超时解决方案:参照 可靠消息模式部分(通过DB先落数据来解决,类似于 WAL 预写日志)
  • 消费者超时
    消费者直到真正消费成功时,才能从服务器移除消息!

2.4.4 超时补偿的原则

  • 补偿模式有 调用方补偿 和 接受方补偿 2种。(上边的超时处理方法也是2种 快速失败 和 内部补偿)
  • 服务间调用超时的补偿原则
    1.接收方应该先 持久化 消息或者数据,才能告诉发起方接收成功。随后接收方才开始处理持久的消息。防止服务进程被杀等导致数据丢失。
    2.如果接收方没有给出明确的接收响应(返回了异常或返回状态不对),那么发起方应该持续重试,直到接收方明确表示已经接收消息。(接收方幂等、滤重)

你可能感兴趣的:(分布式服务架构 - 彻底解决分布式系统一致性的问题)