
本文將從單機定時調度開始,循序漸進地帶領大家了解五福定制三層分發任務處理框架,
一、背景介紹
二、定時任務分類

2.1、單機任務
單機定時任務毫無疑問是在單臺機器上運行的定時任務,在業務量級不大,沒有進行分庫分表時,往往單機定時任務即可滿足業務需求,
從復雜度上來說,單機定時任務又可分為簡單的定時調度和定時調度+批處理兩種,
1、定時調度
在Spring中可以通過@Scheduled 來啟用定時任務,觸發的方式有兩種,分別是:cron 運算式和 fixedRated類配置引數,常用的案例:
// cron運算式
@Scheduled(cron="0 0/30 9-17 * * ?") //按cron規則執行,朝九晚五作業時間內每半小時
@Scheduled(cron="0 0 12 ? * WED") //按cron規則執行,表示每個星期三中午12點
// fixedRated類配置
@Scheduled(fixedRate=5000) //上一次開始執行時間點后5秒再次執行;
@Scheduled(fixedDelay=3000) //上一次執行完畢時間點后3秒再次執行;
@Scheduled(initialDelay=1000, fixedDelay=2000) //第一次延遲1秒執行,然后在上一次執行完畢時間點后2秒再次執行;

定時調度往往用于業務處理流程比較簡單的場景,比如定時生成簡單報表,發送通知,對于復雜耗時的場景,處理效率不高,業務高峰期會積壓大量待處理資料,影響業務,
2、定時調度+批處理
為了解決復雜耗時場景下定時調度效率不高的問題,可以引入批處理框架,定時調度與批處理框架相結合,可以大幅提高資料處理的效率,提升系統穩定性,保障業務穩定運行,
以Spring Batch批處理框架為例,任務處理流程如下:

Spring Batch批處理框架將任務拆分成多個Step,同時每個Step里面又分為itemReader,itemProcessor, itemWriter,通過將任務分層細化,能夠讓多個階段并行處理,提高任務處理效率,批處理框架結合定時調度框架,可以在單機情況下,對大量復雜的業務進行高效的批處理,
2.2、集群任務
在分庫分表大業務流量情況下,單機定時任務已無法滿足業務需求了,這時就產生了集群定時任務,在支付寶技術架構下,用戶資料按照eid進行分庫分表,同時進行Zone維度的隔離,此時單機定時任務無法對全量資料做處理,于是支付寶便有了自己的分布式任務調度中間件Antscheduler,配合三層分發任務處理框架,就可以對大量資料進行定時批量處理,
1、三層分發

2、五福定制三層分發

/**
* 根據配置中心的dataFlag過濾
* 1、默認ALL不區分
* 2、ODD 表示僅分發奇數表號
* 3、EVEN 標識僅分發偶數表號
*
* @param eidList
*/
public void filteByDataFlag(List<String> eidList) {
String dataFlag = SchedulerConfigDrmUtil.getIndexFilterFlag();
int strategy = -1;
if (StringUtil.equalsIgnoreCase("ODD", dataFlag)) {
strategy = 1;
} else if (StringUtil.equalsIgnoreCase("EVEN", dataFlag)) {
strategy = 0;
}
if (strategy == -1) {
// ALL
return;
}
// filter
Iterator<String> it = eidList.iterator();
while (it.hasNext()) {
String str = it.next();
int index = NumberUtils.toInt(str, -1);
if (index % 2 != strategy) {
it.remove();
}
}
}
通過代碼可知,推送任務配置時,將A組機器的值推成“ODD”,B組機器的值推成“EVEN”,即可實作A/B組的所有機器同時執行定時任務的效果,
/**
* 計算定時任務的相關配置
*
* 主要計算:
* scheduleSingleLimit 單機限流值
* scheduleLoaderCount loader撈取條數
*
* @param scheduleConfig
*/
public static SchedulerConfig calculateScheduleConfig(SchedulerConfig scheduleConfig) {
final int qpsLimit = scheduleConfig.getScheduleWholeLimit();
final int machineCounts = scheduleConfig.getScheduleMachineCounts();
MtLogger.info(LOGGER,
"【計算定時任務配置】-開始 任務名稱:{0},機器數量:{1},任務吞吐量:{2}.", scheduleConfig.getScheduleType(),
machineCounts, qpsLimit);
//定時任務的調度頻率是scheduleRate 秒執行一次 所以scheduleRate秒中內集群的整體吞吐量=qps限制*scheduleRate
final int scheduleRate = scheduleConfig.getScheduleRatePerSec();
long totalLoaderCounts = qpsLimit * TimeUnit.SECONDS.toSeconds(scheduleRate);
//定時任務撈取的表數量為1000 所以到每個表的限制=totalLoaderCounts/1000
long loaderCountPerTask = totalLoaderCounts / 1000;
if (loaderCountPerTask < 1) {
loaderCountPerTask = 1;
}
scheduleConfig.setScheduleLoaderCount((int) loaderCountPerTask);
//整體限流通過單機限流實作 整體限流=單機限流*machineCounts
final double singleQps = ((double) qpsLimit / machineCounts);
//創建的限流需要1秒的預熱
scheduleConfig.setScheduleSingleLimit(RateLimiter.create(singleQps, 1, TimeUnit.SECONDS));
MtLogger.info(LOGGER,
"【計算定時任務配置】-結束 任務名稱:{0},撈取條數:{1},單機限流:{2}.", scheduleConfig.getScheduleType(),
scheduleConfig.getScheduleLoaderCount(),
scheduleConfig.getScheduleSingleLimit().getRate());
return scheduleConfig;
}
通過代碼可知,推送的任務配置最侄訓生成兩個重要的配置資訊:

相比通常情況下指定Loader每次撈取的任務數,五福是通過集群qps和任務調度間隔來確定Loader需要撈取的任務數,因此一個調度間隔內的任務數和集群能夠執行的任務數是匹配上的,加上通過單機qps限制達到集群qps限制的效果,從而讓整個定時任務做到了平滑呼叫,簡而言之,優化后的調度邏輯,能夠讓定時調度任務在機器維度和時間維度都能均勻平穩的執行,

三、結語
從單機到集群,再到五福定制集群定時任務,本文逐步做了一個框架設計上的原理介紹,每種定時任務都有自己的優點和缺陷,也都有自己的應用場景,在作業中,要結合當前的業務情況,選擇合適的定時任務進行業務處理,避免設計上的失誤導致業務受損,以五福定制三層分發任務處理框架為例,雖然日常業務中,因為機器數量不固定,依舊無法做到任務的平滑呼叫,但我們可以借鑒最大化利用集群機器資源這一點,同時開啟A/B組的定時任務,從而實作任務調度真正的負載均衡,提高系統整體的穩定性,
作者|金盛杰(司旭)
本文來自博客園,作者:古道輕風,轉載請注明原文鏈接:https://www.cnblogs.com/88223100/p/How-to-do-Alipay-timed-tasks-Introduction-to-the-three-layer-distribution-task-processing-framework.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/549812.html
標籤:其他
下一篇:一文吃透泛型
