由於工作原因,需要用到任務監控平台,經過一番摸索,發現了Quratz.net這個開源的作業調度框架。防止忘記,做個備忘。
1 Quartz.Net概述
開源組件Quartz.Net,這是一個開源的作業調度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#寫成,可用於winform和asp.net應用中。它提供了巨大的靈活性而不犧牲簡單性。能夠用它來為執行一個作業而創建簡單的或復雜的調度。
Quartz於很多特征,如:數據庫支持,集群,插件,支持cron-like表達式等等。
Quartz.net是一個開源的任務調度工具,相當於數據庫中的 Job、Windows 的計划任務、Unix/Linux 下的 Cron,但 Quartz 可以把排程控制的更精細,對任務調度的領域問題進行了高度的抽象,實現作業的靈活調度。
2 Quartz基本概念
Quartz由幾個基本的接口組成,如下圖:
Scheduler:
計划調度器,里面可以盛放眾多的JobDetail和trigger,當容器啟動后,里面的每個JobDetail都會根據trigger按部就班自動去執行。
Trigger:
觸發器,配置調度參數的配置,什么時候去調。描述觸發Job執行的時間觸發規則。主要有SimpleTrigger和CronTrigger這兩個子類。當僅需觸發一次或者以固定時間間隔周期執行,SimpleTrigger是最適合的選擇;而CronTrigger則可以通過Cron表達式定義出各種復雜時間規則的調度方案:如每早晨9:00執行,周一、周三、周五下午5:00執行等;
Job:
任務是一個接口,只有一個方法void execute(JobExecutionContext context),開發者實現該接口定義運行任務,JobExecutionContext類提供了調度上下文的各種信息。Job運行時的信息保存在JobDataMap實例中;
JobDetail:
可執行的工作,它本身可能是有狀態的。Quartz在每次執行Job時,都重新創建一個Job實例,所以它不直接接受一個Job的實例,相反它接收一個Job實現類,以便運行時通過newInstance()的反射機制實例化Job。因此需要通過一個類來描述Job的實現類及其它相關的靜態信息,如Job名字、描述、關聯監聽器等信息,JobDetail承擔了這一角色。
JobDataMap:
存放Job運行時的信息。
Calendar:
日歷功能,一個Trigger可以和多個Calendar關聯,以便排除或包含某些時間點。假設,我們安排每周星期一早上10:00執行任務,但是如果碰到法定的節日,任務則不執行,這時就需要在Trigger觸發機制的基礎上使用Calendar進行定點排除。
ThreadPool:
Scheduler使用一個線程池作為任務運行的基礎設施,任務通過共享線程池中的線程提高運行效率。
SchedulerContext:
調度器的上下文
3 Quartz運行原理
3.1 任務調度原理
啟動過程:
(1) 實例化一個調度器工廠SchedulerFactory,可以使用配置文件,或者代碼實現自定義的實例。
(2) 通過getScheduler()方法從調度器工廠里得到調度器實例
(3) Scheduler有一個QuartzSchedulerThread(Thread的子類)屬性,在scheduler實例化的時候,實例化了一個對象,並用ThreadExecutor啟動該線程對象。該線程就是調度線程,主要任務就是不停的從JobStore中獲取即將被觸發的觸發器(默認30s調度一次)。在這個時候調度線程雖然啟動,但是處於pause狀態。
調度過程:
(4) 通過scheduleJob()方法將任務和觸發器存儲在JobStore中,通過start()方法將QuartzSchedulerThread的pause狀態設為false,通知調度線程執行任務,此后調度線程不停的從JobStore中去取即將觸發的任務。
3.2 任務執行原理
(1) 調度線程首先去線程池中獲取可用的線程,如果沒有的話,就阻塞。
(2) 從JobStore(從存儲介質中獲取觸發器,存儲介質可以是內存也可以是數據庫)獲取(接下來30s內的)觸發器,然后等待該觸發器觸發。
(3) 調度線程創建一個JobRunShell(就是一個Runnable),然后從線程池中調用線程執行該任務。
獲取trigger、JobDetail以及生成Job實例,然后執行job的execute接口函數。
3.3 任務持久化
Quartz提供兩種基本作業存儲類型。第一種類型叫做RAMJobStore,第二種類型叫做JDBC作業存儲。在默認情況下Quartz將任務調度的運行信息保存在內存中,這種方法提供了最佳的性能,因為內存中數據訪問最快。不足之處是缺乏數據的持久性,當程序路途停止或系統崩潰時,所有運行的信息都會丟失。也不方便於集群處理,因此本模塊采用JDBC作業存儲的方案,Quartz.net支持多種數據庫進行任務持久化的存儲。
官方提供的各種數據庫腳本:https://github.com/quartznet/quartznet/tree/master/database/tables
3.4 Quartz表結構
1、QRTZ_JOB_DETAILS:存儲的是job的詳細信息,包括:[DESCRIPTION]描述,[IS_DURABLE]是否持久化,[JOB_DATA]持久化對象等基本信息。
2、QRTZ_TRIGGERS:觸發器信息,包含:job的名,組外鍵,[DESCRIPTION]觸發器的描述等基本信息,還有[START_TIME]開始執行時間,[END_TIME]結束執行時間,[PREV_FIRE_TIME]上次執行時間,[NEXT_FIRE_TIME]下次執行時間,[TRIGGER_TYPE]觸發器類型:simple和cron,[TRIGGER_STATE]執行狀態:WAITING,PAUSED,ACQUIRED分別為:等待,暫停,運行中。
3、QRTZ_CRON_TRIGGERS:保存cron表達式。
4、QRTZ_SCHEDULER_STATE:存儲集群中note實例信息,quartz會定時讀取該表的信息判斷集群中每個實例的當前狀態,INSTANCE_NAME:之前配置文件中org.quartz.scheduler.instanceId配置的名字,就會寫入該字段,如果設置為AUTO,quartz會根據物理機名和當前時間產生一個名字。 [LAST_CHECKIN_TIME]上次檢查時間,[CHECKIN_INTERVAL]檢查間隔時間。
5、QRTZ_PAUSED_TRIGGER_GRPS:暫停的任務組信息。
6、QRTZ_LOCKS,悲觀鎖發生的記錄信息。
7、QRTZ_FIRED_TRIGGERS,正在運行的觸發器信息。
8、QRTZ_SIMPLE_TRIGGERS,簡單的出發器詳細信息。
9、QRTZ_BLOB_TRIGGERS,觸發器存為二進制大對象類型(用於Quartz用戶自己觸發數據庫定制自己的觸發器,然而JobStore不明白怎么存放實例的時候)。
以上為Quartz.Net的基本原理。