Elasticjob在同一个实例上运行的多个分片任务

 一、#创作灵感#

elasticjob在同一个实例上运行的多个分片任务(实例数量小于分片数量)

  1. 很多贴子、AI说可以
  2. 实际不可以,很可能是官方说明翻译时出现了误差
  3. 每个分片由一个独立的作业服务器执行,可以同时处理多个分片,实现作业的并行执行(同时、并行都是指不同的服务器/实例之间并行)
  4. 网上的文章在部分没有写明代码对应的elasticjob版本,导致可读性差就成了鸡肋

需求:作业需要分多片,但不不想启动太多pod/实例

方案:当然这是有解决方案的。本文作者分享编程、配置两种实现方案

二、环境

- SpringBoot 2.7.18   官方下载地址:SpringBoot 2.7.18

- ElasticJob 3.0.4   官方下载地址:ElasticJob 3.0.4

- ElasticJob-UI 3.0.2 图形化工具  官方下载地址:ElasticJob-UI 3.0.2

- Nacos 2.2.3   官方下载地址:Nacos 2.2.3

- Oracle JDK8u202(Oracle JDK8最后一个非商业版本)   下载地址:Oracle JDK8u202

三、方案一(编码方式)

1、使用不同的Job名称

为每个任务定义不同的Job名称。虽然这不一定直接解决在同一实例上运行多个分片的问题,但它可以帮助你更清晰地管理和识别不同的任务。

高版本(ElasticJob 3.0.4+)

    /**
     * 作业配置1
     * @return
     */
    @Bean(name="myJob1")
    public JobConfiguration jobConfiguration1() {

        return JobConfiguration.newBuilder("myJob1", 2 )
                .shardingItemParameters("0=Beijing,1=Shanghai")
                .jobParameter("param=value")
                .build();
    }

    /**
     * 作业配置2
     * @return
     */
    @Bean(name="myJob2")
    public JobConfiguration jobConfiguration2() {

        return JobConfiguration.newBuilder("myJob2", 2 )
                .shardingItemParameters("0=Beijing,1=Shanghai")
                .jobParameter("param=value")
                .build();
    }

低版本

// 第一个任务
SimpleJobConfiguration firstJobConfig = SimpleJobConfiguration.newBuilder(MyJob.class)
        .cron(cron1)
        .shardingTotalCount(2)
        .jobParameter("param1")
        .build();
 
// 第二个任务
SimpleJobConfiguration secondJobConfig = SimpleJobConfiguration.newBuilder(MyJob.class)
        .cron(cron2)
        .shardingTotalCount(2)
        .jobParameter("param2")
        .build();

2、配置多个分片在同一JVM中执行

在ElasticJob中,你可以通过配置JobBootstrap来指定在一个JVM进程中运行多个分片。这通常通过在JobBootstrap中配置多个SimpleJobConfiguration对象实现。

高版本(ElasticJob 3.0.4+)


    private void init(){
        
        ZookeeperRegistryCenter regCenter = new ZookeeperRegistryCenter(
                new ZookeeperConfiguration("localhost:2181", "elastic_job_demo")
        );
        regCenter.init();

        JobConfiguration cfg1 = JobConfiguration.newBuilder("saasHealthJob1", 2 )
                .shardingItemParameters("0=A:01,1=B:01")
                .jobParameter("param=value1")
                .build();

        JobScheduler jobScheduler1 = new JobScheduler( regCenter, myJob, cfg1 );
        jobScheduler1.getJobScheduleController().scheduleJob("0 0/1 * * * ?","GMT+8:00");


        JobConfiguration cfg2 = JobConfiguration.newBuilder("saasHealthJob2", 2 )
                .shardingItemParameters("0=A:02,1=B:02")
                .jobParameter("param=value2")
                .build();

        JobScheduler jobScheduler2 = new JobScheduler( regCenter, myJob, cfg2 );
        jobScheduler2.getJobScheduleController().scheduleJob("0 0/1 * * * ?","GMT+8:00");

    }

低版本

List<SimpleJobConfiguration> jobConfigurations = new ArrayList<>();
jobConfigurations.add(firstJobConfig);
jobConfigurations.add(secondJobConfig);
 
JobBootstrap.getInstance().setJobConfigNames("firstJobConfig", "secondJobConfig").initialize();

3、示例代码整合 

下面是一个整合上述配置的示例:

高版本示例(ElasticJob 3.0.4+)

import org.apache.shardingsphere.elasticjob.api.JobConfiguration;
import org.apache.shardingsphere.elasticjob.lite.internal.schedule.JobScheduler;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description: java代码创建elasticjob作业
 *               针对3个按资源池和集群分片的job(有6片),为了不用启6个实例,实现6个分片在两个实例上并行执行
 * @Author: dand
 * @CreateDate: 2025/2/13 09:20
 * @Version: 1.0
 */
@Configuration
public class ElasticJobConfig {

    @Autowired
    MyJob myJob;

    private void init(){

        ZookeeperRegistryCenter regCenter = new ZookeeperRegistryCenter(
                new ZookeeperConfiguration("localhost:2181", "elastic_job_demo")
        );
        regCenter.init();

        JobConfiguration cfg1 = JobConfiguration.newBuilder("myJob1", 2 )
                .shardingItemParameters("0=A:01,1=B:01")
                .jobParameter("param=value1")
                .build();

        JobScheduler jobScheduler1 = new JobScheduler( regCenter, myJob, cfg1 );
        jobScheduler1.getJobScheduleController().scheduleJob("0 0/1 * * * ?","GMT+8:00");


        JobConfiguration cfg2 = JobConfiguration.newBuilder("myJob2", 2 )
                .shardingItemParameters("0=A:02,1=B:02")
                .jobParameter("param=value2")
                .build();

        JobScheduler jobScheduler2 = new JobScheduler( regCenter, myJob, cfg2 );
        jobScheduler2.getJobScheduleController().scheduleJob("0 0/1 * * * ?","GMT+8:00");

    }

//    /**
//     * 配置注册中心(这里使用 Zookeeper)
//     * @return
//     */
//    @Bean
//    public ZookeeperRegistryCenter registryCenter() {
//        ZookeeperConfiguration zkConfig = new ZookeeperConfiguration("localhost:2181", "my-elastic-job");
//        ZookeeperRegistryCenter regCenter = new ZookeeperRegistryCenter(zkConfig);
//        regCenter.init();
//        return regCenter;
//    }
//
//    /**
//     * 作业配置1
//     * @return
//     */
//    @Bean(name="myJob1")
//    public JobConfiguration jobConfiguration1() {
//
//        return JobConfiguration.newBuilder("myJob1", 2 )
//                .shardingItemParameters("0=Beijing,1=Shanghai")
//                .jobParameter("param=value")
//                .build();
//    }
//
//    /**
//     * 作业配置2
//     * @return
//     */
//    @Bean(name="myJob2")
//    public JobConfiguration jobConfiguration2() {
//
//        return JobConfiguration.newBuilder("myJob2", 2 )
//                .shardingItemParameters("0=Beijing,1=Shanghai")
//                .jobParameter("param=value")
//                .build();
//    }
}

高版本示例(ElasticJob 3.0.4+)如果已经有配置方式的其他job

如果已经有配置方式的其他job,就自然有了ZookeeperRegistryCenter,不需要再对其创建和初始化,直接注入

import org.apache.shardingsphere.elasticjob.api.JobConfiguration;
import org.apache.shardingsphere.elasticjob.lite.internal.schedule.JobScheduler;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;
import org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description: java代码创建elasticjob作业
 *               针对3个按资源池和集群分片的job(有6片),为了不用启6个实例,实现6个分片在两个实例上并行执行
 * @Author: dand
 * @CreateDate: 2025/2/13 09:20
 * @Version: 1.0
 */
@Configuration
public class ElasticJobConfig {

    @Autowired
    ZookeeperRegistryCenter regCenter;

    @Autowired
    MyJob myJob;

    private void init(){

        JobConfiguration cfg1 = JobConfiguration.newBuilder("myJob1", 2 )
                .shardingItemParameters("0=A:01,1=B:01")
                .jobParameter("param=value1")
                .build();

        JobScheduler jobScheduler1 = new JobScheduler( regCenter, myJob, cfg1 );
        jobScheduler1.getJobScheduleController().scheduleJob("0 0/1 * * * ?","GMT+8:00");


        JobConfiguration cfg2 = JobConfiguration.newBuilder("myJob2", 2 )
                .shardingItemParameters("0=A:02,1=B:02")
                .jobParameter("param=value2")
                .build();

        JobScheduler jobScheduler2 = new JobScheduler( regCenter, myJob, cfg2 );
        jobScheduler2.getJobScheduleController().scheduleJob("0 0/1 * * * ?","GMT+8:00");

    }
}

低版本示例

public class ElasticJobApplication {
    public static void main(String[] args) {
        SimpleJobConfiguration firstJobConfig = SimpleJobConfiguration.newBuilder(MyJob.class)
                .cron("0/5 * * * * ?") // 每5秒执行一次
                .shardingTotalCount(2) // 分片总数为2
                .jobParameter("param1") // 参数设置
                .build();
        
        SimpleJobConfiguration secondJobConfig = SimpleJobConfiguration.newBuilder(MyJob.class)
                .cron("0/10 * * * * ?") // 每10秒执行一次
                .shardingTotalCount(2) // 分片总数为2
                .jobParameter("param2") // 参数设置
                .build();
        
        List<SimpleJobConfiguration> jobConfigurations = new ArrayList<>();
        jobConfigurations.add(firstJobConfig);
        jobConfigurations.add(secondJobConfig);
        
        JobBootstrap.getInstance().setJobConfigurations(jobConfigurations).initialize();
    }
}

通过以上设置,你可以在同一实例上高效地运行多个分片任务。

四、方案二(配置方式)【推荐】

1、配置方式实现

下面的方式编码更少,上面的方式配置更少(没有配置)

# job1
elasticjob.jobs.ESLoadJob1.elasticJobClass=person.dand.job.MyJob
elasticjob.jobs.ESLoadJob1.shardingTotalCount=2
elasticjob.jobs.ESLoadJob1.sharding-item-parameters=0=A
elasticjob.jobs.ESLoadJob1.jobErrorHandlerType=LOG
elasticjob.jobs.ESLoadJob1.cron=0 0/1 * * * ?
elasticjob.jobs.ESLoadJob1.jobExecutorServiceHandlerType=SINGLE_THREAD
elasticjob.jobs.ESLoadJob1.misfire=false
elasticjob.jobs.ESLoadJob1.failover=false
elasticjob.jobs.ESLoadJob1.disabled=false
elasticjob.jobs.ESLoadJob1.overwrite=true
elasticjob.jobs.ESLoadJob1.description=XXXX任务1

# job2
elasticjob.jobs.ESLoadJob2.elasticJobClass=person.dand.job.MyJob
elasticjob.jobs.ESLoadJob2.shardingTotalCount=2
elasticjob.jobs.ESLoadJob2.sharding-item-parameters=1=B
elasticjob.jobs.ESLoadJob2.jobErrorHandlerType=LOG
elasticjob.jobs.ESLoadJob2.cron=0 0/1 * * * ?
elasticjob.jobs.ESLoadJob2.jobExecutorServiceHandlerType=SINGLE_THREAD
elasticjob.jobs.ESLoadJob2.misfire=false
elasticjob.jobs.ESLoadJob2.failover=false
elasticjob.jobs.ESLoadJob2.disabled=false
elasticjob.jobs.ESLoadJob2.overwrite=true
elasticjob.jobs.ESLoadJob2.description=XXXX任务2

五、注意事项

  • 资源管理:在同一实例上运行多个分片任务可能会增加资源使用(如CPU、内存等),确保你的服务器硬件能够支持这种配置。

  • 任务隔离:尽管ElasticJob允许在同一JVM中运行多个任务,但在设计时应确保各个任务之间不会互相干扰,例如通过合理的日志记录、资源锁定等措施。

  • 监控与日志:由于多个任务可能同时运行,确保有适当的监控和日志记录机制来跟踪每个任务的执行情况。

  • 配置管理:合理管理配置文件,确保每个任务的配置(如分片数量、执行策略等)正确无误。

特别提醒

作业配置项:sharding-item-parameters  必须以0开头,不能大于等于分片 shardingTotalCount

六、两种方案对比

1、配置方式编码更少

2、编程方式配置更少(没有配置)

相关文章推荐:

多数据源SpringBoot应用集成ElasticJob3.0.4并实现作业事件追踪【最佳实践】_elastic job 3.-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞火流星02027

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值