💖分布式任务调度有那么难吗?来,10分钟带你实战💖

举报
XiaoLin_Java 发表于 2022/02/22 15:15:54 2022/02/22
【摘要】 一、概述 1.1、什么是任务调度我们可以思考一下下面业务场景的解决方案:某电商平台需要每天上午10点,下午3点,晚上8点发放一批优惠券某银行系统需要在信用卡到期还款日的前三天进行短信提醒某财务系统需要在每天凌晨0:10分结算前一天的财务数据,统计汇总以上场景就是任务调度所需要解决的问题,任务调度是为了自动完成特定任务,在约定的特定时刻去执行任务的过程。在Spring中也提供了定时任务注解@...

一、概述

1.1、什么是任务调度

我们可以思考一下下面业务场景的解决方案:

  • 某电商平台需要每天上午10点,下午3点,晚上8点发放一批优惠券
  • 某银行系统需要在信用卡到期还款日的前三天进行短信提醒
  • 某财务系统需要在每天凌晨0:10分结算前一天的财务数据,统计汇总

以上场景就是任务调度所需要解决的问题,任务调度是为了自动完成特定任务,在约定的特定时刻去执行任务的过程

在Spring中也提供了定时任务注解@Scheduled。我们只需要在业务中贴上注解然后在启动类上贴上@EnableScheduling注解即可完成任务调度功能。

@Scheduled(cron = "0/20 * * * * ? ") // 每隔20秒执行一次
 public void doWork(){
 	//doSomething   
 }

1.2、分布式调度出现

感觉Spring给我们提供的这个注解可以完成任务调度的功能,好像已经完美解决问题了,为什么还需要分布式呢?主要的原因有以下几点:

  1. 机处理极限:原本1分钟内需要处理1万个订单,但是现在需要1分钟内处理10万个订单;原来一个统计需要1小时,现在业务方需要10分钟就统计出来。你也许会说,你也可以多线程、单机多进程处理。的确,多线程并行处理可以提高单位时间的处理效率,但是单机能力毕竟有限(主要是CPU、内存和磁盘),始终会有单机处理不过来的情况。
  2. 高可用:单机版的定式任务调度只能在一台机器上运行,如果程序或者系统出现异常就会导致功能不可用。虽然可以在单机程序实现的足够稳定,但始终有机会遇到非程序引起的故障,而这个对于一个系统的核心功能来说是不可接受的。
  3. 防止重复执行: 在单机模式下,定时任务是没什么问题的。但当我们部署了多台服务,同时又每台服务又有定时任务时,若不进行合理的控制在同一时间,只有一个定时任务启动执行,这时,定时执行的结果就可能存在混乱和错误了。

1.3、Elastic-Job

Elastic-Job是一个分布式调度的解决方案,由当当网开源,它由两个相互独立的子项目Elastic-job-Lite和Elastic-Job-Cloud组成,使用Elastic-Job可以快速实现分布式任务调度。Elastic-Job的github地址。他的功能主要是:

  • 分布式调度协调

    在分布式环境中,任务能够按照指定的调度策略执行,并且能够避免同一任务多实例重复执行。

  • 丰富的调度策略:

    基于成熟的定时任务作业框架Quartz cron表达式执行定时任务。

  • 弹性拓容缩容

    当集群中增加一个实例,它应当能够被选举被执行任务;当集群减少一个实例时,他所执行的任务能被转移到别的示例中执行。

  • 失效转移

    某示例在任务执行失败后,会被转移到其他实例执行。

  • 错过执行任务重触发

    若因某种原因导致作业错过执行,自动记录错误执行的作业,并在下次次作业完成后自动触发。

  • 支持并行调度

    支持任务分片,任务分片是指将一个任务分成多个小任务在多个实例同时执行。

  • 作业分片一致性

    当任务被分片后,保证同一分片在分布式环境中仅一个执行实例。

  • 支持作业生命周期操作

    可以动态对任务进行开启及停止操作。

  • 丰富的作业类型

    支持Simple、DataFlow、Script三种作业类型

Elastic-Job架构图

1.4、启动zookeeper

  1. 解压包
  2. 到conf目录中把oo_sample.cfg 拷贝一份 , 修改名字为zoo.cfg。
  3. 到bin目录中启动startup.cmd文件(用1命令行启动)。

1.4、启动zookeeper图形化界面

  1. 解压。
  2. 到1build目录中,找到jar包。
  3. 使用命令:java -jar jar包的名字

二、Elastic-Job快速入门

Elastic-Job的1环境要求:

  • JDK 要求1.7以上保本
  • Maven 要求3.0.4及以上版本
  • Zookeeper 要求采取3.4.6以上版本

2.1、环境搭建

安装运行zookeeper

创建一个maven项目并导入依赖

<dependency>
    <groupId>com.dangdang</groupId>
    <artifactId>elastic-job-lite-core</artifactId>
    <version>2.1.5</version>
</dependency>

写任务类

public class XiaoLinJob implements SimpleJob {

  // 写任务类
  @Override
  public void execute(ShardingContext shardingContext) {
    System.out.println("定时任务开始");
  }
}

编写配置类

public class JobDemo {

  public static void main(String[] args) {
    new JobScheduler(createRegistryCenter(), createJobConfiguration()).init();
  }
  private static CoordinatorRegistryCenter createRegistryCenter() {
    //配置zk地址,调度任务的组名
    ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("127.0.0.1:2181", "elastic-job-demo");
    zookeeperConfiguration.setSessionTimeoutMilliseconds(1000);
    CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
    regCenter.init();
    return regCenter;
  }

  private static LiteJobConfiguration createJobConfiguration() {
    // 定义作业核心配置
    JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder("demoSimpleJob","0/1 * * * * ?",1).build();
    // 定义SIMPLE类型配置
    SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, XiaoLinJob.class.getCanonicalName());
    // 定义Lite作业根配置
    LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();
    return simpleJobRootConfig;
  }
}

2.2、测试

  1. 当只有一台启动的时候,按照corn表达式进行任务调度。
  2. 开启两台机器的1时候,新开的一台会继续执行定时任务,旧的1那一台会停止。

三、SpringBoot集成Elastic-Job

3.1、引入依赖

 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>com.dangdang</groupId>
      <artifactId>elastic-job-lite-spring</artifactId>
      <version>2.1.5</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>

3.2、编写配置文件

application.yaml

因为配置中心的地址不是固定的,所以我们不能写死在代码中,需要把他写在配置文件中。新建一个配置文件:

elasticjob:
  zookeeper-url: localhost:2181
  group-name: elastic-job-group

zookeeper注册中心配置类

// 注册中心的配置类
@Configuration
public class RegistryCenterConfig {

  @Bean(initMethod = "init")
                                                         // 从配置文件中获取注册中心的的url和命名空间
  public CoordinatorRegistryCenter coordinatorRegistryCenter(
      									@Value("${elasticjob.zookeeper-url}") String zookeeperUrl,
                                            @Value("${elasticjob.group-name}") String namespace){
    // zk的配置
    ZookeeperConfiguration zookeeperConfiguration =
        new ZookeeperConfiguration(zookeeperUrl,namespace);
    // 设置超时时间
    zookeeperConfiguration.setMaxSleepTimeMilliseconds(10000000);
    // 创建注册中心
    ZookeeperRegistryCenter zookeeperRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
    return zookeeperRegistryCenter;
  }
}

任务调度的配置类

@Configuration
public class JobConfig {

  @Autowired
  XiaoLinJob xiaoLinJob;

  @Autowired
  private CoordinatorRegistryCenter registryCenter;
  private static LiteJobConfiguration createJobConfiguration(
      								final Class<? extends SimpleJob> jobClass, // 任务的名字
                                       final String cron, // cron表达式
                                       final int shardingTotalCount, // 分片的数量
                                       final String shardingItemParameters // 分片类信奉的参数
                                                                                                  ){
    JobCoreConfiguration.Builder jobCoreConfigurationBuilder = JobCoreConfiguration.newBuilder(jobClass.getSimpleName(),cron,shardingTotalCount);
    if(!StringUtils.isEmpty(shardingItemParameters)){
      jobCoreConfigurationBuilder.shardingItemParameters(shardingItemParameters);
    }
    SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(jobCoreConfigurationBuilder.build(), XiaoLinJob.class.getCanonicalName());
    LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).overwrite(true).build();
    return simpleJobRootConfig;

  }
  @Bean(initMethod = "init")
  public SpringJobScheduler initSimpleElasticJob(){
    SpringJobScheduler springJobScheduler = new SpringJobScheduler(xiaoLinJob,registryCenter,createJobConfiguration(XiaoLinJob.class,"0/3 * * * * ?",1,null));
    return springJobScheduler;
  }

}

自定义任务类

@Component
public class XiaoLinJob implements SimpleJob {

  @Override
  public void execute(ShardingContext shardingContext) {
    System.out.println("============");
  }
}

3.3、测试

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。