1. 程式人生 > >美團技術團隊 Quartz應用與叢集原理分析

美團技術團隊 Quartz應用與叢集原理分析

一、問題背景

美團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。

三、為什麼選擇Quartz