Quartz的问题

1. 任务创建者同时也是执行者之一

现象

有时候我们的任务是动态创建的,并且为了友好,会提供界面创建定时任务。这个创建任务的动作往往是放在一个管理后台系统进行,但是我们不希望这个系统因为创建了Quartz任务就作为运行实例参与到任务的调度执行了。Quartz是一个去中心化的实现,没有区分任务创建者和任务执行者,任何Quartz实例都同时兼顾两种身份。

解决方案

Quartz支持RMI调用,可以在管理后台通过RMI让集群中的任何实例创建任务。当然,也可以通过其他RPC方式调用。

缺点

相对比较麻烦。另外,RPC调用在有多台机器的时候负载均衡比较麻烦。

2. 不支持子集群

现象

有时候我们希望任务能够隔离,比如 A和B这两个Quartz实例专门跑监控任务,C、D、E专门跑网页抓取任务。这样可以做到一定程度(粒度)上的隔离。而不是所有的实例都参与到所有的任务中去。

解决方案

配置同一个jobStore.dataStore和jobStore.tablePrefix的实例会抢任务表的中的任务。所以一种解决方案就是针对不同的子集群配置不同的jobStore.dataStore和jobStore.tablePrefix。也就是说让同一个集群的实例到同一套Quartz表,不同集群的到不同的Quartz表去。

缺点

Quartz表需要预先创建,并且不能统一监控。

3. 不能指定具体运行实例

现象

有时候,我们就想让某个任务在某个实例上执行。比如灰度,比如方便出问题的时候明确定位。

解决方案

使用非集群的方式,另外,为了方便,可能会使用RAM dataStore。

缺点

单点,没有出错fail over机制。另外,采用RAM DataStore没有任务持久化。

4. 没有任务执行进度和结果展示和监控

现象

Quartz表有任务的状态,但是提供的API确实实例级别的。比如通过某个scheduler判断一个job是否在运行,是只是针对这个scheduler调度过的,不是整个集群。原因还是跟Quartz的去中心化设计有关,没有像Hadoop的JobTracker一样的总调度和协调者。

那么hadoop?

Hadoop也是一个任务调度框架。但是它的定位是map-reduce任务。所以有如下一些缺点:

  1. 不支持Quartz一样丰富的定时执行
  2. 任务模型是Map-Reduce计算模型
  3. 用户提交的是代码,移动的是代码,消息使用HDFS作为传输介质

Why not combine them?

所以可以结合两者的优点,重新设计一个任务调度和执行框架。

另外,如果做到像hadoop那样的话,那么其实就是一个容器了,不仅仅是一个调度框架了,用户提交的是executor接口的实现,然后平台将代码分发到某个实例执行。也就是说JobExecutor机器没有特殊的业务逻辑,是纯粹的执行容器。而且Hadoop的任务之间默认是在各自的JVM运行,这样任务之间不会互相影响。当然,性能有一定的损失。

如果把思路放大,其实跑的可以是任何逻辑,不一定是定时任务。比如RPC框架,API容器。不过要解决的问题是用户上传代码的依赖问题。

B2B的”钟楼”?可以在页面看到所有任务,并且点击立即运行,cool!

实现

树状结构,使用zookeeper作为存储?

实例图:

  • clusterA |— instanceA |— instanceB
  • clusterB |— instanceC

任务分配图:

  • taskC
  • clusterA |— taskA (指定集群的任务) |— instanceB |— taskB (指定实例的任务)
  • clusterB |— taskD

任务运行状态图:

  • clusterA |— instanceA |— taskA |— instanceB |— taskB
  • clusterB |— instanceC |— taskC