Dataworks批量刷數優化方案探討


Dataworks批量刷數優化方案探討

在數據倉庫的日常使用中,經常會有批量補數據,或者邏輯調整后批量重跑數據的場景。
批量刷數的實現方式,因調度工具差異而各有不同。

Dataworks調度批量刷數局限

我們的數據倉庫構建在阿里雲的dataworks+maxcompute產品上,dataworks的調度工具提供了補數據的功能,可以很方便的補整個任務流的數據,但是該功能有個局限,就是只能指定一個參數,即業務日期,如下圖。
20211102095700
如果要刷一個月的數據,比如2021年10月份,要怎么操作呢?業務日期選定時間范圍2021-10-01 ~ 2021-10-31。然后dataworks會根據選定的時間范圍,每天生成一個實例去執行任務補數據,也就是補數據的任務要跑31次,每次補一天的數據。
20211102095723
這樣就會導致整個補數的過程非常緩慢,且耗資源。

  1. 因為maxcompute是基於hive的,一個任務的啟動初始化-〉申請資源-〉等待資源分配的過程是很重、很緩慢的,31個天任務的這個過程中耗時會是單個任務的31倍(未並行的情況下)。初步統計了一下,單個maxcompute任務的啟動耗時大概是8s,31個任務啟動就比單個任務多出了4分鍾,如果整個流程涉及10個任務,整個刷數的耗時單在這個階段就要多出40分鍾。
  2. 作為大數據的計算引擎,在一定的數據量級內,數據處理的耗時差別並不大。也就是說一次處理一天的數據,相較於一次處理一個月的數據,正常而言區別不會很大,絕對低於處理30次一天數據的耗時。

所以想要有效率的補數,不能依靠這種方式。

優化方案1

提升批量刷數效率的第一步,就是改造任務,按時間范圍跑數,比如一次跑一個月的數據。但是這與日常調度的任務又有沖突,所以需要新建一份做為手動任務發布執行。
同時dataworks的手動任務的執行,也只能指定一個業務日期參數,且沒法選定業務日期范圍,即批量生成實例。
20211102095741
介於這個限制,所以手動任務的跑數時間周期只能是固定的,比如月、周、年。
按照這種方式刷數的效率,也已經遠遠高於前面的多實例按天補數據的方式。
實際案例,一個涉及近30個任務的流程,通過補數據的多實例按天刷一個月的數,耗時需6.5~8小時。通過手動任務按月刷數耗時只需1.5~2小時,效率提升近75%。

這種方式的缺點是:

  1. 同一腳本要維護兩套,一套周期任務,一套手動任務。增加維護成本。
  2. 腳本跑數時間周期固定,如果需要調整周期需改腳本,並單獨發布。比如按月刷數的腳本,想要按年刷,需要改腳本重新發布。

優化方案2

仔細分析,造成批量刷數麻煩、效率低下的根本原因,其實是dataworks的調度工具(不管是補數據,還是手工任務執行)只能指定一個參數
有其他調度工具使用經驗的朋友都會知道,在用調度工具手動執行任務時,一般是可以指定任務的入參的。而一般的ETL腳本都會設置兩個入參: 開始時間、結束時間,來支持按時間范圍跑數。
而阿里雲dataworks調度工具支持自定義傳參的唯一方式是賦值節點。通過賦值節點的輸出參數,將參數傳遞給下游任務,下游任務可通過設置依賴賦值節點,獲取賦值節點的輸出參數,作為本節點任務的入參。
具體配置方法,可參考dataworks的說明文檔:https://help.aliyun.com/document_detail/137534.html

所以具體的優化思路是,通過控制賦值節點的輸出值,來指定下游任務的跑數時間范圍,以實現批量刷數的目的。

賦值節點配置

因賦值節點的輸出值需要可人為調整,所以設計創建一參數表,賦值節點從表里獲取數據,作為輸出值。可通過update參數表的值,來調整賦值節點輸出值。

因為要update表,所以需創建一個支持事務(update)的表,同時需要包含下游節點需要的兩個參數:開始時間、結束時間。

如:

CREATE TABLE IF NOT EXISTS schedule_args(
  start_date BIGINT COMMENT '開始日期,格式:yyyymmdd'
  ,end_date BIGINT COMMENT '結束日期,格式:yyyymmdd'
) STORED AS ALIORC 
TBLPROPERTIES ('comment'='調度任務入參表', 'transactional'='true')
;

又,因為只有周期任務支持賦值節點,且下游任務都得從該節點獲取跑數時間范圍。所以這里會有個風險點: 對賦值節點參數的調整可能影響到下游任務的日常調度。

解決方法是:通過增加判斷邏輯,把日常調度與補數據兩種場景的參數生成區別開。
具體實現是:通過獲取dataworks內置業務日期參數$bizdate,並對業務日期值的判斷,來區分周期調度和補數據兩種場景。 正常周期調度的業務日期都是前一天,而補數據指定的業務日期不是。

所以賦值節點的腳本如下:

select case when '${bizdate}' <> to_char(dateadd(getdate(),-1,'dd'),'yyyymmdd') then start_date else '${bizdate}' end as start_date
,case when '${bizdate}' <> to_char(dateadd(getdate(),-1,'dd'),'yyyymmdd') then end_date else '${bizdate}' end as end_date
from schedule_args ;

注: 更完備的規避風險的方法是,通過python腳本從表獲取參數,並增加對空表和表不存在兩種異常場景的處理。

這樣正常日調度,賦值節點生成的輸出參數值都是前一天,與不使用賦值節點獲取的dataworks業務日期參數一致。

簡單測試

配置下游節點,測試賦值節點的參數生成和下游節點的參數獲取,以及日常調度和補數據場景的切換。

下游測試節點配置:
20211102095834
20211102095844

節點流程如下:
20211102095857

參數表配置:
20211102095911

業務日期選擇前一天,模擬日常調度場景:
20211102095932

下游節點獲取入參為正常日調度的業務日期:
20211102095950

補數據場景:
20211102100014

下游節點獲取入參為參數表配置的日期:
20211102100215

小結

對於刷數時間周期固定,業務邏輯穩定變更少的任務流程,方案1比較適合。
方案2解決了方案1同一任務需要同時維護多套的問題,同時能夠動態調整跑數的時間周期,支持批量刷數的場景更多,也更方便。唯一存在的問題是,在多人同時通過調整參數表進行批量刷數的時候,會有沖突。
比如:開發者A,update了參數表的值為20211001、20211029。在他執行補數據實例之前,開發者B也要刷數據,將參數表的值改為了20201001、20201030。開發者A再去執行補數據時,獲取的參數時開發者B修改后的參數值20201001、20201030。
因為maxcompute還沒有鎖表機制,所以這個問題目前還沒有很好的解決方案,只能通過收攏表修改權限等方式,來人為規避這個問題。

福祿·研發中心 福星


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM