分布式系统的一致性问题分析和解决办法

谈到分布式都会讨论CAP问题的解决办法,分布式的CAP原理,CAP即一致性、可用性和分区容错性。

百度百科解释:CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。

在我们的应用中一致性出了问题,或者说之前根本没考虑没重视,这次遇到客户问题才引起了重视,不同场景的问题和解决办法如下:

1、同步接口一致性:

当用户操作时,首先考虑做到强一致性,即用户操作A服务,A服务调用B服务,这时候如果这两次调用都是写操作,那么要求两个事务必须一起成功或者一起失败,这时候可以考虑引入分布式事务框架,保证两个事务的一致性。

当不是用户操作时可以做到最终一致性,比如收到一条消息后要调用一个同步接口,这时候可以考虑做到最终一致性,目前考虑到时间的紧迫性先采用了补偿机制做到最终一致性,补偿到达一定次数上限,则停止补偿,并且提供UI对这些补偿提供监控,可以从UI重启某个补偿。

2、异步消息的一致性:

采用消息中间件主要为了做成异步处理,为了快速返回给调用端,要处理的事情另外处理,接口调用不需要等待处理完成后再返回,减少了调用端的等待,提高了TPS。

但是消息中间件也给我们带来了新的挑战,就是必须保证消息发送成功和消息被成功消费。RabbitMQ提供了这样的机制,开启发送确认模式和消费确认模式,消息持久化,消息事务等,持久化和消息事务结合起来使用很消耗性能,开启事务的前提是开启了持久化,意思就是保证消息持久化成功后,这个事务就成功提交,否则就失败了,开启消息事务大概会消耗不开启事务的10倍性能,所以这个方案不是很有必要。

换一个思路,如果我使用消息的确认机制呢?发送成功收到确认,就认为成功了,消息发送方在数据库记录消息发送成功,消费方在收到消息后,在数据库记录收到的消息,处理完业务后返回给消息队列一个确认消费成功的消息,这样也保证了消息被成功消费,就算消费者在处理过程中消费者宕机,那么消息队列没有收到确认消费就不会从队列删除这条消息,并且会把消息发送到其他消费者。不仔细想好像很完美,但是,有一个地方会丢消息,就是消息队列确认收到消息后,消息队列宕机,消费者根本没有消费,消息就丢掉了,这个我们好像无能为力了又没有开启持久化。为了解决这个问题,经过考虑,我们决定在消费者端增加一个消息回执,当消费者消费消息之后,消费者回执一个消息给生产者,告诉生产者,这条消息成功消费,生产者在对应的消息上标记为成功消费,另外在生产者端,还要加上补偿,即一条消息超过多长时间没有回执,生产者就再次发送一条消息,这样就一定能够保证消费成功了,这里也需要做UI去监控,某一条消息发送了多次,需要注意其原因。这样一来又有新的问题出现,比如消息发送过多,消息队列爆了怎么办?所以发送消息如果失败,消息队列如果能返回爆掉的错误代码,那么我们需要做一个熔断,短时间内不要向这个队列发送消息,过段时间再试,并且提供监控预警,通知运维人员及时查看为什么消息队列会爆。

消息队列带来的另一个问题是,消息消费的时序性,即,用户新增了一条记录又删除了它,这个动作要通过消息同步到另一个服务,在A服务中,先增加一条记录item1,发送msg_add item1,在A服务中,又将item1删除,发送msg_delete item1,B是这两条消息的消费者,B存在两个实例节点,恰好这两条消息被分配到两个实例节点,msg_delete item1被先消费,这个时候数据库里没有item1,删除执行后,另一个B实例消费msg_add item1,那么B服务的数据库中就会多出一条item1,这个时候item1在A和B服务的状态就不一致了,所以怎么保证消息消费的时序性呢?确保先发出来的消息先消费,查了相关资料,比较好的做法是,在消息中加上parent_msg_id,在生产者端如果对同一个object发消息,如果存在没有处理完成的消息,将其作为parent msg,发送给消费者,消费者接受到消息,先存库,消费者先处理parent_msg_id为空的消息(这个object没有先前的消息),这个消息一定是第一条,然后处理parent_msg_id不为空并且paren消息已经处理完成的消息(这个消息是依赖于有parent的消息处理状态的),这样就保证了消息的有序消费,不会导致消费者端的脏数据产生。

3、监控报表,对于分布式中的数据流转是否正确,需要一个链路追踪,一条数据来自于哪里,要能要溯源到,同时要做好全局的数据对账,比如在A服务中有多少条数据是什么状态,到B服务中理论上是什么状态,但是偏差了多少条数据,要有UI可见,这样一旦有问题可以及时发现并解决。

你可能感兴趣的:(程序人生)