之前看到很多关于quartz的讨论,尤其是关于quartz和集群应用的讨论是非常的激烈,很多人都共享了自己的想法,很多基本上比较统一的观点是重新启动一个job server,用来跑job,然后把这个job server独立在web container之外启动。然后各节点如果需要启动任务那么就通过db或jms来通知job server。这个方法是robbin大哥提出的,原贴见
http://www.iteye.com/topic/40970,第8楼。用这种方法比较好的处理了quartz和应用集群问题。
首先请大家原谅,这个图是我用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的压力(我觉得这个优点是一个比较重要的优点,尤其是定时任务比较重的情况下)。
我觉得这种方式对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(俺反而觉得这样做比较累赘)。
这种方式也有一个很大的优点,就是不同的node可能会执行的不同的定时任务,这个要看服务器的时间设定了,可能node1执行一个任务,此时node2会执行另一个任务,这样做会比较好的做到负载均衡,而且也能比较好的做到容错,一个node挂了,不会
影响到其他node上的定时任务。每个node上的quartz定期的向数据库里登记它们的时
间,如果某个实例在一定的时间内没有登记,就表示这个实例挂了 ,其它的实例就会重新获取这个挂了的实例所执行的任务。
总结一下:
从上面的描述看来,3种方法都各有优点和缺点。我觉得不同的情况下应该选择自己项目最合适的方案。以上只不过是我自己天马行空想出来了,估计有些地方有问题,欢迎大家探讨一下这个问题。
首先请大家原谅,这个图是我用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的压力(我觉得这个优点是一个比较重要的优点,尤其是定时任务比较重的情况下)。
我觉得这种方式对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(俺反而觉得这样做比较累赘)。
这种方式也有一个很大的优点,就是不同的node可能会执行的不同的定时任务,这个要看服务器的时间设定了,可能node1执行一个任务,此时node2会执行另一个任务,这样做会比较好的做到负载均衡,而且也能比较好的做到容错,一个node挂了,不会
影响到其他node上的定时任务。每个node上的quartz定期的向数据库里登记它们的时
间,如果某个实例在一定的时间内没有登记,就表示这个实例挂了 ,其它的实例就会重新获取这个挂了的实例所执行的任务。
总结一下:
从上面的描述看来,3种方法都各有优点和缺点。我觉得不同的情况下应该选择自己项目最合适的方案。以上只不过是我自己天马行空想出来了,估计有些地方有问题,欢迎大家探讨一下这个问题。