分布式系统中消息队列常用于解决服务解耦,异步通信等问题,从而实现服务高性能,以及业务最终一致性。
这里业务最终一致性指消息上游业务和消息下游业务,在一段时间延迟后,业务逻辑的正确性。
为保证最终一致性,就需要上下游对某个业务操作执行一致的逻辑,同时成功或同时失败。
而业务操作的事件我们是通过消息来传递的,那就要求业务操作与消息传递一致性:
上游业务操作和消息发送事务的一致性
下游业务操作和消息消费事务的一致性
也就是:
消息发送一致性:上游主分支事务与消息发送事务的一致
消息消费一致性:下游支分支事务与消息消费事务的一致
消息发送一致性
常规的消息发送无法保证消息发送的一致性。常见的解决方案有:
分布式事务协议XA
本地事务表
独立消息服务
消息队列事务消息
CDC消息同步
消息确认
实时计算
分布式事务协议XA
消息队列的引入是为解决服务耦合与性能问题,XA协议因为其性能较差,所以一般不会采用该方案。
本地事务表
本地事务表核心思路是新增本地消息表,业务操作与消息写入利用本地事务一致性提交。
本地事务表交互流程如下:
应用业务操作和消息写入使用本地事务一致性提交
应用定时程序,扫描消息表,发送消息到消息队列,并更新消息状态
该方案:
业务表与消息表耦合,每个业务库都需要增加消息表,且数据量较大,操作频繁。
业务表与消息表共用数据库,影响业务性能,降低可用性与扩展性。
事务消息
事务消息核心思路是消息队列提供半事务消息,通过两阶段确认消息操作。第一阶段保留消息信息,第二阶段确认消息操作,如第二阶段出现异常,通过消息回查确认消息操作。
事务消息交互流程如下:
应用发送半事务消息
应用进行业务操作
应用发送事务确认消息
消息队列根据事务确认消息,决定是否投递消息
X时间前,未确认的半事务消息,消息队列进行消息回查,根据回查结果,确定投递操作。
该方案:
消息队列耦合应用:消息队列回查消息,应用需提供回查功能,以确保消息发送的一致性
应用需通过二阶段确认消息操作,第一阶段失败,则业务失败,所以需要尽可能保证消息队列可用性
独立消息服务
独立消息服务与事务消息机制相似,都是通过二阶段来确认消息操作。
独立消息服务作为消息队列的代理,提供事务消息功能,同时以RPC服务的形式提供给应用使用。
独立消息服务交互流程如下:
应用发送原消息
应用进行业务操作
应用发送确认消息
消息服务根据确认消息,决定是否将原消息是否发送到消息队列
X时间前未确认消息消息服务向应用回查消息,确认操作(应用与消息服务相互调用)
为解耦应用与消息服务,消息服务可将未确认消息投递到 异常消息队列,应用消费消息,查询业务操作结果,确定发送无需确认的消息。这样独立消息服务无需调用应用,解耦相互调用。
独立消息服务相比事务消息还具有以下特点:
消息服务作为消息队列的代理,提供事务消息功能,扩展方便灵活。
消息服务区别于业务服务与消息队列,可根据场景选择合适的高性能的存储
CDC消息同步
利用数据CDC技术,业务数据变更后,将相应数据发送到消息队列,下游应用进行消费。同样该方案CDC技术本身需确保数据变更与消息发送的一致性,不能出现丢失消息的情况。
CDC消息同步方案交互流程如下:
应用进行业务操作
数据库数据变更
数据库CDC发送变更时间到消息队列
消费确认
消费确认方案核心思路为:应用自身消费消息,确认消息是否发送成功。
消费确认方案交互流程如下:
应用进行业务操作
应用发送消息
应用订阅消息,消费消息,并将标识入库
应用定时程序,扫描业务表与确认表
获取X时间前,没有确认的业务数据,构建消息重新发送消息
超出某个时间,还未确认的业务数据,记录起来,并报警通知人工处理
消费消息入库,可选择不同于业务库的不同类型的存储库。
该方案:
应用自身控制整个流程
应用只发送一次消息
实时计算
实时计算核心思路为:应用发送原消息与确认消息,实时计算匹配消息成功,将原消息发送到最终消息队列中。
实时计算方案交互方案如下:
应用发送原消息
应用进行业务操作
应用发送确认消息
实时计算匹配原消息与确认消息
匹配消息,根据确认消息决定是否发送原消息到最终消息队列
未匹配消息,X时间后进入确认异常消息队列
应用订阅异常消息队列,查询业务操作结果,确定是否发送原消息到最终消息队列
异常消息队列多次投递未成功,进入死信队列,报警通知人工处理
该方案:
引入实时计算。尽可能使用实时计算框架保证高可用与多个消息操作事务一致性。
消息消费一致性
消息消费一致性较为简单,主要基于以下特性来解决:
消息消费ACK:下游业务操作成功,需ACK消息,否则消息队列会重复投递消息
业务操作幂等性:上面消息为保证消费成功会重复投递,所以服务需保证业务操作幂等性,不会因消息重复消费而出错。
总结
消息队列引入目的是解耦应用,提高性能,降低响应,同时需要保证业务最终一致性。
消息队列保证上下游应用的业务最终一致性,要求上下游应用保障业务操作与消息传递事务一致性即:
消息发送一致性
消息消费一致性
消息发送一致性通常通过多阶段来实现
消息消费一致性通过 消息消费ACK+ 业务操作幂等性 保证
几种消息发送一致性方案简单说明:
分布式事务协议XA,性能较差
本地事务表,数据库耦合,性能差且受影响
事务消息,需消息队列支持,且消息回查耦合业务应用
独立消息服务,消息队列代理,通过异常消息队列避免与应用循环调用
CDC消息同步,依赖数据库CDC技术
消费确认方案,应用控制整个流程,消息只发送一次
实时计算方案,引入实时计算
基于以上介绍,消息发送一致性方案推荐顺序为CDC消息同步、事务消息,消息确认。