账务相关小结

工作的这几年确实和账务系统的同学打过一些交道,我是做信贷业务的,从信贷业务的角度来简述一下账务相关的事宜吧。

首先介绍一些名词概念:
用户余额,是指该用户还有多少余额可以用,银行储蓄卡上的余额数字。
信贷业务还有用户授信额度,分为用户的固定额度或者临时额度,一般是银行信用卡上的额度数字。用户的可用额度=用户当前拥有的授信额度-可已经使用的额度。

当我们使用信用卡发起一笔境内消费时,比如我们用信用卡买了100元的菜,那么我们的可用额度就会减少100元,菜饭的商户余额就会增加100元。这一减一增,要么一起执行,要么一起不执行。这一般就是用事务来完成的。
事务有ACID四个性质,分别是原子性、一致性,隔离性和持久性。

原子性(Atomicity):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。[1]
一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。[1]
事务隔离(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。[1]
持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

一般CS专业的学生都是在学习数据库的是时候学习了事务。数据库的事务语句

Begin transaction
SQL1
SQL2
End transaction

既然提到了数据库的事务,再多提一下数据库事务的隔离级别,由低到高依次为Read uncommitted 、Read committed、Repeatable read 、Serializable ,RC、RR和序列化逐个解决脏读 、不可重复读 、幻读这几类问题。
事务隔离级别-学习

但是我们的日常工作中,资源都是分布在不同的应用系统中的,面对这种需求,我们引入了分布式事务。分布式事务常用的解决方案一般是两阶段提交。两阶段提交需要一个或多个资源管理器(RM)、一个事务管理器(TM,有全局事务的概念)和一个应用程序(ApplicationProgram)组成。
分布式事务最经典的七种解决方案

第一阶段(prepare):即所有的参与者RM准备执行事务并锁住需要的资源。参与者ready时,向TM报告已准备就绪。
第二阶段 (commit/rollback):当事务管理者(TM)确认所有参与者(RM)都ready后,向所有参与者发送commit命令。

示意图

所以一个主事务或者全局事务它有多个子事务,一个子事务会代表一次账务的调用,比如说提现、充值、冻结、解冻等。在调用图中TransIn或者TransOut接口时,我们会先做一些前置校验,主要是一些参数与幂等的校验,然后在prepare阶段做一些资源的预留,将本次交易需要的资金资源先“冻”住,避免被其他请求占用。在事物的二阶段,我们会提交或者回滚。提交的话,我们会把一阶段冻结住的资源还原回去,干干净净地进行实际的余额扣减或者增加,会更新账户余额以及增加变更明细。回滚的话,我们把一阶段预留的资源进行释放并且也会落一个记录。

提到账务的事务处理,必然会提到性能问题。比较著名的就是热点账户的问题,为了账务数据的一致性,我们会经常地去锁住用户的账务数据,当这个用户是大用户或者是大机构时,他的账户上就会在短时间内有频繁的TransIn或者TransOut的操作。比如我们做放贷业务时,一些合作的大机构的授信客群特别多或者交易频率比较高,那么必然会出现热点账户问题。我作为账务系统的上游,看到过一、两次账务系统报错,比如说什么账号锁冲突之类的。为了解决热点账户问题,业界出现了主子账户、汇总记账、缓冲记账等解决方案。我一般接触比较多的是缓冲记账和汇总记账。

一些业务要是允许余额数据可以存在一定的不准确性,但是业务不能中断。我的下游系统主要会采用缓冲或者汇总记账的方式来解决。

缓冲记账主要是采用了“削峰填谷”的思路去做。所以我们会采取将实时的记账操作异步化的方式来解决。当账户的交易量超过实时处理阈值时,账户先返回成功标识给客户,把待处理的账务请求写入消息队列,待并发量不大时再从消息队列取记录做记账处理。

汇总记账的话就是先将外部的系统账务调用请求落库,定时的将某个时间段内的交易sum进行汇总,再将汇总的金额作用到账户余额上,减少与数据库的交互,避免出现数据库处理的瓶颈问题。

其他的一些热点账户节点方案可以查看
浅谈热点账户技术解决方案

有些业务会存在热点账户问题,但是它既要余额做到准实时又要不中断业务,也不能透支。这时候面对余额更新问题,我们引入了流式计算(flink)作为解决方案以及对于流出的账户设置一定的buffer水位底线,一旦低于某个设定的底线后将不能再流出,这样既可以做到余额的准实时也可以一定程度上的放透支。
数据除了需要保证实时性,还需要保证准确性和稳定性,所有还会建立双链路,进行核对互备的方式保证准确性与稳定性,其次应用层还可再加上缓存提高数据使用的稳定性。

一般来说,缓冲账户的准实时余额=账户T日日终的余额+实时的流入与流出。日终余额一般都是在账户日切之后的余额。

日切,通俗的来说就是更换系统记账的时间;系统从当前工作日切换到下一工作日,日切过程中交易可以照常提交并正确处理返回。

一般状态下,不会在过了日切点之后就日切完成的,账务是业务系统中相对底层的系统,如果他的上游出现了一些问题后,那么就会导致不能自动日切完成,就会“卡日切”,所以为了留有一些buffer处理的空间,我们会取用T-2日的日终余额+账户的实时流入与流出。

账户的实时流入与流出的计算就采用了flink技术。这种场景我们一般都是采用lambda架构,业界也有很多的处理方案可以查看。
美团外卖实时数仓建设实践

你可能感兴趣的:(账务相关小结)