zoukankan      html  css  js  c++  java
  • 【学习】023 分布式任务调度平台

    什么是定时任务

     指定时间去执行任务

    Java实现定时任务方式

    Thread

    package com.hongmoshui.thread;
    
    public class Demo01
    {
        static long count = 0;
    
        public static void main(String[] args)
        {
            Runnable runnable = new Runnable()
            {
                public void run()
                {
                    while (true)
                    {
                        try
                        {
                            Thread.sleep(1000);
                            count++;
                            System.out.println(count);
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
        }
    }

    TimerTask

    package com.hongmoshui.TimerTask;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /**
     * 使用TimerTask类实现定时任务
     */
    public class Demo02
    {
        static long count = 0;
    
        public static void main(String[] args)
        {
            TimerTask timerTask = new TimerTask()
            {
    
                @Override
                public void run()
                {
                    count++;
                    System.out.println(count);
                }
            };
            Timer timer = new Timer();
            // 天数
            long delay = 0;
            // 秒数
            long period = 1000;
            timer.scheduleAtFixedRate(timerTask, delay, period);
        }
    
    }

    ScheduledExecutorService

    使用ScheduledExecutorService是从Java

    JavaSE5的java.util.concurrent里,做为并发工具类被引进的,这是最理想的定时任务实现方式。

    package com.hongmoshui.scheduled;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class Demo003
    {
        public static void main(String[] args)
        {
            Runnable runnable = new Runnable()
            {
                public void run()
                {
                    // task to run goes here
                    System.out.println("Hello !!");
                }
            };
            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
            service.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);
        }
    }

    Quartz

    创建一个quartz_demo项目

    引入maven依赖

        <dependencies>
            <!-- quartz -->
            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz</artifactId>
                <version>2.2.1</version>
            </dependency>
            <dependency>
                <groupId>org.quartz-scheduler</groupId>
                <artifactId>quartz-jobs</artifactId>
                <version>2.2.1</version>
            </dependency>
        </dependencies>

    任务调度类

    package com.hongmoshui.quartz;
    import java.util.Date;
    import org.quartz.Job;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    
    public class MyJob implements Job
    {
    
        public void execute(JobExecutionContext context) throws JobExecutionException
        {
            System.out.println("quartz MyJob date:" + new Date().getTime());
        }
    
    }

    启动类

    package com.hongmoshui;
    import java.util.Date;
    import org.quartz.CronScheduleBuilder;
    import org.quartz.JobBuilder;
    import org.quartz.JobDetail;
    import org.quartz.Scheduler;
    import org.quartz.SchedulerException;
    import org.quartz.SchedulerFactory;
    import org.quartz.Trigger;
    import org.quartz.TriggerBuilder;
    import org.quartz.impl.StdSchedulerFactory;
    import com.hongmoshui.quartz.MyJob;
    
    public class QuartzStart
    {
        public static void main(String[] args) throws SchedulerException
        {
            // 1.创建Scheduler的工厂
            SchedulerFactory sf = new StdSchedulerFactory();
            // 2.从工厂中获取调度器实例
            Scheduler scheduler = sf.getScheduler();
            // 3.创建JobDetail
            JobDetail jb = JobBuilder.newJob(MyJob.class).withDescription("this is a ram job") // job的描述
                    .withIdentity("ramJob", "ramGroup") // job
                                                        // 的name和group
                    .build();
            // 任务运行的时间,SimpleSchedle类型触发器有效
            long time = System.currentTimeMillis() + 3 * 1000L; // 3秒后启动任务
            Date statTime = new Date(time);
            // 4.创建Trigger
            // 使用SimpleScheduleBuilder或者CronScheduleBuilder
            Trigger t = TriggerBuilder.newTrigger().withDescription("").withIdentity("ramTrigger", "ramTriggerGroup")
                    // .withSchedule(SimpleScheduleBuilder.simpleSchedule())
                    .startAt(statTime) // 默认当前时间启动
                    .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")) // 两秒执行一次
                    .build();
            // 5.注册任务和定时器
            scheduler.scheduleJob(jb, t);
            // 6.启动 调度器
            scheduler.start();
    
        }
    }

    Quartz表达式

    http://cron.qqe2.com/

    分布式情况下定时任务会出现哪些问题?

    分布式集群的情况下,怎么保证定时任务不被重复执行

    分布式定时任务解决方案

    ①使用zookeeper实现分布式锁 缺点(需要创建临时节点、和事件通知不易于扩展)

    ②使用配置文件做一个开关  缺点发布后,需要重启

    ③数据库唯一约束,缺点效率低

    ④使用分布式任务调度平台XXLJOB

    XXLJOB介绍

    1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手;

    2、动态:支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效;

    3、调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现,可保证调度中心HA;

    4、执行器HA(分布式):任务分布式执行,任务"执行器"支持集群部署,可保证任务执行HA;

    5、任务Failover:执行器集群部署时,任务路由策略选择"故障转移"情况下调度失败时将会平滑切换执行器进行Failover;

    6、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;

    7、自定义任务参数:支持在线配置调度任务入参,即时生效;

    8、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞;

    9、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务;

    10、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;

    11、状态监控:支持实时监控任务进度;

    12、Rolling执行日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;

    13、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。

    14、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;

    15、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;

    16、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;

    17、任务注册: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址;

    18、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等;

    19、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;

    20、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python等类型脚本;

    21、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度;

    22、失败处理策略;调度失败时的处理策略,策略包括:失败告警(默认)、失败重试;

    23、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发对应集群中所有执行器执行一次任务,同时传递分片参数;可根据分片参数开发分片任务;

    24、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。

    25、事件触发:除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。

    XXLJOBGitHub地址

    https://github.com/xuxueli/xxl-job

    文档

    http://www.xuxueli.com/xxl-job/#/?id=_21-%e5%88%9d%e5%a7%8b%e5%8c%96%e8%b0%83%e5%ba%a6%e6%95%b0%e6%8d%ae%e5%ba%93

    步骤:

    ①  部署: xxl-job-admin  作为注册中心

    ②  创建执行器(具体调度地址) 可以支持集群

    ③  配置文件需要填写xxl-job注册中心地址

    ④  每个具体执行job服务器需要创建一个netty连接端口号

    ⑤  需要执行job的任务类,集成IJobHandler抽象类注册到job容器中

    ⑥  Execute方法中编写具体job任务

    客户端对接

    引入依赖

    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.hongmoshui.www</groupId>
        <artifactId>springBoot-xxLjob</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <!-- <dependencies></dependencies> -->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.6.RELEASE</version>
        </parent>
        <dependencies>
            <!-- jetty -->
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-server</artifactId>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-util</artifactId>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-http</artifactId>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-io</artifactId>
            </dependency>
            <!-- spring-boot-starter-web (spring-webmvc + tomcat) -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!-- xxl-job-core -->
            <dependency>
                <groupId>com.xuxueli</groupId>
                <artifactId>xxl-job-core</artifactId>
                <version>1.8.2</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin </artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

    配置文件

    # web port
    server.port=8084
    # log config
    logging.config=classpath:logback.xml
    # xxl-job
    ### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
    xxl.job.admin.addresses=http://127.0.0.1:8081/xxl-job-admin
    ### xxl-job executor address
    xxl.job.executor.appname=test
    xxl.job.executor.ip=192.168.1.3
    xxl.job.executor.port=9999
    ### xxl-job log path
    xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
    ### xxl-job, access token
    xxl.job.accessToken=

    Java代码

    package com.hongmoshui.xxljob;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    import com.xxl.job.core.executor.XxlJobExecutor;
    
    /**
     * xxl-job config
     * @author hongmoshui
     */
    @Configuration
    @ComponentScan(basePackages = "com.xxl.job.executor.service.jobhandler")
    public class XxlJobConfig
    {
        private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
    
        @Value("${xxl.job.admin.addresses}")
        private String addresses;
    
        @Value("${xxl.job.executor.appname}")
        private String appname;
    
        @Value("${xxl.job.executor.ip}")
        private String ip;
    
        @Value("${xxl.job.executor.port}")
        private int port;
    
        @Value("${xxl.job.executor.logpath}")
        private String logpath;
    
        @Value("${xxl.job.accessToken}")
        private String accessToken;
    
        @Bean(initMethod = "start", destroyMethod = "destroy")
        public XxlJobExecutor xxlJobExecutor()
        {
            logger.info(">>>>>>>>>>> xxl-job config init.");
            XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
            xxlJobExecutor.setIp(ip);
            xxlJobExecutor.setPort(port);
            xxlJobExecutor.setAppName(appname);
            xxlJobExecutor.setAdminAddresses(addresses);
            xxlJobExecutor.setLogPath(logpath);
            xxlJobExecutor.setAccessToken(accessToken);
            return xxlJobExecutor;
        }
    
    }
    package com.hongmoshui.xxljob;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    
    import com.xxl.job.core.biz.model.ReturnT;
    import com.xxl.job.core.handler.IJobHandler;
    import com.xxl.job.core.handler.annotation.JobHander;
    import com.xxl.job.core.log.XxlJobLogger;
    
    /**
     * <任务Handler的一个Demo(Bean模式)>
     *  <开发步骤>
     * 1、继承 “IJobHandler” ; 2、装配到Spring,例如加“@Service” 注解;
     * 3、加 “@JobHander”注解,注解value值为新增任务生成的JobKey的值;多个JobKey用逗号分割;
     * 4、执行日志:需要通过 "XxlJobLogger.log"打印执行日志;
     * @author xuxueli 2015-12-19 19:43:36
     */
    @JobHander(value = "demoJobHandler")
    @Service
    public class DemoJobHandler extends IJobHandler
    {
        @Value("${xxl.job.executor.port}")
        private String port;
    
        @Override
        public ReturnT<String> execute(String... params) throws Exception
        {
            XxlJobLogger.log("XXL-JOB, Hello World." + port);
            System.out.println("XXL-JOB, Hello World." + port);
            for (int i = 0; i < 5; i++)
            {
                XxlJobLogger.log("beat at:" + i);
                // TimeUnit.SECONDS.sleep(2);
            }
            return ReturnT.SUCCESS;
        }
    
    }

    XXLJOB路由策略

  • 相关阅读:
    8.C++-类的关键字
    BFS-九宫格重排(详解)
    7.C++类与封装的概念
    4.数码相框-freetype多行显示,居中显示
    3.数码相框-通过freetype库实现矢量显示
    Linux-iconv命令、并批处理将所有GBK文件转换为UTF8(18)
    2.数码相框-编码(ASCII/GB2312/Unicode)介绍,并使LCD显示汉字字符(2)
    1.数码相框-相框框架分析(1)
    Kotlin 之操作符重载
    Andorid-解决View重复点击的思路
  • 原文地址:https://www.cnblogs.com/hongmoshui/p/10994430.html
Copyright © 2011-2022 走看看