分布式事务
来源:互联网 发布:剑灵 知乎 编辑:程序博客网 时间:2024/06/06 03:55
eg:跨行转账
第一步扣款建设银行账户的1000元 第二步通知招商银行账户上加1000
- 产生的原因
数据库分库分表
当单表一年的数据超过1000万条,那么就要考虑分库分表。就是一个数据库变成了多个数据库.如果一个操作涉及到01库、02库,那么就要考虑到数据的一致性
- 业务拆分
原来的单机撑起了整个电商系统,现在对整个电商进行拆解,分离出了订单中心、用户中心、库存中心等.他们都有对应的数据库.如果同时对订单和库存进行操作,那么就设计到订单数据库和库存数据库.
- 业务拆分
事务特性
- 原子性: 整个事务中的所有操作,要么全部完成,要么全部失败。
- 一致性:必须保证系统的一致性。A有500元,B有300元。在一个事务里A转给B50,不论斌方法多少。最后A账户一定时450,B是350.这就是分布式锁
- 隔离性:事务与失误之间不会相互影响,一个事务的中间状态不会被其他事务感知.
- 持久性:一个事务完成了。那么数据的变更就在数据库中l
==================
应用场景
- 支付
扣除买家数据库,对卖家数据库进行增加 - 在线下单
买家在电商下单,一个是库存,一个是更新订单信息。库存和订单属于不同的数据库.
- 支付
常见的解决方案
- 基于XA协议的两阶段提交
但明显在高并发的环境下,性能不理想 - 消息事务+最终一致性
基于消息中间件的两阶段提交,将本地事务和发消息放在了一个分布式事务里,保证要不本地操作成功并且对外发消息成功,要么两者失败.RocketMQ
1出错,则整个事务失败,不会执行A的本地操作
2出错,则整个事务失败,不会执行A的本地操作
3出错,这时候需要回滚预备消息,怎么回滚?答案是A系统实现一 个消息中间件的回调接口,消息中间件会去不断执行回调接口,检查A事务执行是否执行成功,如果失败则回滚预备消息
4 出错,这时候A的本地事务是成功的,那么消息中间件要回滚A吗?答案是不需要,其实通过回调接口,消息中间件能够检查到A执行成功了,这时候其实不需要A发提交消息了,消息中间件可以自己对消息进行提交,从而完成整个消息事务
- 基于XA协议的两阶段提交
上述保存消息的方式使得消息数据和业务数据紧耦合在一起,从架构上看不够优雅,而且容易诱发其他问题。为了解耦,可以采用以下方式。
1)用户A在扣款事务提交之前,向实时消息服务请求发送消息,实时消息服务只记录消息数据,而不真正发送,只有消息发送成功后才会提交事务;
2)当用户A扣款事务被提交成功后,向实时消息服务确认发送。只有在得到确认发送指令后,实时消息服务才真正发送该消息;
3)当用户A扣款事务提交失败回滚后,向实时消息服务取消发送。在得到取消发送指令后,该消息将不会被发送;
4)对于那些未确认的消息或者取消的消息,需要有一个消息状态确认系统定时去用户A系统查询这个消息的状态并进行更新。为什么需要这一步骤,
举个例子:假设在第2步用户A扣款事务被成功提交后,系统挂了,此时消息状态并未被更新为“确认发送”,从而导致消息不能被发送。
优点:消息数据独立存储,降低业务系统与消息系统间的耦合;
缺点:一次消息发送需要两次请求;业务处理服务需要实现消息状态回查接口。
4.2 如何解决消息重复投递的问题
还有一个很严重的问题就是消息重复投递,以我们用户A转账到用户B为例,如果相同的消息被重复投递两次,那么我们用户B账户将会增加2万而不是1万了。
为什么相同的消息会被重复投递?比如用户B处理完消息msg后,发送了处理成功的消息给用户A,正常情况下用户A应该要删除消息msg,但如果用户A这时候悲剧的挂了,
重启后一看消息msg还在,就会继续发送消息msg。
解决方法很简单,在用户B这边增加消息应用状态表(message_apply),通俗来说就是个账本,用于记录消息的消费情况,每次来一个消息,
在真正执行之前,先去消息应用状态表中查询一遍,如果找到说明是重复消息,丢弃即可,如果没找到才执行,同时插入到消息应用状态表(同一事务)。
3.JTA
作为Java平台上事务规范JTA(Java Transaction API)也定义了对XA事务的支持,实际上,JTA是基于XA架构上建模的,在JTA 中,事务管理器抽象为javax.transaction.TransactionManager接口,并通过底层事务服务(即JTS)实现。像很多其他的java规范一样,JTA仅仅定义了接口,具体的实现则是由供应商(如J2EE厂商)负责提供,目前JTA的实现主要由以下几种:
1.J2EE容器所提供的JTA实现(JBoss)
2.独立的JTA实现:如JOTM,Atomikos.这些实现可以应用在那些不使用J2EE应用服务器的环境里用以提供分布事事务保证。如Tomcat,Jetty以及普通的java应用
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式事务
- 分布式 事务
- 分布式事务
- 分布式事务
- 新版本caffe脚本运行无权限,#!/usr/bin/env sh
- Android之监听并获取短信内容
- Docker镜像与容器命令
- Linux(Debian)上安装Redis3.2.8教程
- 使用DroidPlugin框架,startActivityForResult无法传值到插件Activity问题
- 分布式事务
- 设计模式(3)-抽象工厂模式
- 1080. Graduate Admission (30) PAT 甲级
- 多线程释放对象
- 使用SBT编译Spark子项目
- 计蒜客2n皇后问题(dfs)
- YCSB测试hbase
- sizeof与strlen用法详解(结构体对齐)
- 数据链路层的MAC和LLC子层的区别