分布式事务之本地消息表解决方案(跨地区转账实际案例)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 分布式事务之本地消息表解决方案(跨地区转账实际案例)

一、序言

1、现状


最近在做一个跨地区转账的功能,先说一下问题现状,公司业务范围主要分布在新加坡、香港和迪拜,相关交易、卡、账户等数据应各地区监管、合规要求必须分地区物理隔离,关于分库我们选择了中间件Sharding-Proxy,分片键为某个地区的区域码,所有的分片表都会带上区域码这个字段。


cf04f6870e584f7b9f50a7e9646cf3c6.png

如果是同地区转账,动账,交易记录读和写,带上当地区域码,所有的数据库请求都会由Sharding-Proxy路由到该地物理库,所以同地区转账同步在一个事务内跑完其实是没有问题的。


2、问题


如果是跨地区转账,比如从香港到迪拜,或者从新加坡到迪拜,那么问题就来了。虽然Sharding-Proxy本身支持分布式事务,但跨物理库分布式事务之前并没有过实际经验。


同时由于迪拜地区和新加坡、香港地域相隔很远,即使走专线网络传输时间也会比较长,而且转账业务中涉及到两个不同地区多个表的读写,余额变动时也会给出入账账户加上数据库行锁(排它锁),在大事务中很容易超时,同时接口响应慢也会影响用户体验。


于是,我们决定把出账和入账分离,入账通过MQ做成异步处理。


这个时候问题又来了,既然不能通过数据库本地事务保证ACID,那么分布式事务的问题该怎么解决呢?


二、方案探索


开源分布式事务解决方案有Seata,本身提供了ATTCCSAGA还有XA事务模式。但是该方案比较重量级、对外不透明,加上还要部署seata-server,额外增加了维护成本。

最后还是决定选择比较轻量级的解决方案,MQ+本地消息表+重试补发,大致流程如下。


671305731eab4b8988e820f0d2ecef15.png



先看出账方,出账记录、实际出账、本地消息表都在同一个事务,只要出账成功,那么本地消息表中一定会有转账相关的消息。


再看入账方,入账成功后,向ack_queue发送入账成功确认消息。


如果消费成功且入账成功,那么本地消息表中的消息会被逻辑删除,状态置为deleted。


如果消息发送失败、消费入账失败,本地消息表中消息状态会一直为undeleted状态,这时出账方会有一个补偿定时任务轮询本地消息表中状态为undeleted的出账消息。为了减少消息积压,当重试到一定次数后,停止发送消息到MQ,同时发送告警邮件给开发人员处理。


注意:入账方消费消息时需要做幂等,否则会重复入账,这里加上分布式锁就可以解决。


三、根据实际业务进行调整


实际我们的系统更加复杂,普通的转账是从A账户到B账户,而我们的转账A账户可能还会共享企业账户的余额。跨地区转账就更复杂了,每个地区都会有一个对公账户,资金变动流程如下:

60fc3ebbf0594f96a4aa7816c577db27.png

如果从香港地区的个人账户A转到迪拜地区的个人账户B,个人账户A和个人账户B又分别共享企业账户CACB的余额,那么完整的账户资金变动流程如下:

  1. 企业账户CA自动划账到个人账户A
  2. 个人账户A出账到对公账户PA
  1. 对公账户PB出账到个人账户B
  2. 个人账户B自动划账到企业账户CB

1、定时补偿扫表改为扫缓存


如果是直接轮询本地消息表,由于我们的本地消息表是广播表(PS:各个地区物理库都会有相同的表数据),查询时会随机查询各地区物理库,如果随机查询的是迪拜物理库本地消息表的记录,那么查询就会比较慢了。


因此在写完本地消息表后,我们同时会将本地消息表的记录写到Redis中,后续定时任务补偿直接扫缓存而不扫表。


同时在入账消费者方成功处理入账后,除了逻辑删除本地消息表中的记录(置为deleted),还要删除Redis缓存中的记录。


问题:写本地消息表和写Redis缓存这里可能会出现缓存不一致的情况,如果本地消息表写成功了,但Redis缓存写失败了,那么在做定时任务补偿扫缓存时会丢到该记录,这里缓存一致性需要保证。


2、出账异步处理


可以看到,出账时从企业余额共享账户CA个人账户A对公账户PA,中间会有3个账户的余额变动和出账记录,如果是同步返回,响应时间会比较长,也会影响用户体验,出账操作这里可以通过线程异步。


3、去掉ack_queue


目前系统出账方和入账方并没有跨系统,数据库也没有根据业务做垂直拆分,因此消费者入账成功后可以去掉发确认消息到ack_queue中,直接在消费端操作数据库将本地消息表中的记录状态置为deleted并删除缓存就好。


4、入账失败一直重试


跨地区转账业务这里还比较特别,有可能会出现公账的钱不够扣,导致交易失败。如果转入方公账钱不够扣就会导致入账失败,但转出方实际已经扣款成功了,因此入账操作必须成功,出账方定时任务针对本地消息表中的Pending记录会一直重试,直到入账方公账金额够扣,入账交易成功。

备注:在实际业务中,跨地区转账入账方真正到账是有延迟的,虽然出账和入账操作程序只需要在账面上进行余额的扣和减,但是比如从香港地区到迪拜地区,真正的钱要和当地结算后汇款过去才能到账的。


四、可能出现的系统瓶颈


1、各地区公账可能会出现抢锁超时


目前在每个地区都只设有一个公账账户,而在做跨地区转账时,每次都会操作出账方和入账方的公账余额。而在做余额变动时,将会对指定账户加数据库行锁(排它锁),虽然转账业务并不是很频繁,但是如果并发上来确实会导致过多线程等待数据库行锁释放,可能会出现锁争抢超时。


2、出账时异步扣款线程池大小不够用


由于扣账涉及多个账户的余额变动以及业务表记录,扣账操作响应时间会比较长,所以我们通过线程异步,提升用户体验。同时这里扣张操作核心线程数、阻塞队列长度和最大线程数不是很好把控,还是需要根据实际请求量进行调整,拒绝策略我们设置的是交由主线程执行。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
Oracle 关系型数据库 分布式数据库
分布式数据库集成解决方案
分布式数据库集成解决方案
205 0
|
2月前
|
Nacos 数据库
分布式事务解决方案Seata
分布式事务解决方案Seata
26 1
|
3月前
|
消息中间件 存储 负载均衡
【亿级数据专题】「分布式消息引擎」 盘点本年度我们探索服务的HA高可用解决方案
昔之善战者,先为不可胜,以待敌之可胜。不可胜在己,可胜在敌。故善战者,能为不可胜,不能使敌之必可胜。故曰:胜可知,而不可为。
87 2
【亿级数据专题】「分布式消息引擎」 盘点本年度我们探索服务的HA高可用解决方案
|
3月前
|
消息中间件 Dubbo 应用服务中间件
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)
83 0
|
Dubbo 应用服务中间件 微服务
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)(上)
分布式事物【Hmily实现TCC分布式事务、Hmily实现TCC事务、最终一致性分布式事务解决方案】(七)-全面详解(学习总结---从入门到深化)
47 1
|
6天前
|
存储 缓存 算法
【专栏】探索分布式限流:挑战与解决方案
【4月更文挑战第27天】在互联网时代,分布式限流是应对高并发、保护系统稳定的关键。它面临数据一致性、算法准确性和系统可扩展性的挑战。常见限流算法有令牌桶、漏桶和滑动窗口。解决方案包括使用分布式存储同步状态、结合多种算法及动态调整阈值。定期压力测试确保策略有效性。随着系统规模增长,限流技术将持续发展,理解并应用限流原理对保障服务质量至关重要。
|
2月前
|
缓存 应用服务中间件 数据库
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(多级缓存设计分析)
37 1
|
2月前
|
存储 缓存 监控
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(场景问题分析+性能影响因素)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(场景问题分析+性能影响因素)
36 0
|
2月前
|
缓存 监控 负载均衡
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(数据缓存不一致分析)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(数据缓存不一致分析)
30 2
|
2月前
|
存储 缓存 监控
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(数据更新场景策略和方案分析)
【分布式技术专题】「缓存解决方案」一文带领你好好认识一下企业级别的缓存技术解决方案的运作原理和开发实战(数据更新场景策略和方案分析)
9 0