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 执行任务