zoukankan      html  css  js  c++  java
  • 微服务框架下的数据一致性第一篇

      微服务作为当下最火热的服务框架,其给我们开发带来了很多的好处,例如功能复用,独立部署,系统容错等,但是同时也有一些不方便的地方,其中最突出的就是数据一致性的问题,今天我们开始讨论一下这个数据一致性的解决方案:

       在没有使用微服务的时候我们一般都是使用同一个数据库,只要我们使用ACID的数据强一致性就可以解决问题,但是微服务下不同的模块使用不同的数据库,这样就无法保证数据的一致性,我们就需要讨论新的方案----分布式下的数据一致性问题。首先我们需要了解的是两个理论:CAP理论和BASE理论

      CAP理论
        CAP 是指在一个分布式系统下, 包含三个要素:Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),并且三者不可得兼。

        C:Consistency,一致性,所有数据变动都是同步的。

        A:Availability,可用性,即在可以接受的时间范围内正确地响应用户请求。

        P:Partition tolerance,分区容错性,即某节点或网络分区故障时,系统仍能够提供满足一致性和可用性的服务。

      在分布式系统下,我们保证了分区容错性,所以只能在可用性和数据一致性上面做取舍,现实决定了我们只能选择可用性,所以数据的一致性我们只能通过后期的补偿机制来达到了。

      BASE理论:
        BASE 理论主要是解决 CAP 理论中分布式系统的可用性和一致性不可兼得的问题。BASE 理论包含以下三个要素:

        BA:Basically Available,基本可用。

        S:Soft State,软状态,状态可以有一段时间不同步。

        E:Eventually Consistent,最终一致,最终数据是一致的就可以了,而不是时时保持强一致。

      BASE理论与ACID的数据库强一致性不同,是对CAP理论的支持,通过牺牲强一致性来保证系统的可用性,这样会导致数据在一段时间内可能出现不同步的情况,一旦出现异常,需要进行回滚等操作。但是这样的操作也是可以达到最终的数据一致性的。

      介绍完上面的理论,下面的我们看一下我们正在使用的分布式解决方案吧!

      方案主要是分为三个模块,上游应用主要是处理业务并发送MQ消息,可靠消息服务和MQ消息组件负责协调上下游消息的传递并保证数据的一致性,下游应用负责监听MQ消息并执行自身的业务。如图所示:

      

      第一阶段:

      注意点:上游应用将本地执行和消息发送绑定在同一事务中,要么同时成功,要么同时回滚

      步骤:
        上游应用发送待确认消息到可靠消息系统----不会导致出现一致性问题

        可靠消息系统保存待确认消息并返回----不会导致出现一致性问题

        上游应用执行本地业务----不会导致出现一致性问题

        上游应用通知可靠消息系统确认业务已执行并发送消息----会导致出现一致性问题

        可靠消息系统修改消息状态为发送状态并将消息投递到 MQ 中间件----会导致出现一致性问题

      上游应用执行完成,下游应用尚未执行或执行失败时,此事务即处于 BASE 理论的 Soft State 状态

       第二阶段:

      

      注意点:
        下游应用监听 MQ 消息并执行业务,并且将消息的消费结果通知可靠消息服务。

        可靠消息的状态需要和下游应用的业务执行保持一致,可靠消息状态不是已完成时,确保下游应用未执行,可靠消息状态是已完成时,确保下游应用已执行。

      步骤:
        下游应用监听 MQ 消息组件并获取消息----会导致出现一致性问题

        下游应用根据 MQ 消息体信息处理本地业务----会导致出现一致性问题

        下游应用向 MQ 组件自动发送 ACK 确认消息被消费----会导致出现一致性问题

        下游应用通知可靠消息系统消息被成功消费,可靠消息将该消息状态更改为已完成----会导致出现一致性问题

       为了确保上下游数据的最终一致性,在可靠消息系统中,需要开发消息状态确认和消息重发两个功能以实现 BASE 理论的 Eventually Consistent 特性。

    分析:

       在上游应用与消息中间件交互的时候,如果消息中间件或者上游应用发生宕机,就有可能没有将MQ消息发送出去,一旦发生这种情况,就会导致上游应用已经执行业务操作完毕,但是MQ消息并没有收到,上游应用也无法确认追踪到这一情况,最终导致无法给下游应用正确的反馈,数据最终一致。面对这种情况,我们通常会使用confirm机制和returnMessage机制来确认上游应用已经发送消息成功。总结下就是:

      如果消息没有到exchange,则confirm回调,ack=false

      如果消息到达exchange,则confirm回调,ack=true

      exchange到queue成功,则不回调return

      exchange到queue失败,则回调return(需设置mandatory=true,否则不回回调,消息就丢了)

      在下游应用与消息中间件交互的时候,如果发生宕机的情况,就会发生下游业务执行完成,但是MQ并未接收到反馈消息,这个时候MQ还是一直会向其发送消息,这个时候就需要保证接口的幂等性了。

      上游应用对应的是消息状态确认,下游应用对应的是消息重发。以上就是我们系统解决分布式系统下数据一致性的方案的思路。

      Confirm机制的最大优点在于异步,生产者在发送消息以后,即可继续执行其他任务。而服务器返回Confirm后,会触发生产者的回调函数,
    生产者在回调函数中处理Confirm信息。如果消息服务器发生异常,导致该消息丢失,会返回给生产者一个nack,表示消息已经丢失,这样生产者就可以通过重发消息,
    保证消息不丢失。Confirm机制在性能上要比事务优越很多。但是Confirm机制,无法进行回滚,就是一旦服务器崩溃,生产者无法得到Confirm信息,
    生产者其实本身也不知道该消息是否已经被持久化,只有继续重发来保证消息不丢失,但是如果原先已经持久化的消息,并不会被回滚,这样队列中就会存在两条相同的消息,系统需要支持去重。

    代码地址:https://github.com/shouchengdai/rabbitmq_test

    参考博客:

      http://www.cnblogs.com/study-everyday/p/7605619.html?tdsourcetag=s_pctim_aiomsg

        https://www.jishux.com/p/9faed5edeec96a46?tdsourcetag=s_pctim_aiomsg

     

  • 相关阅读:
    六、显式锁和AQS
    五、原子操作(CAS)
    四、线程的并发工具类
    BZOJ 2176 Strange string ——最小表示法
    BZOJ 2882 工艺 ——后缀自动机 最小表示法
    Codeforces Round #401 (Div. 2)
    BZOJ 2331 [SCOI2011]地板 ——插头DP
    BZOJ 2005 [Noi2010]能量采集 ——Dirichlet积
    BZOJ 1087 [SCOI2005]互不侵犯King ——状压DP
    BZOJ 1072 [SCOI2007]排列perm ——状压DP
  • 原文地址:https://www.cnblogs.com/daishoucheng/p/9838773.html
Copyright © 2011-2022 走看看