当前位置: 首页 > 科技观察

微服务分布式一致性模式

时间:2023-03-15 18:39:21 科技观察

微服务拆分后遇到的麻烦之一就是分布后的一致性问题。单体架构的业务处理和数据都在一个进程中,一致性保证非常成熟,开发者基本不用关心。当业务系统拆分成不同的流程时,就会遇到技术一致性问题。这造成了一个纠结,我们希望有一个灵丹妙药可以一次性解决这个问题。但是,由于分布式一致性在(CAP)理论中并没有完美的解决方案,我们可以选择的解决方案是在具体业务场景下的选择。我们这里讨论的分布是指业务逻辑拆分造成的分布,而不是数据量特别大造成的分布。如果业务不拆分,数据量特别大,需要分布式,可以选择支持大数据的分布式数据库。可以选择Cassandra、MongoDB等NoSQL,也可以选择TiDB等支持SQL的分布式解决方案。如果业务拆分,无论选择什么数据库,都解决不了分布式一致性的问题。把数据库或者分布式数据库想象成一个系统,可以处理一个外部请求在数据库内部的分布式问题,但是不能处理多个外部请求的一致性问题。分布式强一致性数据库无法解决业务逻辑拆分带来的分布式一致性问题,我们还得继续纠结于如何解决业务分布式一致性问题。首先我把微服务分布式一致性问题分为数据共享一致性和业务事务一致性。1.数据共享一致性在单一架构下使用同一个数据库时,不存在数据共享问题。微服务强调独立的数据库,这就提出了如何共享数据的问题。数据共享分为拉取和推送两种模式。Pull是指消费者到供应商那里拉取数据,Push是指供应商主动将数据推送给消费者。1.pull-viewsharing对于一般的企业信息系统,数据量不大,并发要求也不大。我建议所有微服务都使用相同的数据库实例,但将它们拆分为不同的模式。这样做的好处是数据库在业务逻辑上是独立的,也可以独立演进。然后可以再次集中管理数据库。这种方案特别适合大型遗留系统的拆分,因为它原本是在一个库中,拆分数据库schema是为了业务更好的独立演进,可以延续原有的数据库实例管理技术。由于不同的微服务实际上运行在同一个数据库实例上,因此可以轻松创建视图以实现数据共享。需要注意的是不要拉出整个表格,根据需要选择几个字段。这种模式技术简单,但是有两个缺点:第一,因为视图同步的数据是实时的,应用程序可能是基于实时数据同步的假设来设计的,这会使得做分布式特别困难未来扩展;第二,视图很容易暴露表结构,需要特别加强视图的设计和结构管理,不要让暴露的视图直接绑定到已有的表结构上。视图需要的字段是外部需要的,而不是表上的内容。这样,视图是一个接口,但它与特定的数据库实例是强耦合的。2.Pull-API获取微服务最推荐的方式是服务提供者提供数据API,消费者需要的时候可以拉取。优点是消费端和供给端在技术上完全解耦,缺点是增加了开发成本。如果消费者使用API??方式获取需要的数据,建议使用异步Stream方式进行编程。如果一个业务请求需要拉取多个数据源,不建议采用同步方式调用,会延长处理时间。建议使用reactX模式进行异步拉取和组装。3.Push-EventMessage事件发生时发送消息是一种DDDCQRS模式,解决了消费者想要拥有数据的问题(根据需要建立本地数据结构、获取性能和方法),也解决了异构数据库技术问题。问题是需要消息传递平台,并且消费者或供应商必须耦合到消息传递平台技术。对于大型遗留系统的改造不是很友好。一方面,遗留系统的消息平台往往无法满足高并发、大数据量的性能需求。另一方面,新的微服务不想依赖旧的消息平台,而是想使用Kafka。一个高并发、轻量级的互联网消息传递平台。4、数据共享一致性选择总结:对于遗留系统改造和数据量小(日交易量不超过百万)的应用,建议使用不同的微服务创建不同的schema,但使用同一个数据库instance,然后通过数据共享的view方式。如果某些业务数据非常大,需要共享,使用API??共享,使用异步Stream编程进行数据共享。如果微服务平台的技术设施成熟,可以采用推送事件消息的方式,既解决了共享数据消费的便捷性问题,又解决了数据结构的解耦,使用轻量级的消息平台(Kafka)只有轻微的技术耦合。2.业务事务的分布式一致性业务事务的分布式一致性是指一个请求,却分布在不同的微服务系统中进行处理,这就导致了一致性协调的问题。事务分布式一致性分为补偿模式、二次提交模式和Saga模式。1.补偿模式补偿模式主要通过重试来实现最终的成功,只适用于业务中交易请求一定不能失败的场景。补偿模式最常见的用途是消息传递。假设你给A发消息,如果没有收到A确认消息已经收到,你就会继续发送,直到A确认你已经收到消息。有很多企业可以变成必须成功的交易。比如下单付款,如果先确认订单再扣款,可能会因为账户缺钱导致扣款失败,导致生意失败。如果业务改为确认订单前扣除货款,可以认为订单必须确认成功。一个事务必须成功的情况是通过业务顺序的调整来实现的。在技??术实现上比较简单,使用一个任务队列来跟踪任务的完成状态来决定重试。补偿模式要求API必须是幂等的,因为有可能任务已经成功,消费者不知道,又重新发送任务请求。2.二次提交模式由于补偿模式需要调整业务,适用范围比较小。我们还是希望有一个通用的分布式一致性方案。最著名的应该是二次提交模式,更具体地说是TCC(Try、Confirm、Cancel)。先发起一个try请求,让业务任务参与者准备好处理,等所有参与者都准备好后再发送confirm进行确认。因为所有的业务参与方都提前做好了准备,所以在确认阶段就可以保证一次成功。如果某个参与者认出了它,则发送取消以回滚。这种模式与数据事务管理基本相同。与Java的JTA实现一样,Automikos支持数据库事务和RESTAPI。二次提交虽然可以解决事务一致性问题,但是成本比较高。一个业务流程必须拆分为准备确认和执行两个阶段,对业务设计和开发成本要求比较高。3.Sagas模式Sagas模式简单,可以广泛支持补偿模式和二次提交模式的分布式事务场景。二次提交模式基于悲观锁,因此要求所有任务参与者在执行前做好准备。Saga和补偿模式都是基于乐观锁,让任务参与者先执行,如果执行没有响应再要求再执行。Saga在向参与者发送任务后会记录一个事件(Saga的中文翻译可以是事迹),所有的事件都会被持久化。如果某个参与者执行失败,则发出取消请求,要求所有参与者回滚。因为大部分事务请求都是成功的,所以这种基于乐观锁的协调机制可以做到一致性,降低开发成本,业务设计也比较容易理解。目前支持Saga的Java框架是华为开源的servicecombsaga,京东已经在部分在线系统中使用。还有axoniq,一个CQRS的框架,同样实现了saga。【本文为专栏作家“张艺”原创稿件,转载请联系原作者】点此阅读更多该作者好文