第20节 大批量任务处理常见的方案(模拟余额宝发放收益)
场景
假如余额宝每天发放收益的功能让咱们来实现,用户量有1个亿,每天早上9点之前需要将发放完毕,咱们会采用什么方案呢?
下面我们会采用2种方法来实现,以后遇到同类问题的时候,大家可以作为参考。
先分析一下需求。
需求分析
- 这用户量相当大,有1个亿
- 当天的收益要在 9 点之前发放完毕,也就是说,如果从零点开始执行,中间有 9 个小时来处理这个业务
- 用户的收益不能出现重复发送的情况
- 对于每天发放的结果需要进行汇报(发放人数、成功人数、失败人数、还未发放的人数、总金额)
- 最好有个后台可以看到这些统计信息,并支持对失败的进行手动补偿
方案1:使用job+线程池去跑
原理如下,主要4步
step1:拉取待处理的数据,比如拉取10000条记录
step2:交给线程池去去处理,比如线程池的大小是100
step3:等待step2中的批处理结束
step4:回到step1,继续拉取用户进行处理,如果step1中发现已经没有用户需要处理了,则直接退出。
这个方法有没有问题?
我们假设每次发放收益需要耗时1秒,我们来算一下,1亿用户跑完需要多久
1亿/100个线程/24小时/每小时是3600秒 = 100000000/100/24/3600 = 如下 ≈ 11.57 天左右。

这个结果完全是无法接受的,那么有些朋友说可以将100个线程开到1000个,但是这样也需要1.15天啊,也无法满足需求
有些同学说,可以将线程池开到1万个,那么就只需要0.115天了,大家可以试试,单台机器跑1万个线程,会是什么个情况,大多数机器都是扛不住的,即使能抗住,数据库也是扛不住的。
如果用户量比较少,比如100万以内的用户,用这种方式可以搞定。
有没有更好的办法?
一台机器搞不定这个问题,那么我们可以搞个100台机器,目前使用云来扩展机器还是很容易的。
如果换成100台机器来同时干这个事情,每个机器负责跑100万用户,这个问题就解决了。
但是如何让100台机器同时来干这个事情呢?看方案2
方案2:使用集群+MQ来解决
需要有一台机器来分发任务,将1个亿的用户转换成1亿条消息丢到MQ中,然后下面有100台机器从MQ中拉取这些消息去消费。
需要有个job来做任务分发
job从db中分多批拉出1亿用户,每个用户生成一条MQ消息,投递到MQ中,差不多1个亿的消息。
如果这里感觉消息太多,那么一条消息中也可以放10个或者100个用户。
这里投递MQ消息也可以使用线程池来进行投递,提升速度。
MQ消费者集群
这里我们会将发放收益的服务,部署100个,每个服务中开100个消费者从MQ中拉取消息,相当于同时有10000个消费者同时消费消息。
这种方式耗时多久?我们来估算下
1、发送1亿条消息,预估0.5小时
2、1 亿条消息,交给1万个消费者,这样每个消费者消费1万个,每个耗时1秒,也就是1万秒 = 3小时左右
预计耗时 3.5 个小时,达到了预期。
开头说的还有一些需求我们没有考虑到
收益不能重复发送,这个如何解决?
也就是发送的逻辑需要幂等,对谁做幂等?(userId+当天的日期),即每个用户当天不能重发。
幂等的解决方案,可以看第12节,我们已经讲过,里面提供了4种方案,并提供了源码,大家随意挑选。
还有个需求:对于每天发放的结果需要进行汇报(发放人数、成功人数、失败人数、还未发放的人数)
这个如何搞呢?
可以创建一张收益发放记录表(t_user_profit),字段如下,通过这个表就可以统计到上面要的信息
- userId:用户id
- day:发放日期,格式:YYYYMMDD,比如:20240414
- status:状态,0:未发放,1:已发放,2:发放失败
- fail_reason:发放失败的原因
- create_time:创建时间
那这个表如何使用呢?
在job中分发MQ消息的时候,同时向这个表中插入对应的记录,也就是每天要写入1亿条记录,这个地方可能有性能瓶颈,建议压测下。
如果感觉太慢,可以分表,按天分表,每天一张表,这样这个表就只有一个亿的数据了。
如果还是感觉慢,分表字段可以使用:日期+userId,每个日期开100个表,然后根据userId再进行路由。
发放逻辑中需要调整下
收益发放成功修改这条记录的状态
收益发放失败也需要修改状态,并记录失败原因
发放逻辑可以考虑失败做一些重试
发放的逻辑中,对于失败的情况,可以稍微休眠会,然后重试,比如重试3次,这样可最大程度使其成功。
提供一个运营后台
最好能够提供一个后台,看到每天发放的情况,如(发放人数、成功人数、失败人数、还未发放的人数、总金额等)
对于发放失败的,支持手动点击按钮进行重试。
总结
这节课给大家分享了,大批量任务的2个方案,任务比较少的时候,如果一台机器可以搞定,可以使用方案1
如果任务量比较大,可以使用MQ来分发任务,配合集群消费,这样便可以解决这种问题。
以后遇到这种问题后,大家可以按照这个思路来解决。
核心原理:任务太多,一个人搞不定的事情,招人,就让多个人来干,领导分发任务,或者大家自己去领任务。