隨着業務量的增長,單機版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
微信掃一掃
支付寶掃一掃