金融交易场景下热key如何解决

2022-08-05 11:50:22 浏览数 (1)

TPS(Transaction Per Second) 每秒钟系统能够处理的交易或事务的数量。它是衡量系统处理能力的重要指标。交易场景下一般使用TPS衡量系统性能.

问题定义

所谓 热点账户 是指产生资金流入流出请求笔数巨大的账户,请求持续时间可能是秒级,也可能较长一段时间。

热点账户普遍存在于大商户的支付收单场景,如直播大V带货、商户活动营销等,形成对单个账户的账务请求洪峰,记账时,所有涉及的账户余额都要做update更新,高并发情况下,当出现热点账户时,由于数据库的行级锁,对同一账户的更新余额操作由并行变成串行,单个请求的响应时间变长,不仅会影响支付体验,还可能会导致系统的大范围故障,甚至是集群的雪崩。

解决方案

第一种方式: 限流排队

最暴力的,也是最简单的。直接在账户系统加一个限流层,不管你请求有多大,我都先放在缓冲区慢慢处理, 这种方式,记账准确,但是体验很差.

image.pngimage.png

第二种方式: 帐号分级, 热账户拆分出多个子账户.

我们把热点账户按照金额变动方向分为加频账户(余额增加频繁)、减频账户(余额扣减频繁)、双频账户(余额增加扣减均频繁)。

  • 加频账户处理

准实时更新余额。先将金额变动插入临时表中,由定时任务按照一定频率汇总发生额,并更新账户余额,而后删除临时记录。当加频账户减钱余额不足时,主动去汇总发生额。这里需要考虑主动汇总发生额和定时任务处理的并发情况,我们在该定时任务执行时设置redis锁,防止并发,主动汇总时会去判断这个redis锁是否存在,如存在证明定时任务正在执行,无需主动汇总,可能是真的余额不足。主动汇总同样会设置redis锁,定时任务同样会判断。

  • 减频账户处理

将减频账户拆分多个子账户,减频子账户设置金额报警,如果某个减频子账户余额不足触发报警,会对该子账户做资金归集,将其他子账户余额归集到该子账户(每个子账户设置可归集金额限制)。如在交易过程中发现该子账户余额不足,转向使用其他子账户记账。由于拆分子账户,余额查询时需要汇总各个子账户余额返回;记录主账户流水需要记账后余额,这里需要异步计算汇总。当减频账户加钱时,需要平均分配入账到不通的子账户。

  • 双频账户处理

将双频账户拆分多个子账户。加钱时,准实时更新余额,先将子账户金额变动插入临时表中,由定时任务按一定频率汇总发生额,将汇总的发生额更新进对应的子账户,并删除金额变动记录;减钱按照之前减频账户的逻辑执行。

高并发情况下,当多个账户之前互相转账时,可能会出现死锁问题。

例如:A余额账户 —> B余额账户(线程1) 和 B余额账户—>A余额账户(线程2) 两个转账请求并发,账户系统对每个转账请求都会更新A、B余额,这两个更新需要在一个事务里,正常流程线程1先更新A,再更新B,线程2先更新B,再更新A,线程1更新完A后会等待B的锁,不提交事务,线程2更新完B后会等待A的锁,不提交事务,这样两个线程互相等待锁,造成死锁。

这种情况下一般是要先对账户号进行排序后再更新余额,这样每个线程都是先更新A再更新B,解决了死锁问题。

这种方式体验会更好, 但是极端情况下可能出现乱账问题, 需要完善的监控以及事务补偿机制.

第三种方式: 通过数据库优化

其实就是把方案二放到了数据库层面实现, 数据库自动进行拆分以及合并处理, 同时提供一致性和安全性保证.

参考

《在微服务中如何应对账户系统的高并发、热点账户等问题》

《高性能帐务数据库Maxwell:自主可控、超低延时》

《支付技术那些事》

0 人点赞