1. 什么是事务数据库
由一组操做构成的可靠、 独立的工做单元。 事务具备如下特色:bash
•Atomicity(原子性)框架
•Consistency(一致性)分布式
•Isolation(隔离性)spa
•Durability(持久性)设计
2.事务的一致性code
单体应用能够在数据库的事物管理器中得到强一致性,这种本地事物可靠简单。 而在微服或者SOA的场景下,咱们的本地事物就不做用了。对于分布式系统 Google 提出 CAP定理 , 分布式的事物只能同时拥有如下三项中的两个:接口
•Consistency(一致性): 全部 用户看到一致的数据。队列
•Availability(可用性): 总能找 到一个可用的数据复本。事件
•Tolerance to Network Partition(分区容忍性): 即便 在系统被分区的状况下,仍然知足上述两点。
分布式系统的事物没法作到强一致性,只能作到最终一致性。
3.常见分布式事物的处理方案
事物消息,简单的说就是消息投递成功,你本地的数据库事物确定提交成功,消息投递失败你本地事物也确定提交失败。至关于你投递消息和操做数据库是绑定在一块儿的,二者是在同一个事物中。
非事物消息,简单的说就是消息投递成功,本地数据库事物不必定执行成功。
而现有的开源的MQ框架 大多数是不支持 事物消息的,也没有和本地事物进行配合。 RocketMQ 好像实现了这个事物消息功能,有兴趣的同窗能够去看看。
先来看个案例: 假设我有一个 文章微服 负责发布文章,查询文章列表等,还有一个 用户微服 保持用户的一些基本信息,如:用户发文章的篇数等。
如今发文章在 文章微服,而用户的发文篇数在 用户微服。这种状况下咱们怎么保证 发文的计数 不会多也不会少,保证其的一致性的呢?
你们先来看一段代码: 假设这是 文章微服 发文代码:
@Transactional
public void saveArticle(Article article){
try{
//保存文章
articleDao.saveArticle(article);
MqEvent saveArticleEvent = new MqEvent();
//消息ID
saveArticleEvent.setMsgId(UUIDUtil.mongoObjectId());
//发送保存文章 事件个用户服务
sender.sendAddArticleMqEvent(saveArticleEvent);
}catch (Exception e){
//抛异常 让事务回滚
throw new RuntimeException();
}
}
}
复制代码
看起来很正常呀!没有什么问题! 咱们来列举一下可能会出现的状况;
保存文章正常,MQ发送也正常,好万事大吉,数据都正常。
保存文章正常,MQ发送失败,抛异常。这时数据回滚,虽然出了点问题 可是数据正常。这也没问题。
文章保存失败,这时确定抛异常,MQ发送走不到,这时也是正常的。
文章保存成功,MQ发送成功,这时会不会有问题出现呢? 刚刚咱们说了 咱们的MQ是非事物性的,恰巧这个时候 MQ 回执异常致使 MQ抛异常了。本地事物回滚,可是MQ虽然抛异常,消息却发成功了。这时候 会致使 用户发文计数多了一篇,数据不一致了致使。
虽然这种作法看起来没有什么问题,但实际上是有问题的。
为了解决这个问题,咱们须要 增长一个本地事件表,专门存放 MQ事件 ,有定时器轮训去发送MQ消息,发送成功后作标记,或者删除。不少MQ都会有 消息回执的。当成功投递到消息队列是 就会获得回执。
因而咱们的代码应该改为这样:
@Transactional
public void saveArticle(Article article) {
articleDao.saveArticle(article);
MqEvent saveArticleEvent = new MqEvent();
//消息ID
saveArticleEvent.setMsgId(UUIDUtil.mongoObjectId());
// 保存事件到事件表
mqEventDao.addMQEvent(saveArticleEvent);
}
复制代码
这样在本地事物的强一致性下能够保证,发文的同事插入发文事件。
说说 用户微服那边的处理 , 用户微服也应该有一个这样的事件表,保存接收的事件,经过轮训等方式处理这些事件,只有成功的接收了事件,事件才能从MQ队列里面消失。MQ在消费消息的时候若是遇到异常会从新将消失从新发回到队列中,不少MQ具备这个特性。
细心的同窗可能会想到我同一个事件消息投递了两次怎么办?这就涉及幂等性的设计了,看到上面的消息ID没? 这就是为幂等性设计的 惟一ID;当用户微服收到两个消息ID是同样的时候,丢弃掉一个。
咱们的微服系统 只要涉及 增 删 改 的操做都应该经过可靠事件进行操做,而不能直接经过 REST 接口,去操做,也不能直接的发送事件去操做。对于消防端,要作好幂等性的处理。可靠事件处理微服的事物算是比较靠谱的作法,2pc,3pc ,Tcc 在微服事物处理这一块,基本上起不了什么做用。 本人的理解大概是这样,欢迎你们提出疑问。