微服务的普及,使用队列处理服务之间通信成为一种潮流,利用队列消息解耦系统不可避免的会出现数据不一致问题。
发布方问题:运行的系统无法避免的存在单点故障问题,保存本地事务和推送队列无论是哪个先执行都无法保证这两个一定都执行完成,先保存本地事务,服务发生故障,消息没推送,反之同理。
订阅方问题:消费收到消息后,执行过程中发生错误或宕机,导致没执行成功。
发布方解决方案
选出两种比较简单的并且不同体系的产品来对比(阿里的RockMq/.net core的CAP框架),先了解下两种方案的实现过程
首先,在你项目运行时候会在你项目指定得数据库生成一张表(cap.published)这张表是用来存储要发送消息的日志。消息有三个状态(Scheduled,Succeeded,Failed),启动程序时候同时还会启动一个监听程序,隔几分钟把表中Failed的消息重新发送。
我用下订单来举个详细例子
这种设计方式相对于2PC/TCC来说,复杂性降低了一个级别,而且支持多种数据库和消息队列,扩展性极强,我觉得缺点应该是依赖数据库,发布消息需要插入日志消息到数据库,受限于单机数据库的瓶颈,如果分库分表还要处理这块,要么就得在数据库层面做分库分表。CAP文档
Rocketmq的功能十分强大,有普通消息,定时消息,全局/局部顺序消息以及事务消息,在阿里云可以直接买服务来使用。RocketMq的事务采用了TCC模式(Try-Confirm-Cancel)
提交mq半事务半事务消息成功确认mq事务回查事务回滚mq事务
可以简单理解为下图内容 【我(消息发送方)和 大佬(rocketmq服务)的聊天记录】
1.完美成功情况
2.消息发送方宕机情况
3.消息发送方本地事务失败情况
可以上阿里云搜Rocketmq查看该产品使用手册。
CAP适合于发送队列消息与业务在同一个服务的场景,而中台架构就不适合,因为中台架构分基础服务和业务中台,队列一般在业务中台跟业务挂钩,有一个订单基础服务,但有N个应用中台都是调用这个订单基础服务存储订单数据,每个中台都相当于一个应用,逻辑可能差异很大,更倾向于在中台决定推不推送消息和推什么消息,这种情况下CAP就完全不适合。
订阅方解决方案
系统的瞬态故障产生的问题,重试便可以解决
这种情况重试是解决不了问题的,需要开发人员做好PlanB,重试N次不成功便执行PlanB。
发送端监听重复推送导致的问题,有两种方案可以解决。
回到选中的两大框架的消费端
同发送端一样,在你项目运行时候会在你项目指定得数据库生成一张表(cap.received)这张表是用来存储消费的消息日志。消息有三个状态(Scheduled,Succeeded,Failed),启动程序时候同时还会启动一个监听程序,隔几分钟把表中Failed的消息重消费。
发送端演示下单,消费端就来个扣库存的。
订阅消息有两种方式:
1.通过http拉取(注意 官方的SDK的http请求性能很差,建议最好自己写)
2.开启tcp监听获取(注意 .net的TCP监听获取消息的SDK至今没有Linux版本--2019年12月13)
获取消息需要在代码里进行ack确认
CAP框架:功能单一,使用简单,.net体系的可自行扩展,适合自治微服务架构。
RocketMq:功能丰富,维护简单,稳定性强,但使用还需要自己做相关开发,使用成本高,对.net支持不太好,适合中台服务。
作者:Carson_dotnet
链接:https://www.jianshu.com/p/f90ce421893e