热点账户出款问题

一、背景
本文讨论热点账户出款问题。

二、问题
热点账户出款问题,主要集中在每次扣款请求都需要锁定热点账户,重新计算余额,造成性能低下。

问题的原因是:在大并发情况下,同时会有大量的扣款请求从热点账户进行扣款。扣款的流程是:

1、判断热点账户的余额是否充足。

2、余额不充足,直接返回失败。

3、余额充足,则重新计算余额。

4、更新热点账户的余额。

这样扣款的过程,就成了一个串行的过程,造成效率比较低下。

三、目标
热点账户扣款TPS达到1000/S。

三、解决思路
热点账户的解决思路有两种,一种是减少扣款请求的数量,一种是增加扣款账户的数量(子账户)。此处采用减少扣款请求数量的方式。
在这里插入图片描述

通过“请求合并”的方式,减少发往扣款模块的请求数量,从而提升扣款的整体性能。

四、方案
1、方案详解
在这里插入图片描述
如上图所示,该方案的核心是通过请求合并的方式,把多个扣款请求缩容为1个扣款请求,这样一次数据库操作,可以同时处理多笔扣款。

第一步:扣款请求缓存。
并发的扣款请求先缓存在“扣款请求队列”中。

第二步:扣款请求合并。
扣款模块按批次从“扣款请求队列”中读取部分扣款请求数据,一次性发给扣款过程处理。

第三步:扣款过程处理。
扣款模块获取到一个批次的扣款请求后,会执行以下步骤:

1)计算整个批次扣款请求的总额。
2)为该账户的余额信息增加行锁;获取该账户的余额,判断余额是否足够。
3)假如余额足够,则在一个事物中记录该批次扣款请求流水(状态为成功),更新账户的余额。
4)假如余额不足,则对该批次的请求重新分批,找到余额充足的最大批次,对选择的批次执行第一步。其余的请求也需要记录流水,状态为失败。
5)提交事务,释放行锁。
第四步:扣款结果反馈。
把整个批次的执行结果,发送到“扣款请求响应队列”中。

2、技术难点处理
该方案在实现过程中有几个关键问题需要处理:

1)分批大小是什么?
此处分批大小的主要限制条件是mysql事物的大小限制,以及在多大的事物下能获取到最高的性能。可以通过压力测试的方式得到最佳方案。参考文档:http://blog.jobbole.com/29432/
了解我们的数据库集群有什么样的限制。
2)异常处理流程?
读取消息错误:消费端释放锁,由下一个消费端处理。
数据库操作错误:写数据库错误,事物回滚,消费端释放锁,由下一个消费端处理。
写消息错误:进行重试。
3)余额不足的处理流程?
余额不足后,对分批数据重新进行分批的算法,是影响性能的一个关键因素。此处的算法不需要精确计算最大的合法批次,模糊即可。这样能保证计算的效率,失败的请求可以通过重新发起的方式进行。
4)请求流水表数据量大的问题?
根据业务的实际情况进行分表,每个表中的数据原则上不能超过5000w条。
5)并发处理流程?
多热点账户问题:该方案下,每个热点账户的请求应该分发到不同的队列中。
同一个热点账户:消息消费需要加锁,一个消费端处理完后,下一个消费者才可以使用。

发布了48 篇原创文章 · 获赞 34 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/u013252773/article/details/89318974