ElasticJob分布式任务调度提效方案

94 阅读6分钟

业务背景

近期,由于运营对一款商品复制工具的大量使用,任务处理速度不尽人意,导致商品复制任务堆积。运营反馈,后续还有大量的商品复制任务需要创建,希望对该工具进行迭代改进,提升商品复制任务的执行效率。

我梳理了整体的业务流程如下图所示: image.png

  • 运营选择来源店铺A的商品数据,复制到到目标店铺B中;
  • 对应的数据库模型中会向【商品复制任务表】新增一条记录,向商品复制任务明细表中新增多条任务明细商品记录;
  • 后续通过ElasticJob定时任务捞取待执行的任务进行商品复制。

商品复制任务执行逻辑如下图所示: image.png

  • ElasticJob的配置为分片数为1,调度时间为每分钟执行一次,线上机器共2台;
  • 每次只有一台机器调度任务,每次处理一个商品复制任务,执行完任务下所有明细数据才完结当前复制任务,然后等待下次定时任务调度。

缩减调度时间间隔

减少调度间隔时间可以减少处理多个商品复制任务的总耗时。如下图所示,由每分钟调度一次修改为每10秒钟调度一次,10个任务的总耗时由9分钟5秒缩短到1分钟35秒。

image.png 具体的调度时间需要权衡下,如果一直没有待处理的商品复制任务,频繁的调度会造成系统资源的浪费。一种解决思路是当运营创建商品复制任务时,启用调度任务,当没有待处理的商品复制任务后,暂停调度任务。

多线程执行任务

存在多个待处理的商品复制任务时,同一时刻只能执行一个商品复制任务,串行执行效率还是慢。想要并行执行任务,一次查询可以获取多条商品复制任务,开多线程执行任务。这样ElasticJob每次调度在一台机器上,一次执行多条商品复制任务。 image.png 目前,只有一台机器利用上了,能不能让每台机器都执行任务调度呢?如果可以的话,那商品复制任务执行效率理论上又能提升很多倍。但是不同的机器获取到的商品复制任务都是一样的,会出现重复执行的问题,该如何分配不同的任务给对应的机器是一个棘手的问题,好在ElasticJob提供了分片功能。

ElasticJob多分片

使得ElasticJob任务可以在分布式的环境下运行,每台任务服务器只运行分配给该服务器的分片项。

ElasticJob默认使用的平均分片策略,根据分片项平均分片。如果作业服务器数量与分片总数无法整除,多余的分片将会顺序的分配至每一个作业服务器。

举例说明:

  1. 如果 3 台作业服务器且分片总数为8,则分片结果为:1=[0,1,6], 2=[2,3,7], 3=[4,5];
  1. 如果 3 台作业服务器且分片总数为9,则分片结果为:1=[0,1,2], 2=[3,4,5], 3=[6,7,8];
  1. 如果 3 台作业服务器且分片总数为10,则分片结果为:1=[0,1,2,9], 2=[3,4,5], 3=[6,7,8]。

设置分片总数后,每台机器获取到对应的分片项后,可以判断任务ID对分片总数取模是否等于当前分片项,逻辑上把商品复制任务数据对分片项进行了分散映射。 image.png

  • 设置分片总数为4,根据平均分片策略,机器1获取分片0、1,机器2获取分片2、3;
  • 运营创建了8次商品复制任务,任务ID依次为1到8,那么调度触发时处理的任务情况如上图所示。

但是,运营创建的商品复制任务中,任务明细的数据量有多有少,处理一条任务明细耗时约1秒,假设商品复制任务ID为1和2的任务明细数量只有1条,执行完商品复制任务耗时约1秒;商品复制任务ID为3和4的任务明细数量有10万条,执行完耗时约28个小时。期间大部分时间只会同时执行任务3和任务4,如下图所示:

image.png

因为ElasticJob分片调度触发的逻辑按照机器维度,存在分片处于进行中,将会跳过本次调度,后续将错过任务重执行。所以,将会出现长时间只有分片0和分片3长时间处理任务,浪费了分片1和分片2的资源。

任务拆分

造成分片资源浪费的主要原因就是商品复制任务大小不均,导致分片执行时间差异大。一种解决方案是控制每个分片调度时执行任务明细的数据量。例如分片每次调度时,只查询任务下1000个任务明细数据,执行完后结束任务,等待下次分片调度时,查询任务下第1001到2000的任务明细数据。等待分片多次调度后,可将商品复制任务下的所有明细数据处理完毕。 image.png

  • 这样,第一次调度执行1000个任务明细耗时约17分钟;
  • 第二次调度的时候就可以处理大任务3和4时,分片1和分片2加载新的商品复制任务5和6进行任务执行,极大的利用分片资源。

多线程执行任务明细

针对于同一商品复制任务,假设有10万条任务明细,从任务明细的角度来看是顺序执行的。如果在分片调度中,捞取一批2000个任务明细后,开启多个线程并发的执行商品创建接口,那么将极大的减少单次分片调度的耗时。 image.png

优化商品创建接口

底层具体的商品复制功能是调用商品中心团队的创建商品接口,所以针对于具体的商品创建接口的提效咱鞭长莫及,可以让产品给商品中心团队提需求。

如果单个商品创建接口耗时能够优化降下来,那么整体任务的处理时间也将大大减少。

总结

本文从多个维度来提升商品复制任务的执行效率:

  • 减少任务间的等待调度时间;
  • 使多个任务可以同时执行;
  • 通过ElasticJob分片让多台机器同时调度;
  • 通过任务拆分降低分片执行的时间差,提高分片利用率;
  • 通过多线程执行任务明细减少单个任务的总处理时间;
  • 通过优化商品创建接口减少单个商品的创建耗时;

需要注意的是,不要盲目增加分片数,多线程,需要观察下游商品中心系统的负载监控信息,平滑操作。