一、Quartz概念
Quartz是一個(gè)優(yōu)秀的任務(wù)調(diào)度框架, 具有以下特點(diǎn):
- 強(qiáng)大的調(diào)度功能,例如支持豐富多樣的調(diào)度方法,可以滿足各種常規(guī)及特殊需求;
- 負(fù)載均衡
- 高可用
調(diào)度器:scheduler
任務(wù)調(diào)度的控制器,負(fù)責(zé)定時(shí)任務(wù)的調(diào)度,并且提供任務(wù)和觸發(fā)器的增刪改查等api方法。
任務(wù):job
job是實(shí)際被調(diào)度的任務(wù),每個(gè)任務(wù)必須指定具體執(zhí)行任務(wù)的實(shí)現(xiàn)類,實(shí)現(xiàn)類需要繼承QuartzJobBean或者實(shí)現(xiàn)org.quartz.Job接口,具體的業(yè)務(wù)邏輯寫在execute方法里面。
是否支持并發(fā)的注解:@DisallowConcurrentExecution
觸發(fā)器:trigger
trigger用來定義調(diào)度時(shí)間的概念,即按什么樣時(shí)間規(guī)則去觸發(fā)任務(wù)。主要幾種類型:
- SimpleTrigger:簡(jiǎn)單觸發(fā)器,從某個(gè)時(shí)間開始,每隔多少時(shí)間觸發(fā),重復(fù)多少次。
- CronTrigger:使用cron表達(dá)式定義觸發(fā)的時(shí)間規(guī)則,如"0 0 0,2,4 1/1 * ? *" 表示每天的0,2,4點(diǎn)觸發(fā)。
- DailyTimeIntervalTrigger:每天中的一個(gè)時(shí)間段,每N個(gè)時(shí)間單元觸發(fā),時(shí)間單元可以是毫秒,秒,分,小時(shí)
- CalendarIntervalTrigger:每N個(gè)時(shí)間單元觸發(fā),時(shí)間單元可以是毫秒,秒,分,小時(shí),日,月,年。
trigger狀態(tài):
-WAITING,
- ACQUIRED,
- EXECUTING,
- COMPLETE,
- BLOCKED,
- ERROR,
- PAUSED,
- PAUSED_BLOCKED,
- DELETED
Scheduler 調(diào)度線程主要有兩個(gè): 執(zhí)行常規(guī)調(diào)度的線程,和執(zhí)行 misfired trigger 的線程。常規(guī)調(diào)度線程輪詢存儲(chǔ)的所有 trigger,如果有需要觸發(fā)的 trigger,即到達(dá)了下一次觸發(fā)的時(shí)間,則從任務(wù)執(zhí)行線程池獲取一個(gè)空閑線程,執(zhí)行與該 trigger 關(guān)聯(lián)的任務(wù)。Misfire 線程是掃描所有的 trigger,查看是否有 misfired trigger,如果有的話根據(jù) misfire 的策略分別處理。
未正常觸發(fā)的任務(wù):misfire job
沒有在正常觸發(fā)時(shí)間點(diǎn)觸發(fā)的任務(wù)。主要由一下幾種情況導(dǎo)致:
- 觸發(fā)時(shí)間在應(yīng)用不可用的時(shí)間內(nèi),比如重啟
- 上次的執(zhí)行時(shí)間過長(zhǎng),超過了下次觸發(fā)的時(shí)間
- 任務(wù)被暫停一段時(shí)間后,重新被調(diào)度的時(shí)間在下次觸發(fā)時(shí)間之后
處理misfire job的策略,需要在創(chuàng)建trigger的時(shí)候配置,每種trigger對(duì)應(yīng)的枚舉值都不同,具體在接口里面有定義。CronTrigger有2種處理misfire的策略:
處理策略 | 描述 |
---|---|
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW | 立即觸發(fā)一次 |
MISFIRE_INSTRUCTION_DO_NOTHING | 忽略,不處理,等待下次觸發(fā) |
之間的關(guān)系:
scheduler由工廠類SchedulerFactory創(chuàng)建,主要負(fù)責(zé)job和trigger的持久化管理,包括新增、刪除、修改、觸發(fā)、暫停、恢復(fù)調(diào)度、停止調(diào)度等;
一個(gè)job可以關(guān)聯(lián)多個(gè)trigger,但是一個(gè)trigger只能關(guān)聯(lián)一個(gè)job。
Quzrtz執(zhí)行原理
單機(jī)模式
單機(jī)模式基本使用
(TODO)
單機(jī)模式原理分析
- scheduler是一個(gè)計(jì)劃調(diào)度器容器(總部),容器里面可以盛放眾多的JobDetail和trigger,當(dāng)容器啟動(dòng)后,里面的每個(gè)JobDetail都會(huì)根據(jù)trigger按部就班自動(dòng)去執(zhí)行。
- JobDetail是一個(gè)可執(zhí)行的工作,它本身可能是有狀態(tài)的。
- Trigger代表一個(gè)調(diào)度參數(shù)的配置,什么時(shí)候去調(diào)。
4.當(dāng)JobDetail和Trigger在scheduler容器上注冊(cè)后,形成了裝配好的作業(yè)(JobDetail和Trigger所組成的一對(duì)兒),就可以伴隨容器啟動(dòng)而調(diào)度執(zhí)行了。 - scheduler是個(gè)容器,容器中有一個(gè)線程池,用來并行調(diào)度執(zhí)行每個(gè)作業(yè),這樣可以提高容器效率。
集群模式
Quartz的集群模式指的是一個(gè)集群下多個(gè)節(jié)點(diǎn)管理同一批任務(wù)的調(diào)度,通過共享數(shù)據(jù)庫(kù)的方式實(shí)現(xiàn),保證同一個(gè)任務(wù)到達(dá)觸發(fā)時(shí)間的時(shí)候,只有一臺(tái)機(jī)器去執(zhí)行該任務(wù)。每個(gè)節(jié)點(diǎn)部署一個(gè)單獨(dú)的quartz實(shí)例,相互之間沒有直接數(shù)據(jù)通信。
集群模式基本使用
(TODO)
集群模式原理分析
quartz集群是通過數(shù)據(jù)庫(kù)表來感知其他的應(yīng)用的,各個(gè)節(jié)點(diǎn)之間并沒有直接的通信。只有使用持久的JobStore才能完成Quartz集群。
數(shù)據(jù)庫(kù)表:以前有12張表,現(xiàn)在只有11張表,現(xiàn)在沒有存儲(chǔ)listener相關(guān)的表,多了QRTZ_SIMPROP_TRIGGERS表:
Table name | Description |
---|---|
QRTZ_CALENDARS | 存儲(chǔ)Quartz的Calendar信息 |
QRTZ_CRON_TRIGGERS | 存儲(chǔ)CronTrigger,包括Cron表達(dá)式和時(shí)區(qū)信息 |
QRTZ_FIRED_TRIGGERS | 存儲(chǔ)與已觸發(fā)的Trigger相關(guān)的狀態(tài)信息,以及相聯(lián)Job的執(zhí)行信息 |
QRTZ_PAUSED_TRIGGER_GRPS | 存儲(chǔ)已暫停的Trigger組的信息 |
QRTZ_SCHEDULER_STATE | 存儲(chǔ)少量的有關(guān)Scheduler的狀態(tài)信息,和別的Scheduler實(shí)例 |
QRTZ_LOCKS | 存儲(chǔ)程序的悲觀鎖的信息 |
QRTZ_JOB_DETAILS | 存儲(chǔ)每一個(gè)已配置的Job的詳細(xì)信息 |
QRTZ_SIMPLE_TRIGGERS | 存儲(chǔ)簡(jiǎn)單的Trigger,包括重復(fù)次數(shù)、間隔、以及已觸的次數(shù) |
QRTZ_BLOG_TRIGGERS | Trigger作為Blob類型存儲(chǔ) |
QRTZ_TRIGGERS | 存儲(chǔ)已配置的Trigger的信息 |
QRTZ_SIMPROP_TRIGGERS |
QRTZ_LOCKS就是Quartz集群實(shí)現(xiàn)同步機(jī)制的行鎖表,包括以下幾個(gè)鎖:
- CALENDAR_ACCESS
- JOB_ACCESS
- MISFIRE_ACCESS
- STATE_ACCESS
- TRIGGER_ACCESS
負(fù)責(zé)任務(wù)調(diào)度的幾個(gè)線程:
(1)任務(wù)執(zhí)行線程:通常使用一個(gè)線程池(SimpleThreadPool)維護(hù)一組線程,負(fù)責(zé)實(shí)際每個(gè)job的執(zhí)行。
(2)Scheduler調(diào)度線程QuartzSchedulerThread :輪詢存儲(chǔ)的所有 trigger,如果有需要觸發(fā)的 trigger,即到達(dá)了下一次觸發(fā)的時(shí)間,則從任務(wù)執(zhí)行線程池獲取一個(gè)空閑線程,執(zhí)行與該 trigger 關(guān)聯(lián)的任務(wù)。
(3)處理misfire job的線程MisfireHandler:輪訓(xùn)所有misfire的trigger,原理就是從數(shù)據(jù)庫(kù)中查詢所有下次觸發(fā)時(shí)間小于當(dāng)前時(shí)間的trigger,按照每個(gè)trigger設(shè)定的misfire策略處理這些trigger。