文档章节

账户系统如何应对高并发、热点账户等问题

宜信技术学院
 宜信技术学院
发布于 09/16 10:06
字数 2791
阅读 5744
收藏 130

互联网金融系统的核心是支付结算,而支付结算的基础又是账户系统。互金账户系统的特点是并发量大、响应快、交易金额大,热点账户问题突出。一个合格的账户系统既要解决上述问题,又必须绝对保证资金安全。作为宜信这家互联网金融公司的支付结算中心,其账户系统也必须具备上述特征。

一、账户体系

1.1 账户结构

宜信支付结算账户体系是客户、用户、账户三层结构,证件号和证件类型唯一确定一个客户,客户号和机构号确定一个用户,一个用户下可开多个不同类型的账户。如图:

1.2 账户属性

账户系统的基础是账户,所有的操作都围绕着账户进行,账户包含以下一些属性:

  • 会计科目:每个账户金额的变动要体现一些会计的属性,以便会计核算。
  • 账户类别:分为个人账户、企业账户、平台类账户。
  • 账户明细:账户的明细是反映账户余额变动的每笔详情,采用复式记账法,包含本对方账号、账户等信息、摘要、借方的发生额及余额等信息。
  • 账户余额:记录账户的实时余额。

1.3 会计科目

账户下挂在最底层的会计科目下,会计科目决定了账户的含义及余额变动方向。会计科目的一些属性如下:

  • 科目类别:资产类、负债类、所有者权益、成本类、损益类等。
  • 科目级别:会计科目的级别,一级科目、二级科目、三级科目等。下级科目归属上级科目。
  • 余额方向:标示余额是在借方还是贷方。
  • 科目的期末余额:每日日切后会汇总底层科目所有下挂账户在上一会计日的余额总和,上级科目汇总下级科目的余额总和。

1.4 科目树

宜信支付结算账户系统采用科目树的概念,每个机构都会绑定一个科目树。科目树的根节点是一级科目,底层的科目下挂账户,结构如下:

二、账户系统架构

宜信支付结算账户系统采用公司自研的分布式微服务框架,对外提供http json接口,内部各服务间采用redis实现的消息队列通讯。

2.1 账户系统功能架构

宜信支付结算账户系统分为接入模块、记账子系统、开户子系统、异步记账模块、查询子系统、定时任务子系统、日终子系统、异步日志模块,下图是账务系统功能模块图:

  • 接入模块:提供报文解析、验签、参数校验、权限认证等公共服务,是账户系统的统一入口。
  • 异步日志模块:异步记录业务系统请求报文。
  • 记账子系统:账户系统的核心模块,处理业务系统的记账请求。
  • 开户子系统:处理业务系统的开户请求。
    • 首次开立账户:为个人或企业开立客户、用户及提前配置的默认开通的账户。
    • 指定开立账户:个人或企业在首次开立账户后,可按科目号指定开立账户。
  • 查询子系统:提供账户、记账的一些查询功能。
  • 异步记账模块:提供异步记录账户流水的功能。
  • 定时任务子系统:处理失败重试、热点账户等的定时任务。
  • 日终子系统:提供日切以及日终跑批的功能。

2.1.1 记账处理

记账处理是账户系统的核心功能,该功能对性能的要求比较高,高并发下热点账户问题比较突出,资金的正确性也必须保证,并且根据业务不同,记账的分录也是五花八门,宜信支付结算账户系统如何应对这些问题,这里重点介绍下:

  • 账户系统记账采用记账服务的概念,每个记账服务就是一个记账分录的模板,业务系统按照这个模板传入记账金额、账户号或者用户号等信息。
  • 账户系统采用redis分布式锁,防止业务系统重复提交请求。设置记账订单防重表,按照请求单号和机构号对记账请求做幂等性校验。
  • 采用复式记账法,按照会计规则按照借贷记录流水,有借必有贷。
  • 记账处理时,更新账户余额后同步返回结果给业务系统,异步的处理记账流水。同时设置补偿机制,定时重试记账流水处理失败的订单,重试三次失败后报警人工介入。
  • 记账规则处理,每个记账服务可以绑定一些记账规则,账户系统根据记账服务遍历其绑定的规则,顺序处理。

2.1.2 热点账户问题

热点账户问题是账户系统的痛点,也困扰了我们很久,这里着重说下。

-- 充值时的记账分录是:

借方:三方支付待清算账户(+)

贷方:个人余额账户(+)

当大量用户充值时,三方支付的待清算账户就是热点账户,频繁的增加余额。

-- 提现时的记账分录是:

借方:个人余额账户(-)

贷方:三方支付资产账户(-)

当大量用户提现时,三方支付的资产账户就是热点账户,频繁的减少余额。

--业务收服务费的记账分录是:

借方:个人账户(-)

贷方:商户服务费账户(+)

当大量向用户收取服务费时,商户服务费账户就是热点账户,会频繁增加余额。

--业务服务费付款的记账分录是:

借方:商户服务费账户(-)

贷方:个人账户(+)

当大量用服务费余额向用户付款时,商户服务费账户就是热点账户,会频繁减少余额。

记账时,所有涉及的账户余额都要做update更新,高并发情况下,当出现上述类型的热点账户时,由于数据库的行级锁,对同一账户的更新余额操作由并行变成串行,单个请求的响应时间变长,从而拖垮整个记账服务。

宜信支付结算账户系统针对上述问题做了如下处理:

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

  • 加频账户处理

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

  • 减频账户处理

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

  • 双频账户处理

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

2.1.3 记账死锁问题

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

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

宜信支付结算账户系统针对这种情况提出了解决办法,对账户号进行排序后再更新余额,这样每个线程都是先更新A再更新B,解决了死锁问题。

2.2 账户系统存储层架构

宜信支付结算账户系统数据库采用Mysql,缓存采用redis。

  • Mysql数据库采用主从架构,一主二从,主库向从库同步数据。针对一些数据量大的表进行分表,比较有代表性的是账户流水表,既要按账户维度查询,又要按时间维度汇总,所以针对这个特点,冗余了一张表,一张按照账户分表,一张按照日期分表。

  • Redis采取集群架构,集群中每个点主备的形式。

2.3 账户系统的网络层架构

账户系统各个服务部署在同一机房,其中记账子系统和异步记账模块部署在4个不同的物理机上,其他子系统和模块部署在2个不同物理机上。最前端采用nginx实现负载均衡。

作者:李锐 程留允

© 著作权归作者所有

宜信技术学院

宜信技术学院

粉丝 242
博文 140
码字总数 465076
作品 5
东城
私信 提问
加载中

评论(18)

你是mvp
你是mvp
有一种做法叫“缓冲入账”.......
talentshu
talentshu
拆子账户隐患多多, 比如一笔交易 要扣1000,你拆了10个子账户,每个还有 99。你怎么合?你合不合?你怎么知道要不要合不合?一个一个合得等多久?这文章太粗了。
Skqing
Skqing
这确实是个问题
Ryan-瑞恩
Ryan-瑞恩
Redis 集群是个什么部署模式?规模多大?
O龙猫O
O龙猫O
业务技术结合得非常棒,都是干货
心心念叨的人
用redis做服务间消息通讯 比较少见。redis在mq方面比较弱吧
_Mr_Right_
_Mr_Right_
我这边系统用redis做了 MQ,感觉还好。简单,是否使用还得看各自的实际情况。
心心念叨的人
就一个最简单的,业务方服务重启时,得做很多操作比如轮询重发消息才能保证消息不丢失吧,不知道你们怎么做的,但如果是我,我会选择任何一个带消息持久化的mq
_Mr_Right_
_Mr_Right_
是否使用还得看各自的实际情况。 我这边的业务目前不需要考虑消费异常的情况。不需要持久化,允许失败。 场景:各系统之间同步一些信息。
f
freezingsky
我也想知道, 多实例下, redis做Pub/Sub, 一方面要做锁, 一方面,消息如果消费异常, 无法重新消费. 你那边是怎么处理的?
_Mr_Right_
_Mr_Right_
是否使用还得看各自的实际情况。 我这边的业务目前不需要考虑消费异常的情况。不需要持久化,允许失败。
cevin
cevin
看起来像个解决问题的设想自己都没实施过的样子。。
石日天
石日天
加入分成两个子账号。每个都只剩下50块,但是要出100块怎么办
hitank1
hitank1
这个把其他一个转过去就好了,如果是100个账号,每个账号是1块钱,这是要出100块,那么就麻烦大了
rouway
rouway
上面有說,餘額不足報警和資金歸集
hitank1
hitank1
系统的复杂性增加了很多,想问个问题,假设减频子账户其中一个分不够了,需要去汇总,汇总的方案是什么
talentshu
talentshu
作者根本不懂技术,这个方案并不靠谱。很有可能他们也没实施过。
isscy
isscy
粒度太大了,具体解决问题的细节并没有进行说明和分析。
支付结算系统如何应对高并发、热点账户等问题

互联网金融系统的核心是支付结算,而支付结算的基础又是账户系统。金融账户系统的特点是并发量大、响应快、交易金额大,热点账户问题突出。一个合格的账户系统既要解决上述问题,又必须绝对保...

宜信技术
09/16
0
0
苏宁金融红包系统大促海量流量背后的技术支撑

发红包是目前各大互联网公司最常用的营销手段之一,它形式多样,内容丰富。2016 年底苏宁金融开启了红包系统及相关系统的项目开发。 本文将对苏宁金融红包系统的架构部署方式、演变过程、技术...

架构师springboot
01/18
94
0
苏宁金融红包系统大促海量流量背后的技术支撑

发红包是目前各大互联网公司最常用的营销手段之一,它形式多样,内容丰富。2016 年底苏宁金融开启了红包系统及相关系统的项目开发。 本文将对苏宁金融红包系统的架构部署方式、演变过程、技术...

架构师springboot
01/18
0
0
java 订单和账户系统如何设计?

在一个高并发的系统,如何设计订单和账户支付系统满足高并发时候系统正常运行。比如淘宝的 的订单和账户系统。 我的理解是这样的: 对前端过来的订单请求 放到订单队列里面,订单系统每次只去...

wdragon1983
2014/12/07
2.8K
0
《实战Java高并发程序设计》问答录,看这些问题解决你所有java并行难题

为大家解答关于 Java 的并行程序设计基础、思路、方法和实战 方面的问题。如: 现在的服务器 CPU 可能多达 10 个以上的内核,并发编程市场需求量激增,如何才能将多核 CPU 的性能发挥到极致呢...

吴小编
2016/01/22
424
0

没有更多内容

加载失败,请刷新页面

加载更多

Andorid SQLite数据库开发基础教程(2)

Andorid SQLite数据库开发基础教程(2) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库。...

大学霸
21分钟前
3
0
YecPad 开源啦!: 基于C#的功能强大的可编辑记事本文本编辑软件

JY Lin 开源:YecPad : 基于C#的功能强大的可编辑记事本文本编辑软件 YecPad 是一款基于C#编程语言开发的功能强大的可编辑记事本文本编辑软件。 可以进行文本文件的打开、保存、删除及编辑功...

YDOOK
29分钟前
3
0
StringBuilder 与 StringBuffer 的区别

StringBuffer是线性安全的,支持并发操作,适合多线程。 StringBuilder线性不安全,不支持并发操作,适合单线程。 也就是说他们俩区别就在于支不支持并发操作,使用上基本上类似...

无名氏的程序员
31分钟前
3
0
js 找数组中的最值

本文转载于:专业的前端网站➸js 找数组中的最值 背景: 2个数组以下 , 比如 [[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]] 找最值的时候,我一开始想用两个...

前端老手
40分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部