1. 程式人生 > >elastic-job使用及過程中遇到的問題

elastic-job使用及過程中遇到的問題

以前的公司專案分散式排程用的兩種方式,一是通過配置檔案進行分割槽,一是用阿里的一個dtss控制元件;配置檔案的方式就不說了,比較挫;而阿里的dtss控制元件存在問題,而且該控制元件也已經停止維護更新(別的控制元件又要收錢)。
所以找到了這個elastic-job,目前只用到了其中的SimpleJob,後續的再更新。。。

官方文件

使用

簡單介紹:

這個框架的任務分派,簡單來說就是,通過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);
        }
    }

需要注意的配置:

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框架也用到了,然後版本不一樣導致了依賴衝突。

相關文件

運維平臺安裝部署

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 &