业务背景
近期,由于运营对一款商品复制工具的大量使用,任务处理速度不尽人意,导致商品复制任务堆积。运营反馈,后续还有大量的商品复制任务需要创建,希望对该工具进行迭代改进,提升商品复制任务的执行效率。
我梳理了整体的业务流程如下图所示:
- 运营选择来源店铺A的商品数据,复制到到目标店铺B中;
- 对应的数据库模型中会向【商品复制任务表】新增一条记录,向商品复制任务明细表中新增多条任务明细商品记录;
- 后续通过ElasticJob定时任务捞取待执行的任务进行商品复制。
商品复制任务执行逻辑如下图所示:
- ElasticJob的配置为分片数为1,调度时间为每分钟执行一次,线上机器共2台;
- 每次只有一台机器调度任务,每次处理一个商品复制任务,执行完任务下所有明细数据才完结当前复制任务,然后等待下次定时任务调度。
缩减调度时间间隔
减少调度间隔时间可以减少处理多个商品复制任务的总耗时。如下图所示,由每分钟调度一次修改为每10秒钟调度一次,10个任务的总耗时由9分钟5秒缩短到1分钟35秒。
具体的调度时间需要权衡下,如果一直没有待处理的商品复制任务,频繁的调度会造成系统资源的浪费。一种解决思路是当运营创建商品复制任务时,启用调度任务,当没有待处理的商品复制任务后,暂停调度任务。
多线程执行任务
存在多个待处理的商品复制任务时,同一时刻只能执行一个商品复制任务,串行执行效率还是慢。想要并行执行任务,一次查询可以获取多条商品复制任务,开多线程执行任务。这样ElasticJob每次调度在一台机器上,一次执行多条商品复制任务。
目前,只有一台机器利用上了,能不能让每台机器都执行任务调度呢?如果可以的话,那商品复制任务执行效率理论上又能提升很多倍。但是不同的机器获取到的商品复制任务都是一样的,会出现重复执行的问题,该如何分配不同的任务给对应的机器是一个棘手的问题,好在ElasticJob提供了分片功能。
ElasticJob多分片
使得ElasticJob任务可以在分布式的环境下运行,每台任务服务器只运行分配给该服务器的分片项。
ElasticJob默认使用的平均分片策略,根据分片项平均分片。如果作业服务器数量与分片总数无法整除,多余的分片将会顺序的分配至每一个作业服务器。
举例说明:
- 如果 3 台作业服务器且分片总数为8,则分片结果为:1=[0,1,6], 2=[2,3,7], 3=[4,5];
- 如果 3 台作业服务器且分片总数为9,则分片结果为:1=[0,1,2], 2=[3,4,5], 3=[6,7,8];
- 如果 3 台作业服务器且分片总数为10,则分片结果为:1=[0,1,2,9], 2=[3,4,5], 3=[6,7,8]。
设置分片总数后,每台机器获取到对应的分片项后,可以判断任务ID对分片总数取模是否等于当前分片项,逻辑上把商品复制任务数据对分片项进行了分散映射。
- 设置分片总数为4,根据平均分片策略,机器1获取分片0、1,机器2获取分片2、3;
- 运营创建了8次商品复制任务,任务ID依次为1到8,那么调度触发时处理的任务情况如上图所示。
但是,运营创建的商品复制任务中,任务明细的数据量有多有少,处理一条任务明细耗时约1秒,假设商品复制任务ID为1和2的任务明细数量只有1条,执行完商品复制任务耗时约1秒;商品复制任务ID为3和4的任务明细数量有10万条,执行完耗时约28个小时。期间大部分时间只会同时执行任务3和任务4,如下图所示:
因为ElasticJob分片调度触发的逻辑按照机器维度,存在分片处于进行中,将会跳过本次调度,后续将错过任务重执行。所以,将会出现长时间只有分片0和分片3长时间处理任务,浪费了分片1和分片2的资源。
任务拆分
造成分片资源浪费的主要原因就是商品复制任务大小不均,导致分片执行时间差异大。一种解决方案是控制每个分片调度时执行任务明细的数据量。例如分片每次调度时,只查询任务下1000个任务明细数据,执行完后结束任务,等待下次分片调度时,查询任务下第1001到2000的任务明细数据。等待分片多次调度后,可将商品复制任务下的所有明细数据处理完毕。
- 这样,第一次调度执行1000个任务明细耗时约17分钟;
- 第二次调度的时候就可以处理大任务3和4时,分片1和分片2加载新的商品复制任务5和6进行任务执行,极大的利用分片资源。
多线程执行任务明细
针对于同一商品复制任务,假设有10万条任务明细,从任务明细的角度来看是顺序执行的。如果在分片调度中,捞取一批2000个任务明细后,开启多个线程并发的执行商品创建接口,那么将极大的减少单次分片调度的耗时。
优化商品创建接口
底层具体的商品复制功能是调用商品中心团队的创建商品接口,所以针对于具体的商品创建接口的提效咱鞭长莫及,可以让产品给商品中心团队提需求。
如果单个商品创建接口耗时能够优化降下来,那么整体任务的处理时间也将大大减少。
总结
本文从多个维度来提升商品复制任务的执行效率:
- 减少任务间的等待调度时间;
- 使多个任务可以同时执行;
- 通过ElasticJob分片让多台机器同时调度;
- 通过任务拆分降低分片执行的时间差,提高分片利用率;
- 通过多线程执行任务明细减少单个任务的总处理时间;
- 通过优化商品创建接口减少单个商品的创建耗时;
需要注意的是,不要盲目增加分片数,多线程,需要观察下游商品中心系统的负载监控信息,平滑操作。