面试官:做过支付资产?那先聊聊热点账户吧

数据库
在高并发的情况下,针对热点账户如何进行账户金额的冲扣,接下来,咱们一起从以下几点来剖析一下这个问题吧。

背景

当前形势不佳,在这种情况下。小猫更是雪上加霜,他被裁了。投了个把月简历,终于约到一个面试。

面试官:“看你简历上写了支付和账户相关项目,那能否聊一下热点账户问题你们是咋处理的吧”。

小猫懵逼了一会,“额?什么是热点账户?我们好像模型里面就一个资产账户,然后充值的时候和消费的时候更新一下该账户,并且记录一下操作明细,然后结束了。”

面试官:“哦。回去等通知吧。”

出来之后,小猫整个人都还是懵逼的。

问题分析

我们一起来看一下这样一个问题,其实这里面试官想要知道的是,在高并发的情况下,针对热点账户如何进行账户金额的冲扣,小猫没有get到面试官的点,可能他负责的项目中本身的量不大,压根就没有想过这类问题。如果问的是你,你该如何应对呢?

接下来,咱们一起从以下几点来剖析一下这个问题吧。

目录

什么是热点账户?

热点账户一般指被高频更新的账户,比如短时间内大量的账户余额更新请求集中在极少数账户上。这类账户虽然数量不多,但更新频率很高,处理不当可能会带来严重的性能问题,影响其他账户的正常读写操作。

我们来看一下热点商家账户S的例子,可能更容易让人理解。大量请求并发打到我们数据库底层表的时候,底层账户S究竟发生了什么。假设我们现在有用户A、用户B、用户C,等等可能更多,另外有一个商家账户S,我们暂时枚举三个,那么当其同时并发打到底层数据库的时候,就有如下图所示。

数据库底层更新

上图中我们可以看到,对于同一个商家账户S,由于实际的业务需要更新可用账户余额,所以单笔冲扣都是在一个事务中进行的,任何的更新行为都会对数据库上行锁。由于并发量大,请求的数量又多,大家很容易就能想到锁的等待问题会严重影响性能。

热点账户的分类

上述我们知道了什么是热点账户,并且知道了热点账户产生的原因。其实热点账户根据资金的出入可以分成三种。

  • 双频账户 :上图中我们看到商家账户既有出也有入,那其实这样的账户就可以理解为双频账户。双频账户指入账频次以及出账频次都很高的账户。
  • 加频账户:大家可能可快就知道了还有纯入账频次高的,那么这个就是加频账户。
  • 减频账户:纯出账的账户那么即为减频账户。

针对这样的三种账户类型,大家其实可以联想一下这些账户对应哪些生活中的场景。

热点账户解决方案

透过现象看本质,其实要解决热点账户问题,其实就是解决数据库压力过大,数据库表更新失败,执行效率过低的问题。那么解决该类问题,阁下该如何应对?(其实小猫如何可以理解面试官的用意,解决方案应该可以想到几个)

1.提升硬件设备性能

如果数据库压力过大,数据库执行效率低,最简单的方式就是调整硬件设备呗。把连接池优化,把CPU优化,把磁盘优化,内存优化等等。在此不展开赘述。老猫给他定义了个别名“大力出奇迹法”。

2.限流法

这种其实也很简单,但是有点粗暴,数据库压力大,那么咱们就让流量少一点打到数据库层呗。做个限流不就结了么。

限流

这种方式无论是上述那种类型的热点账户,显然都支持这种优化方法。

但是用户能满意么?买个东西老半天,重试好久都是支付失败,用户估计会跳起来吧。

这种牺牲用户体验的方案不是一点用处都没有,这种其实完全可以配合其他方案一起,作为一种最终的兜底方案。

3.预写记账日志(WAL-Write Ahead Log)

很多中间件类似于zk、etcd、es等,包括mysql底层以及很多的操作系统其实都用到了WAL的思想,感兴趣的小伙伴可以找一下相关资料。我们也借鉴这种思想,mysql在执行insert语句的时候的效率,其实要比Update执行效率高得多,更新的时候需要获取读和写,但是insert只需要执行顺序插入即可。因此咱们就有了下面了这样的设想方案。

我们先将账务明细插入到MySQL中,再读取明细,完成账户底层的更新动作。

  • 优点:实时的交易全部是insert账务明细,能大大提高入账速度,账户最终更新的频度我们可以自行把控,减少并发带来的压力。
  • 缺点:账户更新存在延迟,这样的话有可能会造成账户透支的风险。
  • 适用:所以这种方案加频类型的热点账户非常适用,但是对于减频账户以及双频账户就需要结合具体业务慎重考虑,因为会存在账户透支可能。

4.异步削峰缓冲记账

我们预写记账方式其实通过异步把控频率进行更新账户,异步削峰模式其实和上述模式有点类似,说到削峰填谷大家很容易就能想到消息队列,于是就有了我们下面的这种方案。

采用消息队列的方式,可以缓解突然到来的大流量。消息多的时候会堆积在队列中,然后被消费慢慢更新下去。

  • 优点:避免了突增的流量给系统带来的冲击。
  • 缺点:账户更新并不是及时的,另外的话,如果程序处理不当或者其他原因,会造成消息丢失,从而造成记账错误,同样也存在账户透支风险。
  • 适用:对于加频类型的账户比较适用,对于减频账户以及双频账户慎用,同样也会存在账户透支风险。譬如加频场景:在B端收单账户与业务中间账户处理;减频场景在C端微信、头条等春节抢红包入账处理(注意账户透支风险)。

5.汇总明细记账

关于该方案其实思路是这样的,既然多次频繁更新账户余额成为瓶颈,那么我们就将多次更新统计之后转换为一次更新。如下图:

汇总明细记账

这种基于统计之后更新账户余额的行为,也是异步进行的。所以优缺点当然也是显而易见的。

  • 优点:化多次账户余额更新操作为一次,减少了数据库的读写操作。
  • 缺点:由于是异步进行,交易其实并不能实时入账,如果是减频账户场景的话,也还是会有账户透支风险。
  • 适用:非常适用加频热点账户,对于减频账户以及双频账户慎用。

6.账户拆分记账

既然单个账户写入的时候压力过大,那么我们就将单个热点账户拆分成多个子账户去分散每个账户的读写压力。

账户拆分记账

这种方案只要能够处理好扣款时,子账户余额不够扣,资金归集处理得好,那么问题其实也能够得到很好的解决。

  • 优点:分散了单个热点账户的写入量。
  • 缺点:子账户扣款的时候余额扣款处理需要做资金归集,可能出现扣款失败,但是如果归集做的好,那么其实问题也不大。
  • 适用:这种方案适用于所有类型的热点账户类型。

7.缓存记账

Mysql的读写能力不好,那么我们就去寻找比Mysql读写效率更高的中间件,将结果预先计算好,那么我们很容易就想到了用非关系型数据库作为前置账户,比如redis,让计算结果先在redis中计算完成,然后最终异步flush到mysql中。

redis缓存

  • 优点:缓存的吞吐量远远高于mysql,而且速度很快。
  • 缺点:数据容易丢失。
  • 适用:这种方案适用于热点账户的任意一种类型,但是由于其数据准确性的考虑,往往对金额不是那么敏感的可以采用该方法,例如刷短视频得积分这种场景。可以采用该类方案。
责任编辑:赵宁宁 来源: 程序员老猫
相关推荐

2020-02-18 15:15:05

Handler消息队列执行任务

2022-05-23 08:43:02

BigIntJavaScript内置对象

2021-12-13 11:54:13

SetEs6接口

2020-07-03 14:19:01

Kafka日志存储

2022-03-21 09:05:18

volatileCPUJava

2019-04-29 14:59:41

Tomcat系统架构

2023-07-13 08:19:30

HaspMapRedis元素

2021-10-26 11:53:50

微信面试支付

2022-11-30 08:19:15

内存分配Go逃逸分析

2021-07-05 07:55:11

String[]byte转换

2019-12-20 08:52:01

算法单链表存储

2015-08-13 10:29:12

面试面试官

2022-12-06 09:03:31

MySQL索引

2020-09-17 17:53:12

面试ArrayList数组

2023-02-16 08:10:40

死锁线程

2021-11-09 14:08:45

DockerDockerfileJava

2021-11-02 09:05:25

Redis

2024-02-20 14:10:55

系统缓存冗余

2024-03-05 10:33:39

AOPSpring编程

2021-09-07 10:44:33

Java 注解开发
点赞
收藏

51CTO技术栈公众号