主要内容:

第一部分 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配置文件能够看到,运行机注冊的入口在TBScheduleManagerFactoryinit方法,代码片段:

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。并实现selectTasksexecute方法,具体演示样例:

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原理与应用的更多相关文章

  1. 详解应对平台高并发的分布式调度框架TBSchedule

    转载: 详解应对平台高并发的分布式调度框架TBSchedule

  2. 开源调度框架Quartz最佳实践

    开源调度框架Quartz最佳实践 Quartz是一个Java调度框架,当前的最新版本为2.2.1. 以Quartz 2.2.1版为例,Quartz最佳实践(用于生产系统)总结如下: 1.跳过更新检查Q ...

  3. 深入理解分布式调度框架TBSchedule及源码分析

    简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...

  4. Java线程池管理及分布式Hadoop调度框架搭建

    平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发工程师却在这个上面吃了不少苦头. 怎么做一套简便的线程开发模 ...

  5. niubi-job:一个分布式的任务调度框架设计原理以及实现

    niubi-job的框架设计是非常简单实用的一套设计,去掉了很多其它调度框架中,锦上添花但并非必须的组件,例如MQ消息通讯组件(kafka等).它的框架设计核心思想是,让每一个jar包可以相对之间独立 ...

  6. 组件化框架设计之阿里巴巴开源路由框架——ARouter原理分析(一)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 背景 当项目的业务越来越复杂,业务线越来越多的时候,就需要按照业 ...

  7. 分布式调度框架TBSchedule使用方法

    一.TBSchedule简介 TBSchedule是来自淘宝的分布式调度开源框架,基于Zookeeper纯Java实现,其目的是让一种批量任务或者不断变化的任务,能够被动态的分配到多个主机的JVM中的 ...

  8. 淘宝开源任务调度框架tbschedule

    背景 分布式任务调度是非常常见的一种应用场景,一般对可用性和性能要求不高的任务,采用单点即可,例如linux的crontab,spring的quarz,但是如果要求部署多个节点,达到高可用的效果,上面 ...

  9. 美团分布式定时调度框架XXL-Job基本使用

    一:XXL JOB 基本使用 1.官方中文文档:https://www.xuxueli.com/xxl-job/ 2.基本环境: 2.1:git下载项目, 执行xxl-job数据库初始化脚本 2.2: ...

随机推荐

  1. bzoj 3203 凸包+三分

    题目大意 具体自己看吧link 读入n,D,表示n关 大概就是第i关有i只僵尸排成一队来打出题人 最前面那只是编号为\(i\)的僵尸,最后面的一只是编号为\(1\)的僵尸 最前面的僵尸离出题人\(X_ ...

  2. Session挂起

    异常信息: toString() unavailable - no suspended threads 使用Spring管理 ,在使用hibernate时使用如下语句Session session = ...

  3. SEO总结(一)

  4. 转 C++ 面向对象程序设计的基本特点

    传送门 Miss it   C++ 面向对象程序设计的基本特点 First: 抽象 面向对象方法中的抽象,是指对具体问题(对象)进行概括,抽出一类对象公共性质并加以描述的过程. 抽象的过程,也是对问题 ...

  5. 记录vim经常使用的几个命令

    vi/vim 基本使用方法 vi编辑器是所有Unix及Linux系统下标准的编辑器. $ vim 1.txt 以vi打开一个文件就直接进入一般模式了(这是默认的模式).在这个模式中, 你可以使用上下左 ...

  6. 三、 java运算符与流程控制

    赋值运算 赋值运算符:=,+=,-=,×=,/=,%= class fuzhiyunsuan{ public static void main(String[] args){ int i1 = 10; ...

  7. PHP连接MySQL报错"No such file or directory"的解决办法

    好下面说一下连接MYSQL数据库时报错的解决办法. 1,首先确定是mysql_connect()和mysql_pconnect()的问题,故障现象就是函数返回空,而mysql_error()返回“No ...

  8. [转]常用iOS图片处理方法

    自:http://blog.sina.com.cn/s/blog_8988732e0100xcx1.html  ========== (one) UIImage 图像 等比例缩放=========== ...

  9. NoSQL数据库 Couchbase Server - 分布式缓存

    Couchbase Server (前身是 Membase) 是一个分布式的面向文档的 NoSQL 数据库管理系统,该系统联合了 CouchDB 的简单和可靠以及 Memcached 的高性能以及 M ...

  10. 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 ...