互联网金融系统的核心是支付结算,而支付结算的基础又是帐户系统。互金帐户系统的特色是并发量大、响应快、交易金额大,热点帐户问题突出。一个合格的帐户系统既要解决上述问题,又必须绝对保证资金安全。做为宜信这家互联网金融公司的支付结算中心,其帐户系统也必须具有上述特征。前端
宜信支付结算帐户体系是客户、用户、帐户三层结构,证件号和证件类型惟一肯定一个客户,客户号和机构号肯定一个用户,一个用户下可开多个不一样类型的帐户。如图:nginx
帐户系统的基础是帐户,全部的操做都围绕着帐户进行,帐户包含如下一些属性:redis
帐户下挂在最底层的会计科目下,会计科目决定了帐户的含义及余额变更方向。会计科目的一些属性以下:sql
宜信支付结算帐户系统采用科目树的概念,每一个机构都会绑定一个科目树。科目树的根节点是一级科目,底层的科目下挂帐户,结构以下:数据库
宜信支付结算帐户系统采用公司自研的分布式微服务框架,对外提供http json接口,内部各服务间采用redis实现的消息队列通信。json
宜信支付结算帐户系统分为接入模块、记帐子系统、开户子系统、异步记帐模块、查询子系统、定时任务子系统、日终子系统、异步日志模块,下图是帐务系统功能模块图:缓存
记帐处理是帐户系统的核心功能,该功能对性能的要求比较高,高并发下热点帐户问题比较突出,资金的正确性也必须保证,而且根据业务不一样,记帐的分录也是五花八门,宜信支付结算帐户系统如何应对这些问题,这里重点介绍下:安全
热点帐户问题是帐户系统的痛点,也困扰了咱们好久,这里着重说下。网络
-- 充值时的记帐分录是:架构
借方:三方支付待清算帐户(+)
贷方:我的余额帐户(+)
当大量用户充值时,三方支付的待清算帐户就是热点帐户,频繁的增长余额。
-- 提现时的记帐分录是:
借方:我的余额帐户(-)
贷方:三方支付资产帐户(-)
当大量用户提现时,三方支付的资产帐户就是热点帐户,频繁的减小余额。
--业务收服务费的记帐分录是:
借方:我的帐户(-)
贷方:商户服务费帐户(+)
当大量向用户收取服务费时,商户服务费帐户就是热点帐户,会频繁增长余额。
--业务服务费付款的记帐分录是:
借方:商户服务费帐户(-)
贷方:我的帐户(+)
当大量用服务费余额向用户付款时,商户服务费帐户就是热点帐户,会频繁减小余额。
记帐时,全部涉及的帐户余额都要作update更新,高并发状况下,当出现上述类型的热点帐户时,因为数据库的行级锁,对同一帐户的更新余额操做由并行变成串行,单个请求的响应时间变长,从而拖垮整个记帐服务。
宜信支付结算帐户系统针对上述问题作了以下处理:
咱们把热点帐户按照金额变更方向分为加频帐户(余额增长频繁)、减频帐户(余额扣减频繁)、双频帐户(余额增长扣减均频繁)。
准实时更新余额。先将金额变更插入临时表中,由定时任务按照必定频率汇总发生额,并更新帐户余额,然后删除临时记录。当加频帐户减钱余额不足时,主动去汇总发生额。这里须要考虑主动汇总发生额和定时任务处理的并发状况,咱们在该定时任务执行时设置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,解决了死锁问题。
宜信支付结算帐户系统数据库采用Mysql,缓存采用redis。
Mysql数据库采用主从架构,一主二从,主库向从库同步数据。针对一些数据量大的表进行分表,比较有表明性的是帐户流水表,既要按帐户维度查询,又要按时间维度汇总,因此针对这个特色,冗余了一张表,一张按照帐户分表,一张按照日期分表。
Redis采起集群架构,集群中每一个点主备的形式。
帐户系统各个服务部署在同一机房,其中记帐子系统和异步记帐模块部署在4个不一样的物理机上,其余子系统和模块部署在2个不一样物理机上。最前端采用nginx实现负载均衡。
做者:李锐 程留允