微服务:事务管理

ccbdbc78d1edb2276fad85b3294b8571.jpeg

几乎所有的信息管理系统都会涉及到事务,事务的目的是为了保证数据的一致性,这里说的一致性是数据库状态的一致性。

说到数据库状态的一致性,相信大家都会想到 ACID :

  • 原子性(Atomic):在一个事件的多个数据库操作中,要么同时成功,要么同时失败,例如:转账业务;

  • 隔离性(Isolation):不同的业务之间处理数据相互独立,互不影响;

  • 持久性(Durability):正常提交的数据能够被持久化,不丢失数据,比如 mysql 天然就能持久化,redis 、 rabbitmq 也能通过设置进行持久化;

  • 一致性(Consistency):最终的数据正确,所以说是通过 AID 这些手段来保证了 C 。

在单体架构中,通常是一套程序对应一个数据库,事务基于数据库本身的能力,如果你在 .NET Core 中使用 dapper 或 sqlsugar ,可以很容易进行事务的处理,可以参考下面文档:

https://dapper-tutorial.net/transaction 

https://www.donet5.com/Home/Doc?typeId=1183

但是,在微服务架构,分布式的场景中,事务的处理就会变得复杂,会存在多个节点,多个节点的同步、可用性等都是需要考虑的问题,在分布式中有一个著名的 CAP 理论:

  • C:数据一致性(Consisitency):分布式中存在多个节点,对某个指定的客户端来说,从任一节点读取的数据保证获取到的是最新写入的数据;

  • A:可用性(Acailability),非故障节点在合理的时间内返回合理的响应(不是错误和超时的响应);

  • P:分区容错性(Partition Tolerance),节点之间的数据传递是基于网络的,由于网络本身不是 100% 可靠,极端情况下会出现网络不可用的情况,进而将网络两端的节点分隔开来,这就是所谓的「网络分区」现象。在出现网络分区时,两部分的数据是不一致的,如果要保证数据的一致性,就必须要让没有及时同步数据的节点变为不可用,这就牺牲了可用性,否则就会牺牲一致性,所以在 P 一定存在的情况下,需要在 C 和 A 中间做取舍。

我们在 CAP、ACID 中讨论的一致性称为「强一致性」(Strong Consistency),而把牺牲了 C 的 AP 系统,但又要保证最终的结果是一致的,称为「弱一致性」,也叫最终一致性。最终一致性的概念由 eBay 的系统架构师丹 · 普利切特(Dan Pritchett)在 2008 年发表于 ACM 的论文「Base: An Acid Alternative」中提出的。

本文主要说下保证一致性的几种方式:TCC、SAGA 和消息队列。

TCC

TCC 是 Try-Confirm-Cancel 的缩写,表示将整个过程分为了三个阶段:

  • Try:一个请求涉及到多个服务,多个服务会同时进行 Try,这个阶段为尝试执行阶段,在这个阶段中会进行数据的校验、检查,保障一致性,并准备资源,都成功会进入到 Confirm 阶段;

  • Confirm:确认执行阶段,不进行任何业务检查,多个服务的 Try 都执行成功了,多个服务都进入到 Confirm 阶段,在这个阶段直接使用 Try 阶段准备的资源来完成业务处理。注意,Confirm 阶段可能会重复执行,因此需要满足幂等性。

  • Cancel:如果在 Try 阶段有一个服务没有成功,那么所有的服务都进入到 Cancel 阶段,在该阶段,释放 Try 阶段预留的业务资源。注意,Cancel 阶段也可能会重复执行,因此也需要满足幂等性。

在 .NET Core 中可以参考:

https://github.com/simpleway2016/JMS

在 Java 中可以使用 seata:

https://github.com/seata/seata https://seata.io/zh-cn/

因为在 TCC 中的第一步 Try 需要预留资源,进行检查和校验,但在某些场景下,资源不是我们所能控制的,比如支付中,余额是银行管理的,我们通常没有权限。所以这时就不太适合 TCC ,可以考虑用 SAGA 来代替 TCC。

SAGA

SAGA 起源于 1987 年普林斯顿大学的赫克托 · 加西亚 · 莫利纳(Hector Garcia Molina)和肯尼斯 · 麦克米伦(Kenneth Salem)在 ACM 发表的一篇论文《SAGAS》。

SAGA 和 TCC 最大的区别是基于数据补偿机制来代替回滚。一个 SAGA 表示处理多个服务中数据的一系列操作,由一连串的本地事务组成,每个独立的本地事务中还是能够使用 ACID 。

SATA 由两部分组成:

  • 将一个大的事务拆分成的若干个小的事务,比如一个大的事务 T ,拆分成 T1、T2、T3;

  • 每一个子事务有对应的补偿动作,例如对应上面的 T1、T2、T3 有 C1、C2、C3 的补偿动作。

在 ACID 中如果出现异常,可以很容易进行回滚,但 SAGA 没办法自己回滚,必须依赖补偿动作来进行回滚。

如果 T1、T2、T3 都提交成功了,整个事务 T 就提交成功,如果执行 T2 时出现异常,这时有两种方式进行处理:

正向(不断重试):不断对 T2 进行重试操作,直到成功(不排除人工干预),等 T2 重试成功后,继续执行后面的 T3;

反向(补偿):T2 出现异常时,执行对应的补偿 C2,C2 必须执行成功(不排除人工),然后执行 T1 对应的补偿动作 C1 。

在上面提到的 seata 中也同样可以支持 SAGA 模式。

除了 seata ,还有一个用 go 语言写的 DTM 分布式事务框架也不错:

https://dtm.pub/ https://github.com/dtm-labs/dtm

重要的是,DTM 支持 C# 客户端:

https://github.com/dtm-labs/dtmcli-csharp

消息队列

消息队列相信大家都不陌生,我们零代码产品中调用外部接口的组件,会被用在一些复杂的业务逻辑编排中,对外部接口的调用就是使用消息队列,RabbitMQ 的延时队列加上死信队列可以来进行重试的操作,来保证数据的最终一致。

还有另一种方式就是使用事务消息表,比如有这样一个场景,在系统列表中删除一条流程数据,这时需要做:

1、列表服务中对数据进行删除;

2、文件服务对这条数据相关的附件进行删除;

3、流程服务对该业务数据的所有流程信息进行删除。

具体的步骤如下:

1、列表服务删除数据成功后,在数据库中创建一张事务消息表,该表中记录事务 ID、数据删除成功的状态、业务数据 ID、附件待删除的状态、流程信息待删除的状态等;

2、列表服务删除数据成功后,发送消息分别进行附件删除处理和流程信息删除处理;

3、消息被正确处理后,修改事务消息表的状态;

4、创建一个单独的消息服务程序,轮询扫描事务消息表,如果发现状态没有变成已完成,就重新发送一个新的消息,这样附件删除和流程信息删除就会进行多次执行,这也要求这些操作必须是幂等的。

RabbitMQ 本身不支持分布式事务,不过有一些消息中间件是支持的,例如:RocketMQ,原生就支持分布式事务操作,可以更方便进行事务处理。

本文是一些理论的梳理,要想更彻底地掌握,可以选择一个框架,找几个场景,写写代码演练一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js - flex布局测试案例:完美居中

<span>I love flex layout!</span><style>body{display:flex;justify-content:center;align-items:center;font-size:3em;color:#00ffff;}</style>![enter image description here][1]<p>与自己为敌&#xff0c;</p><p>与自己为友&a…

操作数据库(对战小游戏)

创建数据库 1 create database duizhan2 go3 use duizhan4 go5 create table duizhan6 (7 Code varchar(20) not null primary key,8 Name varchar(20) not null,9 Sex varchar(20) not null, 10 Blood int, 11 Attack int, 12 Defence int, 13 Mingzhong…

8-Python3从入门到实战—基础之数据类型(集合-Sets)

Python从入门到实战系列——目录 集合的定义 集合&#xff08;set&#xff09;和字典类似&#xff0c;也是一组key的集合&#xff0c;但不存储value&#xff1b;由于key不能重复&#xff0c;所以&#xff0c;在set中&#xff0c;没有重复的key。创建一个set&#xff0c;需要提供…

Redis的那些事:一文入门Redis的基础操作

Redis是什么Redis&#xff0c;全称是Remote Dictionary Service,翻译过来就是&#xff0c;远程字典服务。redis属于nosql非关系型数据库。Nosql常见的数据关系&#xff0c;基本上是以key-value键值对形式存在的。Key-value: 就像翻阅中文字典或者单词字典&#xff0c;通过指定的…

10种提问型爆文标题句式 直接套用

如果你用1天的时间来写篇好文章&#xff0c;那你花掉半天时间想一个好标题都不过分&#xff01; 你是不是觉得我有点言过其实了&#xff1f;没关系&#xff0c;先来问你2个问题&#xff1a; 1、花了很长时间&#xff0c;写了一篇很牛的卖货推文&#xff0c;定稿后&#xff0c…

同域和不同域长啥样

相同域http://www.jiangdou.com/http://www.jiangdou.com/maidou 不同域http://www.jiangdou.comhttp://bbs.jiangdou.comhttps://www.jiangdou.comhttp://www.jiangdou.com:8080转载于:https://www.cnblogs.com/MaiJiangDou/p/6689133.html

2016 China Joy抢先看,文末有彩蛋!

这里只有你想不到的&#xff0c;没有你看不到的。 2016 China Joy开幕在即&#xff0c;天气成了最折磨各种媒体、展商和观众的小妖精&#xff0c;一会艳阳天&#xff0c;一会大暴雨&#xff0c;轩轩现在是这样的&#xff01; 七月底的魔都&#xff0c;热的那叫一个销魂&#x…

JdbcTemplate+PageImpl实现多表分页查询

一、基础实体  MappedSuperclass public abstract class AbsIdEntity implements Serializable {private static final long serialVersionUID 7988377299341530426L;public final static int IS_DELETE_YES 1;// 标记删除public final static int IS_DELETE_NO 0;// 未删除…

消息队列选型手册

前言 消息队列中间件重要吗&#xff1f;面试必问问题之一&#xff0c;你说重不重要。我有时会问同事&#xff0c;为啥你用 RabbitMQ&#xff0c;不用 Kafka&#xff0c;或者 RocketMQ 呢&#xff1f; 他给我的回答&#xff1a;“因为公司用的就是这个&#xff0c;大家都这么用…

Jenkins 持续集成国产嵌入式操作系统 RT-Thread 的CI

我们直接在Jenkins的镜像基础上进行集成RT-Thread 的编译环境&#xff0c; 这样直接使用Shell 命令 最直接了当&#xff0c; 通过 第三方docker等插件&#xff0c; 尝试了计重方案&#xff0c; 没有找到理想中的感觉&#xff0c; 如果其他人有想法可以告知一二。 我们有现成的镜…

codevs原创抄袭题 5960 信使

题目描述 Description•战争时期&#xff0c;前线有n个哨所&#xff0c;每个哨所可能会与其他若干个哨所之间有通信联系。信使负责在哨所之间传递信息&#xff0c;当然&#xff0c;这是要花费一定时间的&#xff08;以天为单位&#xff09;。指挥部设在第一个哨所。当指挥部下达…

VC解析XML--使用CMarkup类解析XML

经过今天尝试MFC解析XML串&#xff0c;也算有了不少收获&#xff0c;总结一下。 我是使用的CMarkup类对XML进行操作。 CMarkup好象都是先从一个xml文件里面把内容读出来&#xff0c;再进行解析&#xff0c;搞得我恨不得要把我的CString写到xml文件里面…

MongoDB精华总结

概述 MongoDB是属于文档型的NoSQL数据库&#xff0c;也就是文档数据库。文档数据库区别于传统的其它数据库&#xff0c;它是用来管理文档。在传统的数据库中&#xff0c;信息被分割成离散的数据段&#xff0c;而在文档数据库中&#xff0c;文档是处理信息的基本单位&#xff0c…

认清性能问题

本文翻译自 Thinking Clearly About Performance 这是我三年前读到的一篇关于性能问题的好文&#xff0c;读完后还觉不过瘾&#xff0c;怕理解的不够遂又翻译了一遍&#xff0c;这也是当年我的第一次翻译。 这几年来每次碰到性能问题&#xff0c;我都会想起这篇文章&#xff0c…

字节也开始缩招了...

阅读本文大概需要6分钟。最近和一个字节技术总监聊天&#xff0c;得知他们公司居然也开始缩招了。这真让人感到意外&#xff0c;毕竟头条这些年是以极速扩张而闻名。搜了搜新闻还真是&#xff0c;这也意味着互联网行业最后一个坚挺的大户也在开源节流了。最近互联网行业的情况真…

实现打字效果

摘自一个表白网站的效果。 方法&#xff1a; substr() 可在字符串中抽取从 第一个参数表示从指定的下标&#xff0c;第二个参数表示抽取指定数目的字符。 indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置&#xff0c;两个参数&#xff0c;第一位指定的字符串&…

php优化-》常用到的部分优化

1.循环内部尽可能不要声明变量&#xff1b; 2.在可以用PHP内部字符串操作函数的情况下&#xff0c;尽量不要用正则表达式&#xff1b; 3.foreach效率更高&#xff0c;尽量用foreach代替while和for循环&#xff1b; 4.用单引号替代双引号引用字符串&#xff1b; 5.尽量的少进行文…

简述:分布式CAP理论和BASE理论

目录 一、什么是CAP&#xff1f; Consistency (一致性)&#xff1a; Availability (可用性): Partition Tolerance (分区容错性): 二、取舍策略 三、Base理论 1、基本可用 2、软状态 3、最终一致性 四、常见产品 Ereka Zookeeper 五、总结 一、什么是CAP&#xf…

WinForm(四)一种实现登录的方式

首先声明&#xff0c;这只是一种登录方式&#xff0c;并不是最好的方式&#xff0c;用这个例子为了说明登录窗体和Application的关系。在登录前&#xff0c;定义了用户实体&#xff0c;然后是一个通用的类&#xff0c;存放进程中当前登录的用户&#xff0c;所以CurrentUser是静…

Java多线程4:synchronized锁机制

脏读 一个常见的概念。在多线程中&#xff0c;难免会出现在多个线程中对同一个对象的实例变量进行并发访问的情况&#xff0c;如果不做正确的同步处理&#xff0c;那么产生的后果就是"脏读"&#xff0c;也就是取到的数据其实是被更改过的。 按照正常来看应该打印&quo…