美團技術團隊 Quartz應用與叢集原理分析
阿新 • • 發佈:2019-02-11
一、問題背景
美團CRM系統中每天有大量的後臺任務需要排程執行,如構建索引、統計報表、週期同步資料等等,要求任務排程系統具備高可用性、負載均衡特性,可以管理並監控任務的執行流程,以保證任務的正確執行。
二、歷史方案
美團CRM系統的任務排程模組經歷了以下歷史方案。
1. Crontab+SQL
每天晚上執行定時任務,通過SQL指令碼+crontab方式執行,例如,
#crm 0 2 * * * /xxx/mtcrm/shell/mtcrm_daily_stat.sql //每天凌晨2:00執行統計 30 7 * * * /xxx/mtcrm/shell/mtcrm_data_fix.sql //每天早上7:30執行資料修復
該方案存在以下問題:
- 直接訪問資料庫,各系統業務介面沒有重用。
- 完成複雜業務需求時,會引入過多中間表。
- 業務邏輯計算完全依賴SQL,增大資料庫壓力。
- 任務失敗無法自動恢復。
2. Python+SQL
採用python指令碼(多資料來源)+SQL方式執行,例如,
def connectCRM(): return MySQLdb.Connection("host1", "uname", "xxx", "crm", 3306, charset="utf8") def connectTemp(): return MySQLdb.Connection("host1", "uname", "xxx", "temp", 3306, charset="utf8")
該方案存在問題:
- 直接訪問資料,需要理解各系統的資料結構,無法滿足動態任務問題,各系統業務介面沒有重用。
- 無負載均衡。
- 任務失敗無法恢復。
- 在JAVA語言開發中出現異構,且很難統一到自動部署系統中。
3. Spring+JDK Timer
該方案使用spring+JDK Timer方式,呼叫介面完成定時任務,在分散式部署環境下,防止多個節點同時執行任務,需要寫死host,控制在一臺伺服器上執行task。
<bean id="accountStatusTaskScanner" class="xxx.crm.service.impl.AccountStatusTaskScanner" /> <task:scheduler id="taskScheduler" pool-size="5" /> <task:scheduled-tasks scheduler="taskScheduler"> <task:scheduled ref="accountStatusTaskScanner" method="execute" cron="0 0 1 * * ?" /> </task:scheduled-tasks>
該方案較方案1,2有很大改進,但仍存在以下問題:
- 步驟複雜、分散,任務量增大的情況下,很難擴充套件
- 使用寫死伺服器Host的方式執行task,存在單點風險,負載均衡手動完成。
- 應用重啟,任務無法自動恢復。
CRM系統定時任務走過了很多彎路:定時任務多種實現方式,使配置和程式碼分散在多處,難以維護和監控;任務執行過程沒有保證,沒有錯誤恢復;任務執 行異常沒有反饋(郵件);沒有叢集支援、負載均衡。CRM系統需要分散式的任務排程框架,統一解決問題,Java可以使用的任務排程框架有 Quartz,Jcrontab,cron4j,我們選擇了Quartz。