LTS light-task-scheduler轻量级分布式任务调度框架学习

Posted RunningFan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LTS light-task-scheduler轻量级分布式任务调度框架学习相关的知识,希望对你有一定的参考价值。

由于业务需求,我们数据仓库定时器太多了,又难管理,每次要更改定时器都得重启服务实在麻烦。上面又让换个框架,给了个LTS,今天开始学习哈。有问题就记录下来,对于一个资质一般的妹子而言,写程序简直太难了大哭大哭大哭。LTS网站内容很全,可是还是没教会我,是我太笨了么?
github地址: https://github.com/ltsopensource/light-task-scheduler
oschina地址: http://git.oschina.net/hugui/light-task-scheduler

1、导入maven项目

刚开始看着下载的文档,按照一般做法Import项目发现不行,然后又折腾半天,看了pom.xml文件都比较特殊,项目都有parent项目,所以这里应该是直接导入maven项目,用maven管理比较方便。成功导入。导入之后的项目结构如图。

2、执行测试用例

运行给的api例子,测试JobTraker,这里用到了jdbc,我把jdbc的配置地址改成可用的地址。运行,结果报错如下:

[INFO ] [15:45:27] org.apache.zookeeper.ZooKeeper - Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=30000 watcher=org.I0Itec.zkclient.ZkClient@b8cabe
[INFO ] [15:45:27] org.apache.zookeeper.ClientCnxn - Opening socket connection to server 127.0.0.1/127.0.0.1:2181. Will not attempt to authenticate using SASL (unknown error)
[WARN ] [15:45:28] org.apache.zookeeper.ClientCnxn - Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused: no further information
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source)
at org.apache.zookeeper.ClientCnxnSocketNIO.doTransport(ClientCnxnSocketNIO.java:350)
at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1068)

这个错误的意思是连接服务失败了,zookeeper的地址有问题,需要一个zookeeper服务!!!!!我选择在内网的一台服务器192.168.100.214上装了一个zookeeper,这里还需要数据库的配置,我把LTS的数据库放在192.168.100.213

3、安装部署zookeeper

zookeeper的官方网站下载包 http://apache.fayea.com/zookeeper/

  我下的版本是zookeeper-3.4.6.tar.gz
  上传至服务,解压。
  通过努力,修改配置文件,原来的是zoo-sample.cfg,复制创建一个zoo.cfg,修改dataDIr和dataLogDir路径(其实也可以不修改的),zoo.cfg内容如下:
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes. 自己配置 没有的话创建一个
dataDir=/home/hadoop/zookeeper/data
dataLogDir=/home/hadoop/zookeeper/log
# the port at which the clients will connect 
clientPort=2181

然后启动,zkServer.sh start,启动成功了,太开心了。也可以再启动一个client,zkCli.sh -server localhost:2181,测试连接成功了。

4、运行lts-example

  再来测试一下lts-example中的类,都能够顺利启动成功,JobTrakerTest日志如下:
[INFO ] [18:06:33] com.lts.core.cluster.SubscribedNodeManager -  [LTS] Add "address":"192.168.100.115:35001","available":true,"clusterName":"test_cluster","createTime":1461146782683,"group":"lts","hostName":"gyhdomain","httpCmdPort":8719,"identity":"3A7C23C32FD84A59B835CE554E685E32","ip":"192.168.100.115","nodeType":"JOB_TRACKER","port":35001,"threads":2, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
[INFO ] [18:06:33] com.lts.core.cluster.MasterElector -  [LTS] Current node become the master node:"address":"192.168.100.115:35001","available":true,"clusterName":"test_cluster","createTime":1461146782683,"group":"lts","hostName":"gyhdomain","httpCmdPort":8719,"identity":"3A7C23C32FD84A59B835CE554E685E32","ip":"192.168.100.115","nodeType":"JOB_TRACKER","port":35001,"threads":2, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
[INFO ] [18:06:33] com.lts.jobtracker.support.checker.FeedbackJobSendChecker -  [LTS] Feedback job checker started!, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
[INFO ] [18:06:34] com.lts.jobtracker.support.checker.ExecutingDeadJobChecker -  [LTS] Executing dead job checker started!, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
[INFO ] [18:06:34] com.lts.jobtracker.support.checker.ExecutableDeadJobChecker -  [LTS] Executable dead job checker started!, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
我变成了节点组中的master节点了, 恭喜, 我要放大招了

JobClientTest日志

master节点变成了"address":"192.168.100.115:0","available":true,"clusterName":"test_cluster","createTime":1461292849210,"group":"test_jobClient","hostName":"gyhdomain","httpCmdPort":8720,"identity":"0CCB00D5AA1144838B8D106708EE71C5","ip":"192.168.100.115","nodeType":"JOB_CLIENT","port":0,"threads":2,不是我,我不能放大招,要猥琐
[INFO ] [11:31:06] com.lts.core.registry.Registry -  [LTS] Register: "address":"192.168.100.115:0","available":true,"clusterName":"test_cluster","createTime":1461295855460,"group":"test_jobClient","hostName":"gyhdomain","httpCmdPort":8722,"identity":"4D10F8AF80044E20B31E378965D8E04A","ip":"192.168.100.115","listenNodeTypes":["JOB_TRACKER","JOB_CLIENT","MONITOR"],"nodeType":"JOB_CLIENT","port":0,"threads":2, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
[INFO ] [11:31:06] com.lts.core.cluster.JobNode -  [LTS] Start success, nodeType=JOB_CLIENT, identity=4D10F8AF80044E20B31E378965D8E04A, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
命令参数: 
    1:cronExpression模式,如 0 0/1 * * * ?(一分钟执行一次), 
    2:指定时间模式 yyyy-MM-dd HH:mm:ss,在执行时间模式下,如果字符串now,表示立即执行 
    quit:退出
    help:帮助
指定时间模式:
[INFO ] [11:31:06] com.lts.core.cluster.SubscribedNodeManager -  [LTS] Add "address":"192.168.100.115:0","available":true,"clusterName":"test_cluster","createTime":1461295855460,"group":"test_jobClient","hostName":"gyhdomain","httpCmdPort":8722,"identity":"4D10F8AF80044E20B31E378965D8E04A","ip":"192.168.100.115","nodeType":"JOB_CLIENT","port":0,"threads":2, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
2016-04-22 11:31:11 任务执行完成:"job":"cron":true,"cronExpression":"0/10 * * * * ?","extParams":"shopId":"111","maxRetryTimes":0,"needFeedback":true,"priority":100,"repeatCount":0,"repeatInterval":0,"repeatable":false,"repeatedCount":0,"replaceOnExist":false,"retryTimes":0,"submitNodeGroup":"test_jobClient","taskId":"604405F235054666A5CA81F0FAF974EA","taskTrackerNodeGroup":"test_trade_TaskTracker","triggerTime":1461295870000,"msg":"执行成功了,哈哈","success":true,"time":1461295871400

TaskTraker日志

[INFO ] [11:34:31] com.lts.example.support.TestJobRunner -  [LTS] 我要执行:"cron":true,"cronExpression":"0/10 * * * * ?","extParams":"shopId":"111","maxRetryTimes":0,"needFeedback":true,"priority":100,"repeatCount":0,"repeatInterval":0,"repeatable":false,"repeatedCount":0,"replaceOnExist":false,"retryTimes":0,"submitNodeGroup":"test_jobClient","taskId":"B8C185711B88485B9631FDF4F82FB534","taskTrackerNodeGroup":"test_trade_TaskTracker","triggerTime":1461296070000, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
[INFO ] [11:34:31] com.lts.tasktracker.runner.JobRunnerDelegate -  [LTS] Job execute completed : "cron":true,"cronExpression":"0/10 * * * * ?","extParams":"shopId":"111","maxRetryTimes":0,"needFeedback":true,"priority":100,"repeatCount":0,"repeatInterval":0,"repeatable":false,"repeatedCount":0,"replaceOnExist":false,"retryTimes":0,"submitNodeGroup":"test_jobClient","taskId":"B8C185711B88485B9631FDF4F82FB534","taskTrackerNodeGroup":"test_trade_TaskTracker","triggerTime":1461296070000, time:0 ms., lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115

5、启动LTS服务

后台怎么看呢?文档是这样描述的:
1、运行下载包light-task-scheduler-master根目录下的sh build.sh或build.cmd脚本,会在dist目录下生成lts-version-bin文件夹。
2、其中bin目录主要是JobTracker和LTS-Admin的启动脚本。jobtracker 中是 JobTracker的配置文件和需要使用到的jar包,lts-admin是LTS-Admin相关的war包和配置文件。 lts-version-bin的文件结构JobTracker启动。
3、如果你想启动一个节点,直接修改下conf/zoo下的配置文件,然后运行 sh jobtracker.sh zoo start即可,如果你想启动两个JobTracker节点,那么你需要拷贝一份zoo,譬如命名为zoo2,修改下zoo2下的配置文件,然后运行sh jobtracker.sh zoo2 start即可。logs文件夹下生成jobtracker-zoo.out日志。
4、LTS-Admin启动.修改conf/lts-monitor.cfg和conf/lts-admin.cfg下的配置,然后运行bin下的sh lts-admin.sh或lts-admin.cmd脚本即可。logs文件夹下会生成lts-admin.out日志,启动成功在日志中会打印出访问地址,用户可以通过这个访问地址访问了。

照着文档说的,生成dist文件夹,在cmd控制台执行build.cmd,结果报错。
发现自己忒傻了,直接执行这个批处理文件是不行的,要进入到这个文件放的位置,再执行,成功下载jar包。执行成功。

生成了dist文件夹后,修改里面相应的配置文件,mysql和zookeeper的配置改成自己相应的地址。 

admin.cfg

// 后台的用户名密码
console.username=admin
console.password=admin

# 注册中心地址,可以是zk,也可以是redis
registryAddress=zookeeper://192.168.100.214:2181
# registryAddress=redis://127.0.0.1:6379

# 集群名称
clusterName=test_cluster

# zk客户端,可选值 zkclient, curator
configs.zk.client=zkclient

# ------ 这个是Admin存储数据的地方,也可以和JobQueue的地址一样 ------
configs.jdbc.url=jdbc:mysql://192.168.100.213:3306/lts
configs.jdbc.username=root
configs.jdbc.password=123456

# admin 数据使用mysql 默认 mysql, 可以自行扩展
jdbc.datasource.provider=mysql

# 使用 可选值  fastjson, jackson
# configs.lts.json=fastjson

# 是否在admin启动monitor服务, monitor服务也可以单独启动
lts.monitorAgent.enable=true

#======================以下相关配置是JobTracker的JobQueue和JobLogger的相关配置 要保持和JobTracker一样==========================
## (可选配置)jobT. 开头的, 因为JobTracker和Admin可能使用的数据库不是同一个
# LTS业务日志, 可选值 mysql, mongo
jobT.job.logger=mysql
# ---------以下是任务队列配置-----------
# 任务队列,可选值 mysql, mongo
jobT.job.queue=mysql

# ------ 1. 如果是mysql作为任务队列 (如果不配置,表示和Admin的在一个数据库)------
# jobT.jdbc.url=jdbc:mysql://127.0.0.1:3306/lts
# jobT.jdbc.username=root
# jobT.jdbc.password=root

# ------ 2. 如果是mongo作为任务队列 ------
# jobT.mongo.addresses=127.0.0.1:27017
# jobT.mongo.database=lts
# jobT.mongo.username=xxx #如果有的话
# jobT.mongo.password=xxx #如果有的话

# admin 数据使用mysql 默认 mysql, 可以自行扩展
# jobT.jdbc.datasource.provider=mysql

monitor.cfg

# 注册中心地址,可以是zk,也可以是redis
registryAddress=zookeeper://192.168.100.214:2181
# registryAddress=redis://127.0.0.1:6379

# 集群名称
clusterName=test_cluster

# LTS业务日志, 可选值 mysql, mongo
configs.job.logger=mysql

# zk客户端,可选值 zkclient, curator
configs.zk.client=zkclient

# ---------以下是任务队列配置-----------
# 任务队列,可选值 mysql, mongo
configs.job.queue=mysql

# ------ 1. 如果是mysql作为任务队列 ------
configs.jdbc.url=jdbc:mysql://192.168.100.213:3306/lts
configs.jdbc.username=root
configs.jdbc.password=123456

# ------ 2. 如果是mongo作为任务队列 ------
configs.mongo.addresses=127.0.0.1:27017
configs.mongo.database=lts
# configs.mongo.username=xxx #如果有的话
# configs.mongo.password=xxx #如果有的话

# admin 数据使用mysql, h2 默认 h2 embedded
jdbc.datasource.provider=mysql

# 使用 可选值  fastjson, jackson
# configs.lts.json=fastjson

这里同时修改jobTracker配置文件

# 注册中心地址,可以是zk,也可以是redis
registryAddress=zookeeper://192.168.100.214:2181

# JobTracker的监听端口
listenPort=3502

# 集群名称
clusterName=test_cluster

# LTS业务日志, 可选值 console, mysql, mongo
configs.job.logger=mysql

# zk客户端,可选值 zkclient, curator
configs.zk.client=zkclient

# ---------以下是任务队列配置-----------
# 任务队列,可选值 mysql, mongo
configs.job.queue=mysql

# ------ 1. 如果是mysql作为任务队列 ------
configs.jdbc.url=jdbc:mysql://192.168.100.213:3306/lts
configs.jdbc.username=root
configs.jdbc.password=123456

# ------ 2. 如果是mongo作为任务队列 ------
configs.mongo.addresses=127.0.0.1:27017
configs.mongo.database=lts
# configs.mongo.username=xxx #如果有的话
# configs.mongo.password=xxx #如果有的话

执行sh ./bin/lts-admin.sh start
执行成功,会一同启动lts-monitor,如下

启动jobTracker服务
sh ./bin/jobtracker.sh zoo start

上面打印出来的地址应该就是lts-admin的后台地址。在浏览器输入localhost:8081/index.htm进入到以下页面:

太开心了,又近了一步了,看到后台了。现在我需要做的就是,怎样把这个集成到我自己的项目。文档说可以打成jar包或者修改maven配置文件pom.xml集成至项目。我的项目是需要管理很多定时任务的,之前是通过cron和trigger方式添加的定时器,不方便修改和管理。

6、maven打包,引入jar包

1)在eclipse中maven打包
将要用到的项目maven打包,这里自己犯糊涂去Export-jar file,结果导不出去。其实maven-install,在target文件夹下就会生成jar文件。这里要导出lts-jobclient.jar、lts-jobtraker、lts-tasktraker.jar、lts-core.jar、lts-spring.jar…本身不是很清楚,我就干脆都maven-install.在生成jar包的过程中,有几个一直报错,起初不知道什么原因,原来是test报错,所以无法生成jar包,最简单的办法,把@Test屏蔽掉,因为有的测试用例要在一定的前提下(比如先启动别的服务或者修改参数)才能正常进行。去掉测试后,运行成功。生成了jar包。
我把生成的jar包加到自己的项目里,起初我是这样弄的:

    在webapp->WEB-INFO->lts->*.jar 

然后再把jar包配置进去。我的项目是maven spring项目,在pom.xml里面还需加入这些jar包依赖的包,直接把lts下面的copy过来稍作修改。我想测试下.xml启动加载,于是,我把job-client.xml加到我的服务里,在tomcat下启动,结果,一直报错,总是类找不到,明明我已经加了啊?

原因是我画蛇添足,在WEB-INFO下加了个lts文件夹。对于普通的java类,编译jar包时,就直接在导入的包中查找就可以了,但是对于web项目,由于它们是借助了tomcat或者其他的容器运行发布的,基于tomcat本身,它会在web项目中的web-inf下的lib中进行编译jar包,而此时,之前导入的jar包却不在这里,所以,就会爆红了,,,解决方案,把需要的jar包拷贝进入WEB-INF下的lib就可以了。。。

问题不断,又遇到下面这个问题,找不到方法。我用的是jdk1.7编译、运行,跑main方法是好的,在tomcat下启动就不行。真是伤脑筋。

    2016-04-26 09:24:45,056 [LTS-HeartBeat-Fast-Ping-thread-1] ERROR [HeartBeatMonitor] -  [LTS] Ping JobTracker error, lts version: 1.6.6-SNAPSHOT, current host: 192.168.100.115
java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView;
    at com.lts.core.commons.concurrent.ConcurrentHashSet.iterator(ConcurrentHashSet.java:45)
    at java.util.AbstractCollection.toArray(Unknown Source)
    at java.util.ArrayList.<init>(Unknown Source)
    at com.lts.core.commons.utils.CollectionUtils.setToList(CollectionUtils.java:93)
    at com.lts.core.cluster.SubscribedNodeManager.getNodeList(SubscribedNodeManager.java:80)
    at com.lts.core.remoting.HeartBeatMonitor.check(HeartBeatMonitor.java:173)
    at com.lts.core.remoting.HeartBeatMonitor.ping(HeartBeatMonitor.java:162)
    at com.lts.core.remoting.HeartBeatMonitor.access$400(HeartBeatMonitor.java:30)
    at com.lts.core.remoting.HeartBeatMonitor$4.run(HeartBeatMonitor.java:131)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask$Sync.innerRunAndReset(Unknown Source)
    at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

这个错误的原因是jar包冲突,我自己的项目原本引用了很多jar包,这里又加入了maven配置,难免有很多包冲突。

2)Windows或者Linux下生成jar包

在Windows下执行文件夹中的build.cmd,或者在Linux下执行build.sh,编译成功后,会在各个子模块的target文件夹中生成jar包,可以直接引用此jar包。

为避免jar包版本不一致而产生冲突,我在加入lts的各个jar包后,逐个测试,缺少什么包就加入什么包的maven依赖,这招的确管用。如果直接加入lts的所有maven依赖,虽然有的maven配置不一样,但是还是会产生很多重复的包,从而导致运行出错。

7、管理后台任务

lts的example可以参考,本来我添加了一个监听器,tomcat启动的时候启动taskTrack服务(这里业务需求用不上jobclient就没管) ,结果tomcat始终启动不起来,我就改成了tomcat启动成功后启动taskTracker服务,可以成功。
现在所有服务是这样的
本机 192.168.100.115 lts-taskTracker
mysql 192.168.100.213 :3306 lts数据库
zookeeper 192.168.100.214 :2181 zkServer服务
lts 192.168.100.215 lts-admin lts-monitor lts-jobTracker
登录后台,添加任务,
lts-admin 登录
lts-monitor 登录admin后的任务管理
lts-jobClient 提交任务 后台添加任务可直接提交
lts-jobTracker 派发任务
lts-taskTracker 执行任务

以上是关于LTS light-task-scheduler轻量级分布式任务调度框架学习的主要内容,如果未能解决你的问题,请参考以下文章

LTS本地搭建详述

LTS用户文档

LTS原理--轻量级分布式任务调度框架(Light Task Schedule)

用腾讯云Gogs搭建私有git服务器

轻量化分割模型-RTSEG

轻量化分割模型-LiteSeg