记账处理过程主要包括两部分,一是记录记账凭证,二是更新账户的余额。为了保证账户不被其他请求影响数据的准确性,在进行记账处理时,会先对账户的资源加锁,记账处理完毕后会自动释放锁。随着账务处理业务量的增大,账务数据库中的账户常常会在瞬间产生多个并发操作,但所有对应的并发线程中只有一个线程能够持有当前账户的资源锁,其他线程必须等待该锁被释放后再逐一进行记账处理,这样该账户将会被频繁加锁释锁,使该账户成为账务数据库热点,产生性能瓶颈点,严重影响账务数据库的性能。
热点账户带来的其实是性能问题,多笔交易需要给同一账户记账时,会产生一笔交易等待前一笔交易记账完成才能接着记账的问题,这样就会产生事务等待问题。
一般是减少事务时间,从业务层面优化减少不必要的事务操作。
通过控制上游支付交易的请求数据的并发请求数来实现。
实时交易全部 insert 账户明细数据,insert 的开销比 加锁开销少。定时跑批将一段时间内的账务明细汇总成一条,一笔入账到指定账户。
避免了限流问题,交易都可以进来,实现也不复杂。
交易不能实时入账,账户加钱没啥问题,很实用,但是账户支出,减钱会出现账户透支问题。
缓存入账,将入账过程异步处理,使用 MQ 消息队列,可以达到削峰填谷的作用,是流量稳定的进来,然后稳定的处理即可。
实时记账 转换为准实时记账
可以让流量比较平缓,出现交易量暴增时,系统也能够处理。提升系统稳定性和实时性,可以准实时记账。
随着队列堆积的消息越来越多,记账请求来不及处理。这种方式也会导致 账户减钱出现账户透支的问题。
具体来讲,就是将一个热点账户对应多个影子账户, 将账户余额分散到各个影子账户,这样就没有热点账户问题。每次请求来的时候,通过 hash 选择合适的影子账户记账,这样账户请求形成了分散热点。
入账流程
热点分散了,解决了热点账户问题。
当选择影子账户扣款的时候,可能出现扣款不成功的情况,但是总的影子账户余额是够的,这样就会影响这笔扣款交易。
实际根据实际业务使用场景,按照金额变动方向,分成加频账户(余额增加频繁)、减频账户(余额扣减频繁)、双频账户(余额增加扣减均频繁)。
三种账户的处理方式各不一样:
选用内存数据库实时处理记账请求,然后异步更新到关系型数据库上。