(转)蚂蚁金服(消息队列事务型消息原理浅析)
原文地址:https://yq.aliyun.com/articles/596022
摘要: 在金融级分布式架构的领域内,消息队列是普遍被应用的异步通信产品,本文主要分为以下几个小结,循序渐进的对消息队列产品事务型消息设计原理进行分析和阐述: 消息队列简介 消息队列应用实例 事务型消息设计方案 事务型消息总结 消息队列简介 在分布式系统架构中,消息队列的核心职责是为不同的应用系统提供异步通信服务,通常涉及以下三个重要角色: 消息发布者,发送消息的应用系统,负责创建消息对象并通过网络发布到消息 Broker,发布的过程一般是同步的。
【(转)蚂蚁金服(消息队列事务型消息原理浅析)】在金融级分布式架构的领域内,消息队列是普遍被应用的异步通信产品,本文主要分为以下几个小结,循序渐进的对消息队列产品事务型消息设计原理进行分析和阐述:
- 消息队列简介
- 消息队列应用实例
- 事务型消息设计方案
- 事务型消息总结
在分布式系统架构中,消息队列的核心职责是为不同的应用系统提供异步通信服务,通常涉及以下三个重要角色:
- 消息发布者,发送消息的应用系统,负责创建消息对象并通过网络发布到消息 Broker,发布的过程一般是同步的。
- 消息 Broker,异步消息的“代理人”,负责接收并持久化消息,保证将消息投递到指定的消息订阅者应用系统。
- 消息订阅者,订阅消息的应用系统,负责消费消息 Broker 投递过来的消息。
- 提高核心链路吞吐量
- 降低应用系统之间的耦合度
- 增强整体服务的高可用能力
分析和设计一个典型的支付应用业务逻辑,以 “账单查询 Case” 为例,基本业务逻辑如下:
- 检索数据库,获取指定账户的账单记录。
- 记录用户的检索行为,为风险控制提供数据积累。
- 发送短信到用户手机,通知用户其账单被查询事件。
文章图片
“账单检索 Case” 同步 RPC 设计方案 A 依赖 “异步消息队列” 的设计方案 B 如下所示:
文章图片
“账单检索 Case” 消息队列设计方案 B 对比以上 A, B 两个设计方案,引入消息队列的设计方案 B 具有如下优势:
- “账单服务” 处理 “账单查询 Case” 的耗时由 60 ms 缩减至 13 ms, 提高了服务的吞吐量。
- “账单服务” 和 “风险控制服务”、“短信通知服务” 完全解耦,如果在业务演进过程中,增加了新的下游服务,“账单服务” 完全无需变更。
当 “风险控制服务” 和 “短信通知服务” 不可用时,不会导致 “账单服务” 不可用。
下面继续分析和设计 “账单变更 Case”,基本业务逻辑如下:
- 写入数据库,变更指定账户的账单记录。
- 记录用户检索行为,为风险控制提供数据积累。
- 发送短信到用户手机,通知用户其账户变更金额。
文章图片
“账单变更 Case” 消息队列设计方案 C “账单变更 Case” 消息队列设计方案 C 存在以下严重问题:
- “账单变更” 关联的数据库变更事务提交成功后,如果 “发布账单变更消息” 发送失败(例如网络异常或者消息队列服务不可用),则会导致 “记录用户行为” 和 “短信通知用户” 后续动作失败,无法完成风险控制数据积累,用户也无法及时获取到账户变更信息。
文章图片
“账单变更 Case” 消息队列设计方案 D 至此,可以梳理一下完美解决 “账单变更 Case” 需要解决的关键点:
- 必须满足“一致性”要求,即账单服务数据库变更事务提交成功,风险控制服务和短信通知服务收到“账单变更”消息;账单服务数据库变更事务回滚,风险控制服务和短信通知服务不会收到“账单变更”消息。
- “账单变更”消息发布失败,尽量避免导致数据库变更事务的回滚。
为了解决以上描述的两个需求,消息队列需要提供一种特殊类型的消息:消息队列收到消息后不会立刻投递消息到消息订阅者,而是根据消息发布者应用的数据库事务状态决定消息是否投递。如果数据库事务提交,则消息投递到订阅者;反之则不投递。此类消息被命名为 “事务型消息”。具体设计方案如下:
文章图片
事务型消息设计方案 E 按照 “事务型消息设计方案 E” 的时序图,消息发布者和消息队列之间增加了一个 “二阶段” 消息,用来标明对应事务型消息的 “事务状态”,消息队列根据 “二阶段” 消息决定是否投递消息到下游消息订阅者。应用 “事务型消息”,“账单变更 Case” 的可行解决方案如下所示:
文章图片
账单变更 Case” 消息队列-事务型消息设计方案 F
按照 “账单变更 Case” 消息队列-事务型消息设计方案 F,可以满足“账单服务数据库变更”与“异步消息是否投递到订阅者应用”的事务一致性需求。结合 Spring Framework 的事务模板工具类伪代码如下:
transactionTemplate.execute(new transactionCallback(){
@override
public Object doInTransaction(TransationStatus status){
try{
messageQueueSDK.publishTransactionMessage(message);
dbService.doUpdateOperation();
}catch (Exception e){
status.seRollbackOnly();
return null;
}
};
至于依据数据库事务提交/回滚状态决定事务型 “二阶段” 消息的发送,可以通过 Spring Framework 提供的事务模板同步器自动感知消息发布者本地事务状态,相关接口是:
org.springframework.transaction.support
TransactionSynchronizationManager.registerSyncronization(TransactionSyncronization)
至此,消息队列 “事务型消息” 的设计方案和实现原理基本阐明清楚了,还遗留两个可以深究的关键点:
- 为什么消息发布方法需要在本地数据库事务方法之前?
- 如果消息队列收不到事务型消息的二阶段“提交 or 回滚” 消息,如何处理?
针对第二个关键点,在分布式网络架构中是可能出现的,比如网络异常、消息队列服务短时间不可用等。这也是消息队列提供严谨的 “事务型消息” 特性必须要解决的问题,如果消息队列没有收到 “提交 or 回滚” 回滚消息,则无法决定是否投递消息到消息订阅者,因此,严谨的 “事务型消息” 设计方案需要有一个异常场景,命名为 “事务型消息状态回查”,具体设计方案如下:
文章图片
事务型消息回查设计方案G 需要明确的是,“事务型消息状态回查” 只在 “提交 or 回滚消息” 失败的场景下被触发,属于异常路径。
事务性消息总结
在分布式系统架构中,尤其是金融级业务应用的解决方案设计中,消息队列提供 “事务型消息” 特性是必不可少的,“数据一致性” 是金融级分布式架构的基本要求,本文通过实例逐步说明消息队列产品支持 “事务型消息” 的必要性、设计方案和原理,定义了明确的消息队列事务型消息的核心原理:
- 消息队列事务型消息基于 “二阶段” 消息实现。
- 事务型消息是否投递与消息发布者本地事务状态保持一致。
- 事务型消息状态回查是保证了 “事务型消息” 的严谨性。
本文来自云栖社区合作伙伴“中生代技术”,了解相关信息可以关注“中生代技术”。
推荐阅读
- 流转
- 一起来学习C语言的字符串转换函数
- 【58】转移注意力
- 考前焦虑——接纳情绪,转移注意力
- leetcode|leetcode 92. 反转链表 II
- 视频转换器哪种好用()
- 2018年7月11日|2018年7月11日 星期三 多云转晴(18)
- 以太坊中的计量单位及相互转换
- 随笔|随笔|蚂蚁的小船
- 爬虫数据处理HTML转义字符