分布式服务架构(二)

2021-07-16 15:28:33 浏览数 (1)

ACID

A:原子性

C:一致性

I:隔离性

D:持久性

具有ACID的数据库支持强一致性,强一致性代表数据库本身不会出现不一致的线性,每个事务都是原子性,要么成功,要么失败,事物间具有隔离性,且互不影响,而且最终状态是持久化的。

但是在互联网的时代,项目大多数都是大规模高并发的特性,必须使用拆分理论,对高并发的压力,分而治之,大而化小,小而化了,否则难以支持亿级流量,即使关系型数据库,单机也难以支持存储和吞吐量的性能需求,如果必须要这样做,就应尽量把数据放到数据库一个分片上,这样就可以利用数据库解决不一致的问题,

CAP

C:一致性,在分布式系统中,每一个节点有所有数据的备份,同一时刻具有同样的值,同一时刻读取的数据是一致的,最新的数据

A:可用性,好的响应性能,完全的可用性指的是任何故障下,服务都会在有限时间内处理完并进行相应

P:分区容错行,尽管网络上有部分消息丢失,但是系统仍然可以继续工作。

BASE

BA:Basically Available,基本可用

S:软状态,状态可以在一段时间内不同步

E:Eventually Consistent,最终一致,在一定的时间窗口内,最终数据达成一致即可

软状态是实现BASE的思想的方法,基本可用和最终一致是目的,BASE由于不是强一致性,所以系统会存在短暂不一致的状态,在这个短暂的时间里面,记录每一个操作的临时状态,通过每个临时状态,在系统出现问题的时候,可以通过这个临时状态,可以继续执行或者进行回滚处理,最终达到一致性

解决一致性问题的总结

  • 使用强悍的硬件并运行专业的关系型数据库如oracle,Mysql,能够保证一致性,能够用硬件解决的问题都不是问题
  • 使用强悍的硬件还是成本太高,因此使用关系型数据库进行水平伸缩和扩展,将相关的数据分到数据库的同一个分区,任然可以解决数据一致性问题
  • 由于业务限制,并不能将数据放到一个数据库分片,因此我们记录事务的软状态,如果出现不一致,就可以通过系统自动化或者人工干预修复不一致的问题

分布式一致性协议

二阶段提交协议

  • 准备阶段,协调者向参与者发起指令,参与者评估自己的状态,如果参与者评估自己可以完成,就会写undo或redo,锁定资源,但是不提交
  • 提交阶段,如果每个参与者在准备阶段都返回成功,也就是预留资源和执行操作成功,则协调者向参与者发起提交指令,参与者提交资源变更的事务,释放资源,如果任何一个参与者明确返回准备失败,就是预留资源和执行失败,则协调器发送中止指令,参与者取消已经变更的事务,执行undo日志,释放资源,

二阶段提交在准备阶段锁定资源,这是一个重量级操作,但是能保证强一致性,实现复杂,成本高,不够灵活,

  • 阻塞,任何一次指令都必须收到明确的响应,否则一直阻塞,占用资源不释放
  • 单点故障,若协调者宕机,参与者没有协调者的指挥,就会阻塞,尽管可以选举新的协调者,但是如果协调者发送一个提交指令后宕机,而提交指令仅仅被一个参与者接受,并且参与者接受后也宕机了,则新的协调者也不能处理
  • 脑裂,协调者发送指令,有的参与者接受到了,有的参与者没有接受到,多个参与者出现不一致的状态

三阶段提交

三阶段解决了二阶段一直阻塞的问题,引入了超时机制,并且引入了询问的阶段

  • 询问阶段,协调者就是问问参与者能否完成指令,参与者只要回复可以或不可以,这个阶段超时导致中止,
  • 准备阶段,如果询问都回复可以,那么准备阶段协调者就会发起执行请求,然后写undo,redo日志,执行操作但不提交,如果询问有一个返回不可以,就会发送中止请求,这个阶段超时导致成功。
  • 提交阶段,如果每个参与者才准备阶段成功返回,这协调者就会发送提交操作指令,参与者提交变更的事务,释放资源,若干任何参与者返回失败,则协调者就会发起中止操作,参与者取消变更的事务,执行undo日志,释放资源,

三阶段和二阶段有以下不同

  • 增加了一个询问阶段,为了尽可能早点发现无法执行操作而中止行为,但是只能减少这种情况发生,不能完全避免
  • 在准备阶段,加入了超时机制,一旦超时,协调者和参与者都会继续执行提交事务,默认成功

三阶段协议和二阶段相比,一旦发生超时,系统仍然会发生不一致,但是可以减少这种情况,好处就是不会阻塞和永远锁定资源

TCC协议

不管是二阶段还是三阶段在极端情况下,可能产生阻塞,以及数据不一致的,并且实现比较复杂,此时就提出了TCC协议

TCC分为三个阶段,一个是尝试执行,如果执行没有问题,就会执行confirm,如果执行出现了问题,就会执行cancel操作,看起来和二阶段提交协议没有差别,但是当执行出现问题的时候,有一定的自我修复能力,如果参与者出现了问题,协调者就会通过执行操作的逆操作来达到最终一致性状态,

当然TCC也有许多问题,例如如果有些参与者接收到了请求,有些没有接收到,整个系统然仍处于不一致的,这种情况,往往是自动修复,如果无法修复,就必须有人工参与解决.

保证最终一致性的模式

二阶段和三阶段实现复杂且有的一定的自身问题,TCC,实现协议更简单,容易实现,但是由于每个服务都要进行Try,confirm,和cancel,略显臃肿,因此系统的底线是仅仅需要达到最终一致性,而不是需要实现专业,复杂的一致性协议,实现最终一致性有些非常有效的模式

  1. 查询模式

任何服务操作都需要提供一个查询接口,用来向外部输出操作执行的状态,服务操作的使用方可以通过查询接口得知服务操作执行的状态,然后根据不同状态做不同的处理操作

2.补偿模式

上面的查询模式,在任何情况下,我们可以知道服务的状态,如果整个操作处于不正常状态,则我们需要修正操作中间有问题的子操作,这可能要重新执行未执行的子操作,后者取消已经完成的子操作,通过修复使得整个操作系统达到一致性,为了系统最终达到一致状态而做的努力叫做补偿

补偿分为以下几种

  • 自动恢复,程序根据不一致的环境,通过继续完成未执行的操作,或者回滚已经完成的操作,最终达到一致性
  • 通知运营,如果程序无法自动恢复,并且设计考虑了不一致的场景,则可以提供运营功能,通过手工补偿
  • 技术运营,有些问题,必须要通过技术手段进行修复,包括数据库变更,或者代码变更

3.异步确保模式

对于主流程响应时间要求不太高的场景中,通常把这类操作单独拿出来,通过异步的方式进行处理,然后把结果通知通知系统通知服务使用方。

实践中我们把要执行的异步操作封装后持久化入库,然后通过定时任务捞取任务进行补偿操作实现异步确保模式,只要定时系统足够健壮,则任何任务最重都会被成功执行

4.定时校验模式

在分布式系统中构建了唯一的id,调用链的等基础设施后,我们可以很容易对系统间的不一致进行核对,通常需要第三方的定时核对系统,从第三方监控服务执行的健康程度.

定期校对模式多应用于金融系统,金融系统由于涉及资金安全,需要保证准确性,所以需要多重的一致性保证机制,包括商品交易对账,系统间一致性对账现金对账等,这些都是定期校对模式。

5.可靠消息模式

在分布式系统中,我们经常使用的就是上面提到的异步确认模式,为了让一步操作的调用方和被调用方充分的解耦,采用消息队列,具有可以伸缩性,可分片,可持久化等,

  • 消息的可靠发送 消息的可靠发送认为是尽最大努力发送消息通知,有两种方式

第一种就是上图,发送消息之前就把消息进行持久化,标记为待发送,然后发送消息,如果成功,则将消息标记为发送成功,定时任务定时把未发送的消息并将消息发送

第二种就是上图,和第一种不同就是持久化消息的数据库是独立的,并不耦合在业务系统,发送消息前,先发送一个预发送消息,消息管理模块将其持久化,并标记待发送,在发送成功后,标记消息发送成功,定时任务定时从数据库捞取一定时间内未发送的消息,查询业务系统是否要继续发送,要根据查询结果来确定消息的状态,

超时处理模式

微服务之间通信和交互通过某种协议,然后网络通信是不确定的,我们必须考虑对网络的容错,特定是对调用超时问题的处理

服务之间服务交互模式有三种模式如下

同步调用

异步调用模式

消息队列异步处理模式

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

  1. 同步模式调用模式的解决方案 服务的处理结果会通过返回值返回给使用方,对返回的状态定义分为两种
    1. 成功和失败
    2. 成功和失败以及处理中

两种状态的同步接口有两种同步超时情况

第一种超时是当调用服务1的时候超时了,此时我们需要使用查询模式,查询处理的结果,获取到结果之后,做出相应的处理,如果成功就继续下面操作,如果失败了就会重试,请求再次处理,但是当查询的结果是异常的,这种情况,服务1实际上没有接受到请求,或者还没有接受到一开始的处理请求,服务适用方需要使用同一个请求id进行重试,当然服务1必须支持幂等性

第二种超时是在服务内部超时的,由于我们前提是只有两种状态,成功和失败,因此这里服务内部使用内部快速失败,同时如果服务2已经接受到了请求,且处理了,则进行回滚操作,否则忽略不做任何处理。

三种状态的同步接口有两种超时情况

三种状态的同步接口超时,服务1超时,和上面两种状态的处理方案一样,而如果服务1调用服务2超时,就不一样了

因为三种状态的同步接口支持中间状态,因此可以返回给使用方一个中间状态,变相的把同步接口变成异步接口,达到最终一致性结果

这种场景下,我们尽最大努力成功处理用户发送的请求,因此服务1调用用服务2超时,我们返回助理中的状态,随后系统尽最大努力补偿执行出错的部分,服务1需要通过服务2的查询结果获取最新的请求处理状态,如果服务2没有明确回复,则可以尝试重新发送请求,服务2也要支持幂等性操作。

2,异步调用模式下解决方案

上图和同步两状态是一样,当服务1超时的时候,我们通过查询来补齐状态,并根据状态完后后续操作,

当内部超时的时候,这和三状态场景相似因此当服务1调用服务2超时,服务1需要根据服务2的最新状态,根据状态补偿后续操作,如果服务2根据最新状态,接受了请求,则继续后续操作,这种和同步三状态不一样的是,一旦处理成功,需要异步回调通知使用方,而三状态只需等待使用方查询,不需要通知,也无法实现,

当在异步返回的时候超时,此时服务1要保证通知一定可送达,如果超时,服务1负责重新继续补偿,通常会实际一个间隔递增的策略,保证通知到使用方.

消息队列异步处理模式解决方案

上面当请求处理,返回受理超时的时候,我可以使用消息可靠发送

当在服务2异步处理超时的时候,消息队列提供两种方式消费消息

  1. 自动增长消费的偏移量,在一个消费者从消费服务器中取走消息后,消队列的消息偏移量自动增加,一旦消息被消费,则不存在服务器中,如果处理失败,也无法从消息服务器中找回
  2. 手工提交偏移量,在一个消费者从消费服务器中取出消息后,先把消息持久化到本地数据库,然后告诉消费服务器已经消费消息,消费服务器才会移除消息,如果持久化失败,则消息任然存在于消费服务器中,消息还可以继续消费

0 人点赞