7.0 柔性事务:可靠消息最终一致性

消息发送一致性:是指产生消息的业务动作与消息发送的一致。也就是说,如果业务操作成功,那么由这个业务操作所产生的消息一定要成功投递出去(一般是发送到kafkarocketmqrabbitmq等消息中间件中),否则就丢消息。

​ 柔性事务、可靠消息最终一致性、异步确保性

下面用伪代码进行演示消息发送和投递的不可靠性:

1、先进行数据库操作,再发送消息

public void test1(){//1 数据库操作//2 发送MQ消息}

这种情况下无法保证数据库操作与发送消息的一致性,因为可能数据库操作成功,发送消息失败

2、先发送消息,再操作数据库

public void test1(){//1 发送MQ消息//2 数据库操作}

这种情况下无法保证数据库操作与发送消息的一致性,因为可能发送消息成功,数据库操作失败

3、在数据库事务中,先发送消息,后操作数据库

@Transactionalpublic void test1(){//1 发送MQ消息//2 数据库操作}

​ 这里使用spring 的@Transactional注解,方法里面的操作都在一个事务中。同样无法保证一致性,因为发送消息成功了,数据库操作失败的情况下,数据库操作是回滚了,但是MQ消息没法进行回滚。

4、在数据库事务中,先操作数据库,后发送消息

@Transactionalpublic void test1(){//1 数据库操作//2 发送MQ消息}

​ 这种情况下,貌似没有问题,如果发送MQ消息失败,抛出异常,事务一定会回滚(加上了@Transactional注解后,spring方法抛出异常后,会自动进行回滚)。

​ 这只是一个假象,因为发送MQ消息可能事实上已经成功,如果是响应超时导致的异常。这个时候,数据库操作依然回滚,但是MQ消息实际上已经发送成功,导致不一致。

5、使用JTA事务管理器

​ 前面通过spring的@Transactional注解加在方法上,来开启事务。其实有一个条件没有明确的说出来,就是我们配置的事务管理器是DataSourceTransactionManager

​ 事实上,Spring还提供了另外一个分布式事务管理器JtaTransactionManager。这个是使用XA两阶段提交来保证事务的一致性。当然前提是,你的消息中间件是实现了JMS规范中事务消息相关API(回顾前面我们介绍JTA规范时,提到DB、MQ都只是资源管理器RM,对于事务管理器来说,二者是等价的)。

​ 因此如果你满足了2个条件:1、使用JtaTransactionManager 2、DB、MQ分别实现了JDBC、JMS规范中规定的RM应该实现的两阶段提交的API,就可以保证消息发送的一致性。

​ DB作为RM,一般都是支持两阶段提交的。不过,一些MQ中间件并不支持,所以你要找到支持两阶段提交的MQ中间件。另外,JtaTransactionManager只是一个代理,你需要提供一个真实的事务管理器(TM)实现。如前面提到了atomikos公司,就有这样的产品。

​ 但是笔者依然不建议,这样玩。因为XA两阶段提交性能低,我们使用消息中间件就是为了异步解耦,这种情况,虽然保证了一致性,但是响应时间却大大增加,系统可用性降低。

​ 那么如何保证,数据库操作和消息发送的一致性呢?

两种方案:一种是基于MQ的事务消息,以下展示了RocketMQ的事务消息机制。

BE2326B0-FC19-4620-BD2E-D34A32B8A405.png

事务消息的逻辑,由发送端 Producer进行保证(消费端无需考虑)

​ 首先,发送一个事务消息,这个时候,RocketMQ将消息状态标记为Prepared,注意此时这条消息消费者是无法消费到的。

​ 接着,执行业务代码逻辑,可能是一个本地数据库事务操作

​ 最后,确认发送消息,这个时候,RocketMQ将消息状态标记为可消费,这个时候消费者,才能真正的保证消费到这条数据。

​ 如果确认消息发送失败了怎么办?RocketMQ会定期扫描消息集群中的事务消息,如果发现了Prepared消息,它会向消息发送端(生产者)确认。RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。

​ 如果消费失败怎么办?阿里提供给我们的解决方法是:人工解决。

​ 另外一种实现,并不是所有的mq都支持事务消息。也就是消息一旦发送到消息队列中,消费者立马就可以消费到。此时可以使用独立消息服务、或者本地事务表。

ECEB0CD9-A61C-4ED9-98C1-CE02A9B658C3.png

​ 可以看到,其实就是将消息先发送到一个我们自己编写的一个"独立消息服务"应用中,刚开始处于prepare状态,业务逻辑处理成功后,确认发送消息,这个时候"独立消息服务"才会真正的把消息发送给消息队列。消费者消费成功后,ack时,除了对消息队列进行ack(图中没有画出),对于独立消息服务也要进行ack,"独立消息服务"一般是把这条消息删除。而定时扫描prepare状态的消息,向消息发送端(生产者)确认的工作也由独立消息服务来完成。

​ 对于"本地事务表",其实和"独立消息服务"的作用类似,只不过"独立消息服务"是需要独立部署的,而"本地事务表"是将"独立消息服务"的功能内嵌到应用中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容