elastic-job使用及过程中遇到的问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/name_z/article/details/81274029

以前的公司项目分布式调度用的两种方式,一是通过配置文件进行分区,一是用阿里的一个dtss控件;配置文件的方式就不说了,比较挫;而阿里的dtss控件存在问题,而且该控件也已经停止维护更新(别的控件又要收钱)。
所以找到了这个elastic-job,目前只用到了其中的SimpleJob,后续的再更新。。。

官方文档

官网地址:http://elasticjob.io/index_zh.html
官网文档:http://elasticjob.io/docs/elastic-job-lite/00-overview/

使用

简单介绍:

这个框架的任务分派,简单来说就是,通过zookeeper知道线上总共有多少台执行机器,然后把分片平均分到线上的机器上,而每次机器的上线、下线都会触发分片的重新分配。
而分片其实就是数字,数字将平均分配到几台机器上,例如:
设置总分片数为4片(0,1,2,3总共4个分片),线上2台机器,机器A可能被分配到0、1两个数字,机器B被分配到2、3两个数字,然后就可以根据这个被分配到的数字进行任务划分。

依赖添加:

<!-- 引入elastic-job-lite核心模块 -->
<dependency>
    <groupId>com.dangdang</groupId>
    <artifactId>elastic-job-lite-core</artifactId>
    <version>2.1.5</version>
</dependency>
<!-- 使用springframework自定义命名空间时引入 -->
<dependency>
    <groupId>com.dangdang</groupId>
    <artifactId>elastic-job-lite-spring</artifactId>
    <version>2.1.5</version>
</dependency>

实现类:

    public class TestJob implements SimpleJob{

        private Logger logger = LoggerFactory.getLogger(TestJob.class);

        @Override
        public void execute(ShardingContext shardingContext) {
            // 分片数字以及作业的一些信息都在ShardingContext这个类中
            logger.info(...);
        }
    }

启动方法:

有两种启动方式:代码启动和配置文件加载启动,

代码启动:

    // 启动方法
    public void init(){
        new JobScheduler(getRegistryCenter(), getJobConfiguration()).init();
    }

    // 配置zookeeper连接信息,以及进行连接
    public CoordinatorRegistryCenter getRegistryCenter() {
        // 连接Zookeeper服务器的列表,包括IP地址和端口号,多个地址用逗号分隔,如: host1:2181,host2:2181
        // Zookeeper的命名空间
        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(zookeeperIps, zookeeperNamespace));
        regCenter.init();
        return regCenter;
    }

    // 配置job的信息
    public LiteJobConfiguration getJobConfiguration(){
        // 定义作业核心配置
        JobCoreConfiguration simpleCoreConfig = getJobCoreConfiguration();
        // 定义SIMPLE类型配置
        SimpleJobConfiguration simpleJobConfig = getSimpleJobConfiguration(simpleCoreConfig);
        // 定义Lite作业根配置
        LiteJobConfiguration simpleJobRootConfig = getLiteJobConfiguration(simpleJobConfig);

        return simpleJobRootConfig;
    }

    // 定义作业核心配置
    public JobCoreConfiguration getJobCoreConfiguration(){
        // 分片总数
        int shardingTotalCount = 10;
        return JobCoreConfiguration.newBuilder("任务名称", "cron表达式", shardingTotalCount ).jobParameter("作业参数").shardingItemParameters("分片参数").build();
    }

    // 定义SIMPLE类型配置
    public SimpleJobConfiguration getSimpleJobConfiguration(JobCoreConfiguration simpleCoreConfig){
        // job实现类名字需要写全名
        return new SimpleJobConfiguration(simpleCoreConfig, SimpleJob.getClass().getCanonicalName());
    }

    // 定义Lite作业根配置
    public LiteJobConfiguration getLiteJobConfiguration(SimpleJobConfiguration simpleJobConfig){
        // overwrite:本地配置是否可覆盖注册中心配置
        // jobShardingStrategyClass:分片策略
        return LiteJobConfiguration.newBuilder(simpleJobConfig).overwrite(isOverwrite).jobShardingStrategyClass(OdevitySortByNameJobShardingStrategy.class.getCanonicalName()).build();
    }

配置文件启动:

当加载该文件的时候,就启动其中任务调度

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:reg="http://www.dangdang.com/schema/ddframe/reg"
       xmlns:job="http://www.dangdang.com/schema/ddframe/job"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.dangdang.com/schema/ddframe/reg
                        http://www.dangdang.com/schema/ddframe/reg/reg.xsd
                        http://www.dangdang.com/schema/ddframe/job
                        http://www.dangdang.com/schema/ddframe/job/job.xsd
                        ">

    <!--配置作业注册中心 -->
    <reg:zookeeper id="regCenter"
                   server-lists="1.1.1.1:2181,2.2.2.2:2181"
                   namespace="Zookeeper的命名空间"
                   base-sleep-time-milliseconds="1000"
                   max-sleep-time-milliseconds="3000"
                   max-retries="3"
    />

    // 实现类,需要实现指定接口
    <bean id="simpleJob" class="xxx.SimpleJob">

    </bean>

    <!-- 配置关联Bean作业-->
    <job:simple id="simpleRefElasticJob"
                overwrite="true"
                job-parameter="2"
                sharding-item-parameters="0=A,1=B"
                job-ref="simpleJob"
                registry-center-ref="regCenter"
                cron="0/59 * * * * ?"
                sharding-total-count="64"
                job-sharding-strategy-class="com.dangdang.ddframe.job.lite.api.strategy.impl.OdevitySortByNameJobShardingStrategy"
    />
</beans>

注意项

代码启动中,实现类的execute方法中不能使用spring注入的对象:

elastic-job是封装的quartz框架,这个特性也存留下来,execute方法中只能用static对象

    @Service
    public class TestJob implements SimpleJob{

        private Logger logger = LoggerFactory.getLogger(TestJob.class);

        @Autowired
        private TestService testService;

        private static TestService staticTestService;

        // 启动前,需要调用该方法初始化static对象
        public void init(){
            staticTestService = testService;
        }

        @Override
        public void execute(ShardingContext shardingContext) {
            // 分片数字以及作业的一些信息都在ShardingContext这个类中
            logger.info(...);

            // 日志输出为:true
            logger.info(testService == null);

            // 日志输出为:false
            logger.info(staticTestService == null);
        }
    }

需要注意的配置:

详细的配置信息可以看官方文档:http://elasticjob.io/docs/elastic-job-lite/02-guide/config-manual/

overwrite:

overwrite
默认为false,如果为false的话,第一次启动的时候,会在zookeeper中保存了一份作业信息(调度时间、参数等),后面即使修改了作业信息,无论重新启动服务或者zookeeper,还是会使用第一次启动时候的作业信息(根据作业名字)。
因此需要设为true,这样每次启动,作业信息都会覆盖zookeeper中的保存的配置信息,这样可以保证修改了配置信息可以马上使用。

分片策略:

根据文档介绍,OdevitySortByNameJobShardingStrategy这个比默认的策略好

启动的时候可能连不上zookeeper

服务原来就有用dubbo,dubbo这边每次都可以连上zookeeper,但是elastic-job经常出现启动的时候连不上zookeeper的,需要启多几次,也可以把zookeeper的最大重连次数(max-retries)设置大点

实际应用中遇到的问题

依赖冲突:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.dangdang.ddframe.job.lite.spring.api.SpringJobScheduler#0': Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.apache.curator.framework.api.CreateBuilder.creatingParentsIfNeeded()Lorg/apache/curator/framework/api/ProtectACLCreateModePathAndBytesable;
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
        at crm.app.logistics.LogisticsAppMain.main(LogisticsAppMain.java:44)
Caused by: java.lang.NoSuchMethodError: org.apache.curator.framework.api.CreateBuilder.creatingParentsIfNeeded()Lorg/apache/curator/framework/api/ProtectACLCreateModePathAndBytesable;
        at com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter.persist(ZookeeperRegistryCenter.java:218)
        at com.dangdang.ddframe.job.lite.internal.storage.JobNodeStorage.replaceJobNode(JobNodeStorage.java:160)
        at com.dangdang.ddframe.job.lite.internal.config.ConfigurationService.persist(ConfigurationService.java:72)
        at com.dangdang.ddframe.job.lite.internal.schedule.SchedulerFacade.updateJobConfiguration(SchedulerFacade.java:103)
        at com.dangdang.ddframe.job.lite.api.JobScheduler.init(JobScheduler.java:105)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1758)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1695)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
        ... 12 more

后面经过排除,发现是依赖冲突的问题,原来项目中有用到阿里的dtss控件,里面有依赖到一个jar包:org.apache.curator,elastic-job框架也用到了,然后版本不一样导致了依赖冲突。

相关文档

官方文档对于很多机制写得并不详细,下面列出些别的大牛的文章来补充:
源码分析ElasticJob任务错过机制(misfire)与幂等性:https://blog.csdn.net/prestigeding/article/details/80140777

运维平台安装部署

官方文档中关于运维平台的介绍:http://elasticjob.io/docs/elastic-job-lite/02-guide/web-console/

1.编译jar包

就是编译的时候用的是1.8的jdk编译的时候,报了异常:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:2.10.3:jar (attach-javadocs) on project elastic-job-lite-lifecycle: MavenReportException: Error while generating Javadoc: 
[ERROR] Exit code: 1 - ????: ???E:\maven-repository\org\codehaus\jettison\jettison\1.1\jettison-1.1.jar?????; error in opening zip file
[ERROR] 
[ERROR] Command line was: D:\java\jdk1.8.0_181\jre\..\bin\javadoc.exe @options @packages
[ERROR] 
[ERROR] Refer to the generated Javadoc files in 'E:\zwh\elastic-job-lite-dev\elastic-job-lite-lifecycle\target\apidocs' dir.
[ERROR] 
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
[ERROR] 
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :elastic-job-lite-lifecycle

看pom文件中,该项目原来用的是1.7版本的jdk,后面用了1.7的版本但是还是报这个错,应该小版本不对,后面直接把pom中的javadoc相关的配置注掉后,就可以正常编译了(1.8也可以):

/* 把下面代码注掉
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <executions>
        <execution>
            <id>attach-javadocs</id>
            <goals>
                <goal>jar</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <aggregate>true</aggregate>
        <charset>${project.build.sourceEncoding}</charset>
        <encoding>${project.build.sourceEncoding}</encoding>
        <docencoding>${project.build.sourceEncoding}</docencoding>
    </configuration>
</plugin>
*/

2.启动

在服务器上启动的,需要长期存活,这样启动不会退出服务器就关掉

nohup sh ${PROJECT_NAME}/elastic-job-lite-console-3.0.0.M1-SNAPSHOT/bin/start.sh -p 30001 &

猜你喜欢

转载自blog.csdn.net/name_z/article/details/81274029
今日推荐