隨着業務量的增長,單機版Quartz已經難以應對分佈式任務管理的需求,此時集群版Quartz就迎刃而解了。集群版Quartz的優點是可以將多台機器作為工作節點來執行任務,這個方案可以提高任務的可靠性、性能和吞吐量。接下來,將從多個方面詳細介紹集群版Quartz的實現原理和使用方法。
一、配置文件
Quartz集群的配置可以放在屬性文件中,集群中每個節點都需要使用相同的配置文件。下面是一個簡單的示例:
org.quartz.scheduler.instanceName = MyClusteredScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 20000 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 25 org.quartz.threadPool.threadPriority = 5
其中,”org.quartz.scheduler.instanceName”和”org.quartz.scheduler.instanceId”是必須的。
二、消息通訊
Quartz集群依靠JDBC或者RMI方式進行消息通訊,以實現不同節點之間的任務調度信息共享。在消息通訊的過程中,需要注意下面的事項:
1、消息通訊組件不能夠出現重複id的節點;
2、消息通訊組件的狀態一定要準確。
同時,集群中所有節點的數據庫連接信息必須相同。
三、任務執行原則
在Quartz集群模型中,所有的任務都必須實現Job接口,並且該接口應該是StatefulJob的子接口。StatefulJob接口要求任務必須是有狀態的並且支持並發執行。這個要求是Quartz集群正常運行必須遵守的規則,並且可以通過實現StatefulJob接口來實現。
為了確保任務被正確分配到集群中各個節點,我們需要在任務類的添加註解@PersistJobDataAfterExecution。這個註解會在執行任務之前保存任務當前狀態,並在任務執行完成後更新狀態到數據庫。這種方式可以確保任務能夠正確的在不同節點之間傳遞。
四、任務負載均衡
任務負載均衡是Quartz集群中特別重要的一個方面。Quartz使用平衡負載策略以確保在集群中任務的平衡的分配。
四種負載均衡策略如下:
1、默認的負載均衡策略:按照最近的一次執行時間靠前的優先被執行;
2、Round Robin策略:所有節點輪流執行任務,每個節點會輪流執行一次。
3、隨機策略:隨機挑選一個節點去執行任務。
4、基於權重的策略:按照節點配置的權重來分配任務,權重大的節點分配到的任務數量也會比較多。
下面是一個TaskDispatchSelector的示例,可以用來選擇節點:
public class TaskDispatchSelector implements LoadBalanceTaskDispatcher{ public void dispatchTask(List ctxs) { JobExecutionContext selectedContext = null; try { //...... //根據權重選擇節點 selectedContext = new WeightedLoadBalancedScheduler().instanceIdSchedulerMap.entrySet().stream().max(Comparator.comparingInt((entry) -> entry.getValue().getThreadPool().getBusyThreadCount())).get().getValue().getContext(); //...... selectedContext.getScheduler().triggerJob(selectedContext.getJobDetail().getKey()); } catch (Exception e) { throw new MyException("Dispatch Quartz Task Fail.", e); } } }
五、運行模式
可以在兩種運行模式之間切換:
1、只讀模式:節點向集群中獲取任務並執行。
2、讀寫模式:節點不僅獲取任務,還會去分配或者刪除任務。
可以使用JobStoreCMT來實現讀寫模式。下面是一個JobFactory實現的示例:
public class JobFactory extends AdaptableJobFactory { @Autowired ApplicationContext applicationContext; /** * 實例化任務類 * @param bundle * @param method * @return * @throws Exception */ protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { JobDetail jobDetail = bundle.getJobDetail(); Class jobClass = jobDetail.getJobClass(); return applicationContext.getBean(jobClass); } }
六、集群初始化及關閉
對於集群的初始化,需要確保所有節點都按照相同的配置啟動JobScheduler。關閉集群時需要調用shutdown()方法,不要在代碼中手動關閉Scheduler。
下面是一個啟動和關閉Quartz集群的示例:
public class QuartzClusterRunner { public void start() { try { // 初始化Quartz SchedulerFactory sf = new StdSchedulerFactory("quartz.properties"); Scheduler scheduler = sf.getScheduler(); //監聽Quartz scheduler的啟動與關閉事件,和job調度事件 scheduler.getListenerManager().addSchedulerListener(new MySchedulerListenerAdapter()); scheduler.start(); LOGGER.info("Quartz Scheduler started..."); } catch (Throwable e) { LOGGER.error("Quartz Scheduler start error: {}", e.getMessage(), e); } } public void stop() { try { LOGGER.info("Shutting Quartz Scheduler down..."); SchedulerFactory sf = new StdSchedulerFactory(); //注意這裡沒有指定屬性文件 Scheduler scheduler = sf.getScheduler(); scheduler.shutdown(); LOGGER.info("Quartz Scheduler shut down."); } catch (Throwable e) { LOGGER.error("Quartz Scheduler stop error: {}", e.getMessage(), e); } } }
致謝
本文檔參考了官方文檔和網上的一些文章,特此致謝:
1、Quartz官方文檔:
http://www.quartz-scheduler.org/
2、博客:
http://blog.csdn.net/endymionwang/article/details/7329144
http://gold.xitu.io/entry/5691b98c60b2ff006f6d741d
原創文章,作者:MSZXV,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/371817.html