`
dalan_123
  • 浏览: 83919 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

使用消息系统避免分布式事务

 
阅读更多
首先举个栗子:比如通过支付宝向余额宝转账1000元,这样一种生活中很平凡的事情,却可以引出很多问题:如果系统宕机挂掉,交易没有完成?那么数据就出现了不一致。等等类似的事情,在各类系统中都能找到类似情形。那么也可以换句专业的说法:当一个表update之后,如何保证另外一个与之关联的表也能完成update。

1、本地事务:

    支付宝账户表:A  id uid amount

    余额宝账户表:B  id uid amount

     用户id:uid = 100

   执行上面的过程分两部分:

    1、支付宝账户表-1000:update A set amount=amount - 1000 where uid = 100;

    2、余额宝账户表+1000:update B set amount=amount + 1000 where uid = 100;

如何保证两部分都能够完成,保证两部分“收支平衡”

对数据库熟悉的同学会那么我们使用transaction(事务)不就解决了

BEGIN TRANSACTION

   update A set amount=amount - 1000 where uid = 100;

    update B set amount=amount + 1000 where uid = 100;

END TRANSACTION

COMMIT;

OK,上面的操作是没有问题的

那么对spring熟悉的同学也知道 其实在spring只需要使用注解就OK了

@Transactional(rollbackFor=Exception.class)

public void updateAmount(){

   updateA();

   updateB();

}

是的,没有错的。能够完成。但是这些情况只是针对系统规模小,数据表在一个数据库实例上的;那么系统规模大,对应的数据表分布在不同的数据库实例上,分布在不同的物理节点上,前面采用的本地事务的方式就无用武之地了。

2、分布式事务(两阶段提交协议)

两阶段提交协议经常用来实现分布式事务;一般需要两个角色:协调器C和若干个事务执行者Si;那么事务执行者多半是具体的数据库,同时协调器和事务执行器可在一台机器上。

   1、应用程序application发起一个请求到TC(事务协调器)

   2、TC(事务协调器)将消息写到本地日志,再向所有的SI(事务执行者)的发送消息。

   3、Si(事务执行者)接受到消息之后,执行本地事务但是不commit,如果成功返回yes否则no;同样返回      之前仍要进行日志记录。

   4、Tc(事务协调器)接受到所有执行器返回的结果,如果所有的执行全部返回yes,那么发送commit消息给各个执行器,本地事务执行commit;若是有一个返回no,那么tc就会发送abort消息给各个执行器

注:tc和si把发送和接收到的消息存放到本地日志里,主要为了故障恢复复用,如若某一个si从故障中恢复后,先检查本地日志的内容,如果已接收到commit则本地事务执行器commit;若是abort,则回滚;

若是yes则在tc询问,确定下一步;若是什么都没有则可能前面执行已经崩溃,需要回滚。

熟悉java的同学可以看:http://acen-chen.iteye.com/blog/1055481
采用分布式事务,也满足了我们前面的需求,同时新的问题随之而来

      1、两阶段提交涉及多个节点的网络通信,通信时间如果过长

       2、事务的相对时间长了,那么锁定资源的时间也就长了

               那么在高并发的服务中,就会存在严重的性能问题。

3、消息队列

在高并发的环境中,我们一般会采用消息队列来避免分布式事务的执行

这和实际生活中,我们去饭店吃饭很类似,首先点单,这时服务员给你一张小票,等待服务器给你端上你的饭菜。

  在使用消息队列我们需要做到可靠凭证的保存(分布式事务的消息),有如下两种方式

   方式1、支付宝完成扣钱的动作时,并记录消息数据,消息数据和业务数据在同一个数据库实例

   BEGIN TRANSACTION

     update A set amount=amount - 1000 where uid = 100;
     INSERT INTO MESSAGE(UID,AMOUNT,STATUS) VALUES(1,1000,1)
   END TRANSACTION
   COMMIT;

那么我们可以将支付宝完成扣钱操作的消息通过及时服务发给余额宝,余额宝完成处理返回成功消息,支付宝收到消息,清除消息表中对应的消息记录,即完成本次扣钱操作。

   方式2、

     1)支付宝在扣款事务提交之前,向实时消息服务请求发送消息,实时消息服务只记录消       息数据,而不真正发送,只有消息发送成功后才会提交事务;

     2)当支付宝扣款事务被提交成功后,向实时消息服务确认发送。只有在得到确认发送指令后,实时消息服务才真正发送该消息;

    3)当支付宝扣款事务提交失败回滚后,向实时消息服务取消发送。在得到取消发送指令后,该消息将不会被发送;

    4)对于那些未确认的消息或者取消的消息,需要有一个消息状态确认系统定时去支付宝系统查询这个消息的状态并进行更新。为什么需要这一步骤,举个例子:假设在第2步支付宝扣款事务被成功提交后,系统挂了,此时消息状态并未被更新为“确认发送”,从而导致消息不能被发送。

优点:消息数据独立存储,降低业务系统与消息系统间的耦合;

缺点:一次消息发送需要两次请求;业务处理服务需要实现消息状态回查接口
------------------------------------------------------------------------------------------------------------------------------------
那么如上的消息队列也就解决了我们实际业务中的高并发情况下分布式事务处理性能低下的问题

在使用消息队列防止重复投递消息

解决方法很简单,增加消息应用状态表(message_apply),通俗来说就是个账本,用于记录消息的消费情况,每次来一个消息,在真正执行之前,先去消息应用状态表中查询一遍,如果找到说明是重复消息,丢弃即可,如果没找到才执行,同时插入到消息应用状态表(同一事务)。
for each msg in queue
  Begin transaction
    select count(*) as cnt from message_apply where msg_id=msg.msg_id;
    if cnt==0 then
      update B set amount=amount+10000 where userId=1;
      insert into message_apply(msg_id) values(msg.msg_id);
  End transaction
  commit;
分享到:
评论

相关推荐

    如何用消息系统避免分布式事务

    详细讲解了通过消息来解决分布式事务的问题

    分布式事务

    消息系统可以避免分布式事务,分布式事务。效率非常的低。不适合互联网使用。。要使用的就是最终一致性。使用消息系统就可以避免这个问题。

    微服务架构下处理分布式事务,你必须知道的事儿

    根据微服务架构的鼻祖MartinFowler的忠告,微服务架构中应当尽量避免分布式事务。然而,在某些领域,分布式事务如同宿命中的对手无法避免。在工程领域,分布式事务的讨论主要聚焦于强一致性和最终一致性的解决方案。...

    聊聊分布式事务,再说说解决方案

    分布式事务是企业集成中的一个技术难点,也是每一个分布式系统架构中都会涉及到的一个东西,特别是在微服务架构中,几乎可以说是无法避免,本文就分布式事务来简单聊一下。在说分布式事务之前,我们先从数据库事务...

    基于消息队列模型和数据冗余技术避免电商平台分布式事务的研究.pdf

    #资源达人分享计划#

    基于消息队列模型和数据冗余技术避免电商平台分布式事务的研究 (2015年)

    用户的增多,商品的繁多,电商平台模式已经进入了大数据时代,及时再强大的单个数据库也无法支持,解决方式就是分布式数据库[1],近几年分布式成为热门的话题,也成为大型Web应用系统必备良药,而在数据库方面应用更加广泛...

    基于Java+Dubbo设计的分布式智能公交查询系统-源代码压缩包.zip

    本系统通过运用JAVA语言,使用SSM框架和Dubbo分布式来搭建。将智能公交查询系统信息存入Mysql数据库当中,通过系统来对数据库中的站点信息、公交信息、用户信息、公交信息、用户留言信息及新闻发布信息管理等事务。 ...

    boltmq:分布式发布订阅的消息系统

    是一个分布式发布订阅的消息系统 BoltMQ现在有哪些特性 负载发送消息,除顺序消息之外所有的消息轮循发送到所有消息处理机器 扩容非常方便,多topic对应多broker的数量关系,使得扩容只需要增加机器即可 顺序写,适应...

    Eris:Eris分布式交易

    Eris是用于高性能分布式事务处理的新系统。 它将并发控制功能的核心部分移至数据中心网络本身。 该网络原语负责一致地对事务进行排序,并且新的轻量级事务协议可确保原子性。 在正常情况下,Eris避免了复制和事务...

    Java中间件-RabbitMQ教程

    1、项目中为什么要使用消息中间件? 2、项目中为什么使用RocketMQ而不是RabbitMQ? 3、系统TPS有多少?引入消息中间件之后,系统一定不会被撑爆了吗? 4、消息中间件中出现大量消息堆积,会产生什么后果? 5、如何...

    JAVA毕业设计基于Spring cloud房产销售平台系统项目(ssm完整源码+说明)

    3. 数据一致性:通过采用分布式事务管理机制,保证不同微服务模块之间的数据一致性,避免了数据冲突和不一致的问题。 4. 弹性设计:系统根据不同的负载情况,可以自动进行水平扩展和缩减,以保证系统的高性能和高...

    分布式死锁和分布式恢复-研究论文

    分布式系统由两种组件组成:处理信息的站点和在站点之间传输信息的通信链路,因此本文旨在研究分布式死锁和分布式恢复对系统性能和数据传输的影响。 通过对现有文献的批判性回顾,确定:随着分布式处理需求的增加,...

    智能调度平台系统技术要求.pdf

    2.9 系统须具有分布式事务功能。 2.10系统须支持负载均衡及双机热备。 2.11除系统所用到的硬件、数据库软件及操作系统的费用由招 标人承担以外,其它费用均由投标人承担。 2.12电子地图要求必须支持ArcGIS地图,...

    java抢票系统源码-distributed-lock-redis:手把手教你设计并实现一个基于Redis的分布式锁

    例如,在分布式任务系统中为避免同一任务重复执行,某个节点执行任务之后可以使用分布式锁避免其他节点在同一时刻得到相同任务,和卖车票类似 设计 这非常像一道面试题:如何实现一个分布式锁?在简介中,基本上已经...

    大规模网站架构PPT

    避免分布式事务 反范式的数据库设计 负载均衡 DNS负载均衡 反向代理负载均衡 LVS 缓存 数据库缓存 服务器缓存/页面缓存/数据缓存/静态化 反向代理缓存 Session/Share Nothing Architecture架构 浏览器优化 ...

    收纳幂等限流降级断路器事务缓存分库分表等总结!

    我们可以通过使用集群、负载均衡、故障转移等技术手段来提高系统的可用性,确保用户能够正常使用。 幂等是指对于同一操作,无论执行多少次,最终的结果都是一致的。在分布式系统中,由于网络延迟等原因,可能会导致...

    大规模网站架构PPT文档

    避免分布式事务 反范式的数据库设计 负载均衡 DNS负载均衡 反向代理负载均衡 LVS 缓存 数据库缓存 服务器缓存/页面缓存/数据缓存/静态化 反向代理缓存 Session/Share Nothing Architecture架构 浏览器优化 ...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    3、 系统的易用性和易维护性:要实现这一点,就要求系统应该尽量使用用户熟悉的术语和中文信息的界面;针对用户可能出现的使用问题,要提供足够的在线帮助,缩短用户对系统熟悉的过程。 4、 系统的数据要求:1、...

    DistributedTransactions

    跨越多个数据源的事务,使我们能够将发生在不同系统上的几个不同的操作合并到一个通过或失败的操作中,被称为分布式事务。 系统事务 System.Transactions 命名空间包含允许您编写自己的事务应用程序和资源管理器的...

    第九讲:分布式锁的原理及应用&秒杀设计实现.pdf

    单进程的系统中,存在多线程同时操作一个公共变量,此时需要加锁对变量进行同步操作,保证多线程 的操作线性执行消除并发修改。解决的是单进程中的多线程并发问题。 2)分布式锁: 只要的应用场景是在集群模式的多个...

Global site tag (gtag.js) - Google Analytics