分布式开源调度框架TBSchedule原理与应用
主要内容:
第一部分 TBSchedule基本概念及原理
1. 概念介绍
2. 工作原理
3. 源代码分析
4. 与其它开源调度框架对照
第二部分 TBSchedule分布式调度演示样例
1. TBSchedule源代码下载
2. 引入源代码Demo开发演示样例
3. 控制台配置任务调度
4. selectTasks方法參数说明
5. 创建调度策略參数说明
6. 创建任务參数说明
第一部分 TBSchedule基本概念及原理
1. 概念介绍
TBSchedule是一个支持分布式的调度框架。能让一种批量任务或者不断变化的任务,被动态的分配到多个主机的JVM中,不同的线程组中并行运行。基于ZooKeeper的纯Java实现,由Alibaba开源。
2. 工作原理
TBSchesule对分布式的支持包含调度机的分布式和运行机的分布式,其网络部署架构图例如以下:
2.1 数据存储
运行机和调度机均以ZooKeeper为注冊中心,全部数据以节点及节点内容的形式注冊,通过定时汇报主机状态保持存活在ZooKeeper上。
首先看下运行机对ZooKeeper的使用配置文件:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<bean id="scheduleManagerFactory"
class="com.taobao.pamirs.schedule.strategy.TBScheduleManagerFactory"
init-method="init">
<property name="zkConfig">
<map>
<entry key="zkConnectString" value="${schedule.zookeeper.address}" />
<entry key="rootPath" value="${schedule.root.catalog}" />
<entry key="zkSessionTimeout" value="${schedule.timeout}" />
<entry key="userName" value="${schedule.username}" />
<entry key="password" value="${schedule.password}" />
<entry key="isCheckParentPath" value="true" />
</map>
</property>
</bean>
</beans>
1)运行机部署启动,会在ZooKeeper上创建永久根节点schedule.zookeeper.address
,其后全部的操作均在该根节点下进行。
这里以/ttest/creditjob
为根节点。查看运行机注冊后情况:
[zk: 172.26.50.86:2181(CONNECTED) 28] ls /ttest/creditjob
[strategy, baseTaskType, factory]
[zk: 172.26.50.86:2181(CONNECTED) 29] ls /ttest/creditjob/factory
[127.0.0.1$MIE-ZHANGTAO-D1$9D3029EC0C574403B6CFD0C146644A77$0000000000, 127.0.0.1$MIE-ZHANGTAO-D1$D826BC6565DC4D6CB85F7AE321EE51AE$0000000001]
能够看到根节点以下有3个永久子节点,strategy
存储调度机创建的策略信息,baseTaskType
存储调度机创建的任务信息,factory
存储运行机注冊的主机信息。每台运行机启动后。都会在factory
下创建一个暂时顺序子节点
,该节点名是由TBSchedule源代码生成的主机唯一表示。
根节点内容为当前TBSchedule内置版本号号。可在程序改动,实际没什么意义。
[zk: 172.26.50.86:2181(CONNECTED) 17] get /ttest/creditjob
tbschedule-3.2.12
2)调度机部署启动,这时不会对ZooKeeper节点做不论什么操作。打开调度机配置面板:
配置好ZooKeeper接入点,点击管理主页。进入调度任务管理面板:
输入各项參数创建新任务后,此时会在baseTaskType
以下创建任务名称永久子节点(调度机全部都宕机重新启动后。仍能保持数据的完整性)。而当前节点的内容就是配置的各项參数。
[zk: 172.26.50.86:2181(CONNECTED) 37] ls /ttest/creditjob/baseTaskType
[IScheduleTaskDealSingleTest]
[zk: 172.26.50.86:2181(CONNECTED) 39] get /ttest/creditjob/baseTaskType/IScheduleTaskDealSingleTest
{"baseTaskType":"IScheduleTaskDealSingleTest","heartBeatRate":5000,"judgeDeadInterval":60000,"sleepTimeNoData":500,"sleepTimeInterval":0,"fetchDataNumber":500,"executeNumber":1,"threadNumber":1,"processorType":"SLEEP","permitRunStartTime":"0 * * * * ?","expireOwnSignInterval":1.0,"dealBeanName":"iScheduleTaskDealSingleTest","taskParameter":"0","taskKind":"static","taskItems":["0"],"maxTaskItemsOfOneThreadGroup":0,"version":0,"sts":"resume"}
3)创建调度策略,控制调度机调度状态。
创建完毕调度策略后开启调度,此过程会在相应的任务节点strategy
下创建永久子节点
并写入策略数据。在该子节点下创建表示调度机的暂时顺序子节点
并写入调度策略数据。
[zk: 172.26.50.86:2181(CONNECTED) 56] get /ttest/creditjob/strategy/IScheduleTaskDealSingleTest
{"strategyName":"IScheduleTaskDealSingleTest","IPList":["127.0.0.1"],"numOfSingleServer":0,"assignNum":1,"kind":"Schedule","taskName":"IScheduleTaskDealSingleTest","taskParameter":"0","sts":"resume"}
[zk: 172.26.50.86:2181(CONNECTED) 57] get /ttest/creditjob/strategy/IScheduleTaskDealSingleTest/127.0.0.1$MIE-ZHANGTAO-D1$9D3029EC0C574403B6CFD0C146644A77$0000000000
{"strategyName":"IScheduleTaskDealSingleTest","uuid":"127.0.0.1$MIE-ZHANGTAO-D1$9D3029EC0C574403B6CFD0C146644A77$0000000000","requestNum":1,"currentNum":0,"message":""}
同一时候会在baseTaskType/IScheduleTaskDealSingleTest
下创建下创建两层永久子节点
并注冊调度主机数据。
[zk: 172.26.50.86:2181(CONNECTED) 45] ls /ttest/creditjob/baseTaskType/IScheduleTaskDealSingleTest/IScheduleTaskDealSingleTest
[taskItem, server]
[zk: 172.26.50.86:2181(CONNECTED) 50] get /ttest/creditjob/baseTaskType/IScheduleTaskDealSingleTest/IScheduleTaskDealSingleTest/taskItem
IScheduleTaskDealSingleTest$127.0.0.1$4E8008EE18334564BE1E31C7C0D55296$0000000000,IScheduleTaskDealSingleTest$127.0.0.1$4E8008EE18334564BE1E31C7C0D55296$0000000001
[zk: 172.26.50.86:2181(CONNECTED) 51] get /ttest/creditjob/baseTaskType/IScheduleTaskDealSingleTest/IScheduleTaskDealSingleTest/server
reload=true
2.2 分布式高可用高效率保障
1)调度机的高可用有保障
,多调度机向注冊中心注冊后,共享调度任务。且同一调度任务仅由一台调度机运行调度。当前调度机异常宕机后。其余的调度机会接上。
2)运行机的高可用有保障
,多运行机向注冊中心注冊后,配置运行机单线程(多机总线程为1)运行任务。调度机会随机启动一台运行机运行。当前运行异常机宕机后。调度机会会新调度一台运行机。
3)运行机的并行高效保障
,配置运行机多线程且划分多任务子项后,各任务子项均衡分配到全部运行机,各运行机均运行,多线程数据一致性协调由任务项參数区分。
4)弹性扩展失效转移保障
,运行中的运行机宕机,或新增运行机。调度机将在下次任务运行前又一次分配任务项,不影响正常运行机任务(崩溃的运行机当前任务处理失效)。运行中的调度机宕机或动态新增调度机,不影响运行机当前任务,调度机宕机后动态切换。
3. 源代码分析
3.1 运行机注冊节选
从Spring配置文件能够看到,运行机注冊的入口在TBScheduleManagerFactory
的init
方法,代码片段:
public class TBScheduleManagerFactory implements ApplicationContextAware {
public void init() throws Exception {
Properties properties = new Properties();
for(Map.Entry<String,String> e: this.zkConfig.entrySet()){
properties.put(e.getKey(),e.getValue());
}
this.init(properties);
}
public void init(Properties p) throws Exception {
if(this.initialThread != null){
this.initialThread.stopThread();
}
this.lock.lock();
try{
this.scheduleDataManager = null;
this.scheduleStrategyManager = null;
ConsoleManager.setScheduleManagerFactory(this);
if(this.zkManager != null){
this.zkManager.close();
}
this.zkManager = new ZKManager(p);
this.errorMessage = "Zookeeper connecting ......" + this.zkManager.getConnectStr();
initialThread = new InitialThread(this);
initialThread.setName("TBScheduleManagerFactory-initialThread");
initialThread.start();
}finally{
this.lock.unlock();
}
}
}
init
方法将配置參数封装到Properties
对象后開始初始化,连接上ZooKeeper并启动一个新的线程进行节点数据处理。
this.zkManager = new ZKManager(p);
...
initialThread = new InitialThread(this);
initialThread.start();
跟踪代码能够看到新线程调用的实际处理方法是:
public void initialData() throws Exception{
/** 递归创建永久根节点(/ttest/creditjob)并写入版本号信息 */
this.zkManager.initial();
/** 创建永久子节点 baseTaskType */
this.scheduleDataManager = new ScheduleDataManager4ZK(this.zkManager);
/** 创建永久子节点 strategy 和 factory */
this.scheduleStrategyManager = new ScheduleStrategyDataManager4ZK(this.zkManager);
if (this.start == true) {
/** 注冊调度管理器,创建暂时顺序子节点。节点表示主机的注冊信息 */
this.scheduleStrategyManager.registerManagerFactory(this);
if(timer == null){
timer = new Timer("TBScheduleManagerFactory-Timer");
}
if(timerTask == null){
/** 启动一个定时器检測ZooKeeper状态,假设连接失败,关闭全部的任务后,又一次连接Zookeeper服务器 */
timerTask = new ManagerFactoryTimerTask(this);
timer.schedule(timerTask, 2000,this.timerInterval);
}
}
}
上述几个节点创建完毕,并向ZooKeeper注冊监听,当有数据变化时获得通知(任务运行/暂停)。到这里。就完毕了运行机到ZooKeeper的注冊监听过程。
3.2 调度任务创建节选
任务创建提交保存为入口。将參数封装到ScheduleTaskType
对象中,调用节点创建和更新方法:
//taskTypeEdit.jsp->taskTypeDeal.jsp
if(action.equalsIgnoreCase("createTaskType")){
ConsoleManager.getScheduleDataManager().createBaseTaskType(taskType);
result = "任务" + baseTaskType + "创建成功!
!!
!
";
}else{
ConsoleManager.getScheduleDataManager().updateBaseTaskType(taskType);
result = "任务" + baseTaskType + "改动成功!
!
!。";
}
真正运行任务节点及数据处理的代码段:
//ScheduleDataManager4ZK.java
public void createBaseTaskType(ScheduleTaskType baseTaskType) throws Exception {
if(baseTaskType.getBaseTaskType().indexOf("$") > 0){
throw new Exception("调度任务" + baseTaskType.getBaseTaskType() +"名称不能包含特殊字符 $");
}
/** 在 baseTaskType 节点下创建任务永久节点并写入节点内容为任务配置參数 */
String zkPath = this.PATH_BaseTaskType + "/"+ baseTaskType.getBaseTaskType();
String valueString = this.gson.toJson(baseTaskType);
if ( this.getZooKeeper().exists(zkPath, false) == null) {
this.getZooKeeper().create(zkPath, valueString.getBytes(), this.zkManager.getAcl(),CreateMode.PERSISTENT);
} else {
throw new Exception("调度任务" + baseTaskType.getBaseTaskType() + "已经存在,假设确认须要重建,请先调用deleteTaskType(String baseTaskType)删除");
}
}
假设是更新的话,就不会再创建任务永久节点了,直接改动任务节点内容就可以。
3.3 策略创建节选
策略创建提交保存为入口,将參数封装到ScheduleStrategy
对象中。调用节点创建和更新方法:
//scheduleStrategyEdit.jsp->scheduleStrategyDeal.jsp
if (action.equalsIgnoreCase("createScheduleStrategy")) {
ConsoleManager.getScheduleStrategyManager().createScheduleStrategy(scheduleStrategy);
isRefreshParent = true;
} else if (action.equalsIgnoreCase("editScheduleStrategy")) {
ConsoleManager.getScheduleStrategyManager().updateScheduleStrategy(scheduleStrategy);
isRefreshParent = true;
}
真正运行任务节点及数据处理的代码段:
//ScheduleStrategyDataManager4ZK.java
public void createScheduleStrategy(ScheduleStrategy scheduleStrategy) throws Exception {
String zkPath = this.PATH_Strategy + "/"+ scheduleStrategy.getStrategyName();
/** 在 strategy 节点下创建任务永久节点并写入节点内容为任务配置參数 */
String valueString = this.gson.toJson(scheduleStrategy);
if ( this.getZooKeeper().exists(zkPath, false) == null) {
this.getZooKeeper().create(zkPath, valueString.getBytes(), this.zkManager.getAcl(),CreateMode.PERSISTENT);
} else {
throw new Exception("调度策略" + scheduleStrategy.getStrategyName() + "已经存在,假设确认须要重建,请先调用deleteMachineStrategy(String taskType)删除");
}
}
假设是更新的话,就不会再创建任务永久节点了,直接改动任务节点内容就可以。
3.4 调度控制节选
策略调度控制代码段:
//scheduleStrategyList.jsp->scheduleStrategyDeal.jsp
else if (action.equalsIgnoreCase("deleteScheduleStrategy")) {
ConsoleManager.getScheduleStrategyManager()
.deleteMachineStrategy(
scheduleStrategy.getStrategyName());
isRefreshParent = true;
} else if (action.equalsIgnoreCase("pauseTaskType")) {
ConsoleManager.getScheduleStrategyManager().pause(
scheduleStrategy.getStrategyName());
isRefreshParent = true;
} else if (action.equalsIgnoreCase("resumeTaskType")) {
ConsoleManager.getScheduleStrategyManager().resume(
scheduleStrategy.getStrategyName());
isRefreshParent = true;
}
真正运行任务节点及数据处理的代码段:
//ScheduleStrategyDataManager4ZK.java
/** 策略删除,即删除strategy下相应的策略节点及数据 */
public void deleteMachineStrategy(String taskType) throws Exception {
deleteMachineStrategy(taskType,false);
}
/** 调度暂停,即改动strategy下相应的策略节点的状态标示数据 */
public void pause(String strategyName) throws Exception{
ScheduleStrategy strategy = this.loadStrategy(strategyName);
strategy.setSts(ScheduleStrategy.STS_PAUSE);
this.updateScheduleStrategy(strategy);
}
/** 调度启动,即改动strategy下相应的策略节点的状态标示数据 */
public void resume(String strategyName) throws Exception{
ScheduleStrategy strategy = this.loadStrategy(strategyName);
strategy.setSts(ScheduleStrategy.STS_RESUME);
this.updateScheduleStrategy(strategy);
}
改动节点数据,通过ZooKeeper的事件通知机制,让运行机获得变更通知。
4. 与其它开源调度框架对照
1)Quartz
:Java其实的定时任务标准。
但Quartz关注点在于定时任务而非数据。并无一套依据数据处理而定制化的流程。
尽管Quartz能够基于数据库实现作业的高可用。缺少分布式并行运行作业的功能。
2)Crontab
:Linux系统级的定时任务运行器。缺乏分布式和集中管理功能。
3)elastic-job
:当当网近期开源项目,功能跟TBSchedule差点儿一样(批斗TBSchedule文档缺失严重),一台服务器仅仅能开启一个任务实例,基于Ip不基于IpPort,单机难调试集群功能。
4)TBSchedule
:淘宝早期开源。稳定性能够保证。
第二部分 TBSchedule分布式调度演示样例
1. TBSchedule源代码下载
下载TBSchedule源代码project,内容包含两部分:project编译成jar
的任务开发依赖包和project编译成war
的调度控制台。
2. 引入源代码Demo开发演示样例
当前演示样例与Spring集成,源代码可作为普通project依赖入任务project,也可将其打包成jar
并引入依赖,此处版本号为3.2.2.2
。
补充
:若打包失败,请检查编译插件版本号及jdk编译版本号。
任务project依赖
<dependency>
<groupId>com.taobao.pamirs.schedule</groupId>
<artifactId>tbschedule</artifactId>
<version>3.3.3.2</version>
</dependency>
调度任务实现IScheduleTaskDealSingle
。并实现selectTasks
。execute
方法,具体演示样例:
Component("iScheduleTaskDealSingleTest")
public class IScheduleTaskDealSingleTest implements IScheduleTaskDealSingle<TaskModel> {
private static final Logger LOG = LoggerFactory.getLogger(IScheduleTaskDealSingleTest.class);
@Override
public Comparator<TaskModel> getComparator() {
return null;
}
@Override
public List<TaskModel> selectTasks(String taskParameter, String ownSign, int taskQueueNum,
List<TaskItemDefine> taskItemList, int eachFetchDataNum) throws Exception {
LOG.info("IScheduleTaskDealSingleTest配置的參数,taskParameter:{}。ownSina:{}。taskQueueNum:{},taskItemList:{}, eachFetchDataNum:{}", taskParameter, ownSign, taskQueueNum, taskItemList, eachFetchDataNum);
LOG.info("IScheduleTaskDealSingleTest选择任务列表開始啦..........");
List<TaskModel> models = new ArrayList<TaskModel>();
models.add(new TaskModel(String.valueOf(System.currentTimeMillis()), "taosirTest1"));
models.add(new TaskModel(String.valueOf(System.currentTimeMillis()), "taosirTest2"));
return models;
}
@Override
public boolean execute(TaskModel model, String ownSign) throws Exception {
LOG.info("IScheduleTaskDealSingleTest运行開始啦.........." + new Date());
System.out.println(model);
return true;
}
}
当中selectTasks
方法获取须要处理的列表(用集合装着),循环集合中的元素并调用execute
方法运行。子计时任务启动,会直到获取不到数据后才停止等待下一个子计时開始,參数后面具体介绍。
将调度任务注冊到zookeeper
中心,spring
中引入例如以下配置:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<bean id="scheduleManagerFactory"
class="com.taobao.pamirs.schedule.strategy.TBScheduleManagerFactory"
init-method="init">
<property name="zkConfig">
<map>
<entry key="zkConnectString" value="${schedule.zookeeper.address}" />
<entry key="rootPath" value="${schedule.root.catalog}" />
<entry key="zkSessionTimeout" value="${schedule.timeout}" />
<entry key="userName" value="${schedule.username}" />
<entry key="password" value="${schedule.password}" />
<entry key="isCheckParentPath" value="true" />
</map>
</property>
</bean>
</beans>
环境属性配置文件添加例如以下配置:
#注冊中心地址
schedule.zookeeper.address=172.26.50.86:2181
#定时任务根文件夹。随意指定,调度控制台配置时相应
schedule.root.catalog=/tbschedule/example
#账户,随意指定。调度控制台配置时相应
schedule.username=username
#密码,随意指定,调度控制台配置时相应
schedule.password=password
#超时配置
schedule.timeout=60000
启动容器,iScheduleTaskDealSingleTest
就完毕了到zookeeper
中心的注冊。
补充
:TBSchedule提供了IScheduleTaskDealSingle和IScheduleTaskDealMulti两个接口,个人在測试中发现两者除了execute方法上參数不同外,功能上并没有别的不同,仅仅是语义上的区分,在处理模式为SLEEP下getComparator()没实用。普通情况下,都是SLEEP模式。
3. 控制台配置任务调度
将控制台ScheduleConsole.war
部署到tomcat
容器。
补充
:我通过ant
运行源代码中的build.xml
构建控制台。部署运行失败(没用过ant,眼下不知道原因),这样的情况下:使用方式一,直接用下载包中的控制台部署就可以。
使用方式二,改动project配置打成
war
包,这灵活,还能够自己定义改动,源文件不支持中文,可将编码改成utf-8
支持。
向注冊中心注冊配置(跟任务注冊用同一根文件夹,官方wiki图示)
http://{server}:{port}/ScheduleConsole/schedule/config.jsp
配置调度任务(官方wiki图示)
http://{server}:{port}/ScheduleConsole/schedule/index.jsp
4. selectTasks方法參数说明
taskParameter
:相应控制台自己定义參数
,可自己定义传入做逻辑上的操作
taskQueueNum
:相应控制台任务项
数量
taskItemList
:集合中TaskItemDefine
的id值相应任务项
值,多线程处理时,依据任务项协调数据一致性和完整性
eachFetchDataNum
:相应控制台每次获取数量
,因为子计时单元開始后,会不断的去取数据进行处理,直到取不到数据子计时才停止,等待下一个子计时開始。
能够限制每次取数。防止一次性数据记录过大,内存不足。
ownSign
:环境參数,一般没什么用
5. 创建调度策略參数说明
策略名称
:策略标示,可随意填写
任务类型
:一般保持默认Schedule
任务名称
:相应任务栏被调度任务名称
任务參数
:一般不用,保持默认
单JVM最大线程组数量
:单个JVM同意开启的线程数
最大线程组数量
:多处理机情况下的线程总数限制(总线程为2。任务项线程为4是没有意义的)
IP地址
:127.0.0.1
或者localhost
会在全部机器上运行,注意多处理机若没有依据任务子项划分数据处理,会导致多处理机反复处理数据,慎重配置
创建演示样例。官方wiki上有图示。上面主要是各參数的具体含义。
6. 创建任务參数说明
任务名称
:策略调度的标示。一旦创建保存,不可更改
任务处理的SpringBean
:注冊到spring的任务bean,如iScheduleTaskDealSingleTest
心跳频率
/假定服务死亡时间
/处理模式
/没有数据时休眠时长
/运行结束时间
:一般保持默认就可以
线程数
:处理该任务的线程数,在没有划分多任务项
的情况下,多线程是没有意义的,且线程数量大于任务项
也是没有意义的(线程数小于等于任务项)。注意假设开启多线程,必须对数据做任务项过滤
单线程组最大任务项
:配置单JVM处理的最大任务项数量,多任务项
情况下。可按需限制,一般默认,多运行机会均衡分配
每次获取数量
:子计时单元開始。线程会不断的去获取数据(每次获取的限制)并处理数据,直到获取不到数据子计时才结束(方法内不用就能够随意配置)
每次运行数量
://还没測试过(可能是将获取的数量拆分多次运行)
每次处理完休眠时间
:子计时单元開始,仅仅要有数据,就会不停的获取不停的处理,这个时间设置后,子计时单元開始每次获取运行后。无论还有没有待数据,都先歇会儿再获取处理
自己定义參数
:可自己定义控制任务逻辑操作
任务项
:这项非常重要。在多线程情况下,划分任务项是有意义的,可是要注意必须通过任务项參数,协调待处理数据。否则多线程会反复处理
创建演示样例,官方wiki上有图示。上面主要是各參数的具体含义。
分布式开源调度框架TBSchedule原理与应用的更多相关文章
- 详解应对平台高并发的分布式调度框架TBSchedule
转载: 详解应对平台高并发的分布式调度框架TBSchedule
- 开源调度框架Quartz最佳实践
开源调度框架Quartz最佳实践 Quartz是一个Java调度框架,当前的最新版本为2.2.1. 以Quartz 2.2.1版为例,Quartz最佳实践(用于生产系统)总结如下: 1.跳过更新检查Q ...
- 深入理解分布式调度框架TBSchedule及源码分析
简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...
- Java线程池管理及分布式Hadoop调度框架搭建
平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发工程师却在这个上面吃了不少苦头. 怎么做一套简便的线程开发模 ...
- niubi-job:一个分布式的任务调度框架设计原理以及实现
niubi-job的框架设计是非常简单实用的一套设计,去掉了很多其它调度框架中,锦上添花但并非必须的组件,例如MQ消息通讯组件(kafka等).它的框架设计核心思想是,让每一个jar包可以相对之间独立 ...
- 组件化框架设计之阿里巴巴开源路由框架——ARouter原理分析(一)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 背景 当项目的业务越来越复杂,业务线越来越多的时候,就需要按照业 ...
- 分布式调度框架TBSchedule使用方法
一.TBSchedule简介 TBSchedule是来自淘宝的分布式调度开源框架,基于Zookeeper纯Java实现,其目的是让一种批量任务或者不断变化的任务,能够被动态的分配到多个主机的JVM中的 ...
- 淘宝开源任务调度框架tbschedule
背景 分布式任务调度是非常常见的一种应用场景,一般对可用性和性能要求不高的任务,采用单点即可,例如linux的crontab,spring的quarz,但是如果要求部署多个节点,达到高可用的效果,上面 ...
- 美团分布式定时调度框架XXL-Job基本使用
一:XXL JOB 基本使用 1.官方中文文档:https://www.xuxueli.com/xxl-job/ 2.基本环境: 2.1:git下载项目, 执行xxl-job数据库初始化脚本 2.2: ...
随机推荐
- bzoj 3203 凸包+三分
题目大意 具体自己看吧link 读入n,D,表示n关 大概就是第i关有i只僵尸排成一队来打出题人 最前面那只是编号为\(i\)的僵尸,最后面的一只是编号为\(1\)的僵尸 最前面的僵尸离出题人\(X_ ...
- Session挂起
异常信息: toString() unavailable - no suspended threads 使用Spring管理 ,在使用hibernate时使用如下语句Session session = ...
- SEO总结(一)
- 转 C++ 面向对象程序设计的基本特点
传送门 Miss it C++ 面向对象程序设计的基本特点 First: 抽象 面向对象方法中的抽象,是指对具体问题(对象)进行概括,抽出一类对象公共性质并加以描述的过程. 抽象的过程,也是对问题 ...
- 记录vim经常使用的几个命令
vi/vim 基本使用方法 vi编辑器是所有Unix及Linux系统下标准的编辑器. $ vim 1.txt 以vi打开一个文件就直接进入一般模式了(这是默认的模式).在这个模式中, 你可以使用上下左 ...
- 三、 java运算符与流程控制
赋值运算 赋值运算符:=,+=,-=,×=,/=,%= class fuzhiyunsuan{ public static void main(String[] args){ int i1 = 10; ...
- PHP连接MySQL报错"No such file or directory"的解决办法
好下面说一下连接MYSQL数据库时报错的解决办法. 1,首先确定是mysql_connect()和mysql_pconnect()的问题,故障现象就是函数返回空,而mysql_error()返回“No ...
- [转]常用iOS图片处理方法
自:http://blog.sina.com.cn/s/blog_8988732e0100xcx1.html ========== (one) UIImage 图像 等比例缩放=========== ...
- NoSQL数据库 Couchbase Server - 分布式缓存
Couchbase Server (前身是 Membase) 是一个分布式的面向文档的 NoSQL 数据库管理系统,该系统联合了 CouchDB 的简单和可靠以及 Memcached 的高性能以及 M ...
- Codeforces Gym101502 I.Move Between Numbers-最短路(Dijkstra优先队列版和数组版)
I. Move Between Numbers time limit per test 2.0 s memory limit per test 256 MB input standard inpu ...