论坛首页 Java企业应用论坛

quartz和应用的集群问题

浏览 18723 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-08-21  
    之前看到很多关于quartz的讨论,尤其是关于quartz和集群应用的讨论是非常的激烈,很多人都共享了自己的想法,很多基本上比较统一的观点是重新启动一个job server,用来跑job,然后把这个job server独立在web container之外启动。然后各节点如果需要启动任务那么就通过db或jms来通知job server。这个方法是robbin大哥提出的,原贴见http://www.iteye.com/topic/40970,第8楼。用这种方法比较好的处理了quartz和应用集群问题。
     为了更好的说明这个问题,我画了一张图:
见图qu2

    首先请大家原谅,这个图是我用visio画的,画的不咋滴(上次收到pd的警告信之后不敢再用pd了),大概就是这个样子吧,如果理解有误请大家指出来啊。这种情况下jobserver也可以看作是一个node,如果定时任务很多的话就有问题了,因为所有的任务都会在这个节点上运行。

第二种方案
    在上面的基础上,我想到,能不能通过轻量级远程调用和quartz结合起来,也是把任务定时跑到一个jobserver上,但是正真跑任务还是在web节点上,那么如何实现呢,我也来详细讲解一下自己的想法。
1, 独立出一个job server,这个server上跑一个spring+quartz的应用,这个应用专门用来启动任务。
2, 在jobserver上加上hessain,得到业务接口,这样jobserver就可以调用web container中的业务操作,也就是正真执行任务的还是在cluster中的tomcat。
3, 在jobserver上配置cluster上各节点的地址,即各tomcat的hessian。他们的业务接口都是一样的,只不过地址是不一样的。
4, 在jobserver启动定时任务之后,轮流调用各地址上的业务操作(类似apache分发tomcat一样),这样可以让不同的定时任务在不同的节点上运行,减低了一台某个node的压力(我觉得这个优点是一个比较重要的优点,尤其是定时任务比较重的情况下)。
让我们来看看图示:
见图qu1

    我觉得这种方式对jobserver来说就比较简单了,它只需要考虑调用谁谁谁,不需要把node上的应用部署到JobServer上去,但是有优点肯定就有缺点(用易中天的话说:喜欢的人越多,反对的声浪也越高),我们再来看看这种方式的缺点:
1 即使是用了hessain也可以象上面那种方式jobserver是一个单独的虚拟机实例,不在web container中。当然我们也可以用RMI来代替,而且RMI的速度比hessian快得多,但是显然带来的是开发上更多的复杂性,RMI环境的配置非常麻烦,而且在网络端口方面也存在一些问题,如防火墙的问题等。
2 网络延迟问题,如果是时间要求比较精准的任务用这种方案就不合适了,因为hessain调用是有网络延迟的时间的,数量级从十到百不等,单位十毫秒。尤其是第一次调用,可能需要1秒钟,如果在同一台机器上第一次调用大概是300-600毫秒。
3 需要再做一个额外的web应用,就是做一个基于web的jobserver(不过这一条也不一定是缺点)

      这两种方法事实上都没有把quart集群起来,虽然应用是集群了,但是jobserver还是只有一个。第一种方案只能在jobserver中执行定时操作,第二种方法还是在集群的各节点中执行定时操作。在这两种情况下,只要jobserver挂了,整个定时的任务就挂了。

      或者我们也可以把这些单独的jobserver集群起来,比如在第一种情况下再部署一个jobserver,通过数据库中的表的记录的锁定与否来判断这条任务是否在执行,这种情况下需要两个jobserver的时间一定要保持一致,因为如果有一个时间差,定时任务就有可能被执行两遍了。而且同一个应用就需要被部署多次,保存部署到jobserver上,如果在第二种情况下做集群,那么没有业务操作的jobserver集群起来应该是非常轻松的,但是还是有同样的问题,就是时间差不能太大,否则应用又会被调用多次。而且这两个方案的集群都需要数据库的支持(不过没有数据库还真不知道如何做到定时操作的集群了),这种方案要实现起来就需要另写文章仔细叙述了。

第三种情况:
     quartz本身事实上也是支持集群的。在这种方案下,cluster上的每一个node都在跑quartz,然后也是通过数据中记录的状态来判断这个操作是否正在执行,这就要求cluster上所有的node的时间应该是一样的。而且每一个node都跑应用就意味着每一个node都需要有自己的线程池来跑quartz(俺反而觉得这样做比较累赘)。
见图qu3


     这种方式也有一个很大的优点,就是不同的node可能会执行的不同的定时任务,这个要看服务器的时间设定了,可能node1执行一个任务,此时node2会执行另一个任务,这样做会比较好的做到负载均衡,而且也能比较好的做到容错,一个node挂了,不会
影响到其他node上的定时任务。每个node上的quartz定期的向数据库里登记它们的时
间,如果某个实例在一定的时间内没有登记,就表示这个实例挂了 ,其它的实例就会重新获取这个挂了的实例所执行的任务。

总结一下:
从上面的描述看来,3种方法都各有优点和缺点。我觉得不同的情况下应该选择自己项目最合适的方案。以上只不过是我自己天马行空想出来了,估计有些地方有问题,欢迎大家探讨一下这个问题。


  • 大小: 13 KB
  • 大小: 12.6 KB
  • 大小: 10.7 KB
   发表时间:2007-08-22  
你想的太多了,其实quartz已经把很多事情作完了。
正如他的文档描述的
你可以做jvm级的,使用rmi的cluster server,只需要配置一下xml。
0 请登录后投票
   发表时间:2007-08-22  
cacodemon 写道
你想的太多了,其实quartz已经把很多事情作完了。
正如他的文档描述的
你可以做jvm级的,使用rmi的cluster server,只需要配置一下xml。

我到不觉得我想太多了,而且第一种情况也不是我想出来的。
你说的情况就是文中所提的第3种情况,第3种情况有自己固有的缺点啊。
见正文,你的观点好像是不管什么情况,第3种方式一定是最合适的?
0 请登录后投票
   发表时间:2007-08-22  
那个讨论是老黄历了

另外没看出方案3有什么缺点


1 请登录后投票
   发表时间:2007-08-22  
loki 写道
那个讨论是老黄历了

另外没看出方案3有什么缺点





首先说明一下老贴不代表没有价值

虽然第3种情况既能做到负载均衡,也能做到容错,但是也是有点代价的。
我觉得第3种方案有如下的缺点:
quartz需要使用jdbc-jobstore,quartz本身的性能减低。
所有节点所在机器的时间相差必须在一秒之内。
如果还有其他没有集群的quartz的话不能用这个jdbc-jobstore,不然可能会出问题。
所有的节点(web应用)都需要跑quartz实例,那么每个节点上都需要额外的线程池,而且参照前人的经验,如果考虑不周,
可能会导致servlet资源不能释放的问题。
还有一个是实现起来比较繁琐。
0 请登录后投票
   发表时间:2007-08-23  
ahuaxuan 写道
loki 写道
那个讨论是老黄历了

另外没看出方案3有什么缺点





首先说明一下老贴不代表没有价值

虽然第3种情况既能做到负载均衡,也能做到容错,但是也是有点代价的。
我觉得第3种方案有如下的缺点:
quartz需要使用jdbc-jobstore,quartz本身的性能减低。
所有节点所在机器的时间相差必须在一秒之内。
如果还有其他没有集群的quartz的话不能用这个jdbc-jobstore,不然可能会出问题。
所有的节点(web应用)都需要跑quartz实例,那么每个节点上都需要额外的线程池,而且参照前人的经验,如果考虑不周,
可能会导致servlet资源不能释放的问题。
还有一个是实现起来比较繁琐。


我所说的不是这几种,因为不会用到tomcat cluster,而是jvm cluster,也是quartz自己提供的,所以不存在servlet资源不能释放的问题。
既它的文档上说的
quartzServerC1.properties:
org.quartz.scheduler.instanceName = QuartzServer
org.quartz.scheduler.instanceId = ONE

quartzServerC2.properties:
org.quartz.scheduler.instanceName = QuartzServer
org.quartz.scheduler.instanceId = TWO
这样就是他的cluster最简单的配置,当然你还需要配置她的Datasource,如果你需要及时提交job,那你还需要加上
org.quartz.scheduler.rmi.export = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1198
org.quartz.scheduler.rmi.serverPort = 0
org.quartz.scheduler.rmi.createRegistry = true
之类的,然后自己写个web应用或其他的来call他的rmi接口
0 请登录后投票
   发表时间:2007-08-23  
jobserver作为hessian客户端,不需要是web容器吧?
0 请登录后投票
   发表时间:2007-08-28  
cacodemon 写道
我所说的不是这几种,因为不会用到tomcat cluster,而是jvm cluster,也是quartz自己提供的,所以不存在servlet资源不能释放的问题。
既它的文档上说的
quartzServerC1.properties:
org.quartz.scheduler.instanceName = QuartzServer
org.quartz.scheduler.instanceId = ONE

quartzServerC2.properties:
org.quartz.scheduler.instanceName = QuartzServer
org.quartz.scheduler.instanceId = TWO
这样就是他的cluster最简单的配置,当然你还需要配置她的Datasource,如果你需要及时提交job,那你还需要加上
org.quartz.scheduler.rmi.export = true
org.quartz.scheduler.rmi.registryHost = localhost
org.quartz.scheduler.rmi.registryPort = 1198
org.quartz.scheduler.rmi.serverPort = 0
org.quartz.scheduler.rmi.createRegistry = true
之类的,然后自己写个web应用或其他的来call他的rmi接口


刚才google了一下,发现网上并没有quartz在jvm级别做集群得描述,
http://wiki.opensymphony.com/display/QRTZ1/ConfigRMI,这个页面是关于rmi配置的,在这里我丝毫没有看到cluster这个字眼。
http://wiki.opensymphony.com/display/QRTZ1/ConfigJDBCJobStoreClustering,这个页面是我所描述得关于jdbcjobstore的描述。
而且你说到
cacodemon 写道
当然你还需要配置她的Datasource

从上面那个连接来看,这个datasource的作用其实就是支持我说的第三种方案。
而且在用jdbcjobstore做集群的时候就是需要配置:
quartzServerC1.properties:
org.quartz.scheduler.instanceName = QuartzServer
org.quartz.scheduler.instanceId = ONE

quartzServerC2.properties:
org.quartz.scheduler.instanceName = QuartzServer
org.quartz.scheduler.instanceId = TWO
还有datasource,这些配置不是用到什么“jvm级别”的集群上的,却是在使用jdbcjobstore做集群时所需的配置
你说了用rmi做jvm级别的集群我认为并不存在,除非你拿出证据来,或者证明你确实这样做过

daquan198163 写道
jobserver作为hessian客户端,不需要是web容器吧?

你说的对,不过我是想如果可以的话可以做一个web端来监控quartz执行的状态,当然如果不需要这样做的话可以不用web容器。
0 请登录后投票
   发表时间:2007-08-28  
我感觉第一种方式是比较实用, job业务逻辑, 一般都是比较独立或特殊的, 就算跟前端web的业务有重复, 拷贝一个jar过来, 也是很方便的.

重要得是, 控制在时间程序上的投入.
0 请登录后投票
   发表时间:2007-08-30  
galaxystar 写道
我感觉第一种方式是比较实用, job业务逻辑, 一般都是比较独立或特殊的, 就算跟前端web的业务有重复, 拷贝一个jar过来, 也是很方便的.

重要得是, 控制在时间程序上的投入.

第一种方案在不集群的情况下不能负载均衡啊,我还是认为这种三种方案应该是有不同的使用场景,应该试情况而定
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics