
金融系统中,常常会充值和提现两个功能,因为涉及到钱的变动,所以又特别重要。那么针对这个提现功能,你有什么好的方案呢?有什么样的方案能够保证系统的可靠性呢?
针对提现这个功能,可以使用同步的方式,也可以使用异步的方式。
同步:发起提现,系统接受到请求,一直处理到有结果。(转账成功/转账失败)
异步:先接收转账请求,直接告诉用户请求已经提交。等待处理有结果后,给用户发送消息。
现在我们在手机上发起提现都是异步的方式。为什么会用这种方式呢?原因有下:
1.对用户友好。用户无需实时等待处理的结果,只需要被动的接收消息即可。
2.对系统友好。异步的处理方式,可以让系统的接受请求和处理请求进行逻辑剥离,系统的吞吐量会有很大的提升。而且处理的逻辑可以有很大的可操作空间。
异步处理,很多人第一反应一定是MQ。异步,解耦,削峰填谷这是MQ的三大有点。
提现逻辑整体流程设计:
提现功能异步处理主要分成两部分:
1.接收提现请求部分
这一块的代码主要有一个获取token的接口,通过这个token,来确保接口的幂等性,保证同一个token只能发起一次提现操作,这也是确保转账接口的准确的第一层保障。
可以通过redis缓存来做接口的幂等。在接口中先用UUID生成一个Token,然后将
处理完发起转账接口的幂等性后,将转账信息转换为一条消息发送到MQ中,因为MQ是一个队列,所以天然的会将所有的请求进行入队操作,消息就有了顺序。
2.处理提现消息部分
通过单线程的方式处理队列的消息,那么就保障了无并发的问题带来的代码层面实现的复杂程度。
当完成了用户转账操作后,进行异步的通知(下发短信,发送邮件,推送消息等),最后需要在消息处理完毕之后手动ACK确认消息,这样就保障了消息的消费的原子性。
拓展:
有小伙伴可能觉得我这样设计的吞吐并不大,因为毕竟只有一个队列一个消费者。不要忘了,假如吞吐上来了,我们可以通过一些入队的手段,将队列横向拓展,比如根据用户的ID取模,将队列变成5个,使用5个线程去处理这不同的五个队列,那么吞吐量就提升了5倍,但是处理逻辑依旧是简单的,依旧可以简单的单线程消费模型(处理逻辑简单)去满足当前的业务。
单线程是处理并发问题的好帮手,会让代码实现的复杂度下降,会让整个处理逻辑简单,高效。并不是高并发场景就一定要使用JUC,分布式锁,这一类的技术。针对于具体的业务,简单,适用的方案设计会比臆想出来的落地方案好太多,希望大家在生活工作中多思考,多领悟。才能成为一个优秀的代码贡献者,而不是码农。
小知识:银行的实时转账其实都不是实时的,因为银行都是在凌晨12点进行对账,会将所有的交易进行核对(对账)后,确保借贷相平,才能真正的进行转账。所谓的实时转账,只不过银行有一个账户先将钱垫付,才能实现实时到账。