事件觸發更新
一般而言,分析性的資料需求,資料表的延時可以容許一天左右的資料延時 (delay)。然而,隨著企業使用資料的頻率與強度昇高,現在也有很多的資料表,需要儘可能地縮短資料延時 (delay),也因此需要應用到事件觸發更新。
事件觸發更新是我在協助某金融業客戶導入現代資料棧時,遭遇到的挑戰之一。要導入現代資料棧的單位是數據交換中心,該單位要建立一個全新的資料倉儲,並且該資料倉儲之後會使用 dbt 來做資料轉換。資料倉儲的原始資料,會被某種 EL 工具寫入源資料表 (source table),據說,日後,資料倉儲內會有接近 1 萬張資料表。現存的設計是:「每當一張源資料表的同步完成時,資料管線就會得到一個事件,而該事件就會觸發一個 shell script ,該 shell script 會啟動對應的 SQL 來做資料轉換。」
當我在設法導入 dbt ,用 dbt 來取代既有的 shell script 時,一開始都覺得沒有什麼問題吧?偏偏就是資料同步完成的事件觸發更新,與 dbt 格格不入。
定時更新 vs 事件觸發更新
一般使用 dbt 的情境是定時更新,比方說,總共有 n 張源資料表 (source table),這 n 張表,由於它們的更新頻率通常都是半天、一天、一週、一個月,所以 dbt 啟動的排程,可以簡單地用每半天、每一天、每一週、每一個月來排程。當 dbt 啟動之後,dbt 本身就會將這次啟動時所有需要更新的資料轉換 (data transformation) 變成一個有向圖,以拓撲排序地方式,依序更新所有的資料轉換。由於 dbt 內部可以設置並行的線程數 (thread number),當 dbt 在更新資料轉換時,也可以做到平行處理。
與上述一般使用情境相對的,則是事件觸發更新,即資料表因為使用情境的需要,更新的頻率並不是固定的頻率,而是需要透過事件 (event) 觸發更新。在這種情境下對應的使用 dbt 方式,是對每個事件設計一個專門更新特定資料表的 dbt 指令。像這樣子的 dbt 指令,由於往往只更新少數的資料表,就算有設定多執行緒也沒有用,因為它還是只能用一條執行緒來執行。而當這類的事件愈來愈多,即需要「事件觸發更新」的資料表愈多時,就不得不考慮要讓 dbt 同步執行,即在同一時間之內,執行超過一個 dbt job 。
很不幸的是,dbt core 並不支援同步執行 (concurrent run)。換言之,當我們硬是讓 dbt 同步執行時,我們必須自行設計機制來避免資料表的寫入有競爭情況 (race condition)。
另一個問題,則是資料服務水準協議 (data service level agreement),有少數的資料表要比其它的資料表更加即時,換言之,需要優先級機制。當會有大量的觸發更新事件在極短的時間內大量觸發時,就需要準備一個優先佇列先收下這些事件更新,並且依優先級排序事件,再將事件一一從佇列取出,去觸發 dbt 的執行。
dbt 同步執行的設計:應用程式鎖
由於 dbt 的專案特性,有時候我們可以預設執行 dbt 的機器只會有一台,如果滿足這個條件的話,可以用 Linux 指令 flock 來做應用程式鎖。
如果要利用資料庫來做應用程式鎖的話,在 stackoverflow 上有查到一個應用 dbt macro 的範例。
設置一個 dbt macro ,它可以生成應用程式鎖 (application lock)。
利用 dbt 的 hook 功能,讓上述的 dbt macro 會在每次資料轉換執行之前就先執行。
等該次資料轉換結束時,再釋放掉應用程式鎖。
資料服務水準協議的設計:優先佇列
參考上圖,Event Trigger 有可能會在 1 分鐘之內,觸發 100 個事件,這表示同時有 100 張表的資料已經準備好了。每一個事件都會啟動一個 shell script ,而 shell script 之後會回報 dbt 執行的結果給 Event Trigger 。
在 shell script 執行的事,畫在上圖中的紅色虛線之內:
將「事件」存進優先佇列 (Priority Queue)
之後,就是不停地去輪詢 (polling) 工作完成佇列 (Done Queue),看看 dbt 執行的結果為何
當 shell script 得到 dbt 執行的結果之後,就回報給 Event Trigger ,即可結束。
在這個系統之中,會有幾個 worker 程式,不停地從 Priority Queue 裡取出「事件」,並且依事件指定的資料表去執行 dbt run 。執行完成的結果會放入 Done Queue 裡。需要高執行優先級的資料表,其對應的事件會較早從 Priority Queue 被 worker 程式挑選出來,因而可以達成資料服務水準協議。
結論
從一般使用的 dbt 情境「定時更新」到即時資料串流 (real time data streaming) 之間,還存在有「事件觸發更新」這樣子的使用情境。這種使用情境比起「定時更新」複雜多了,因此需要更多的設計,但又還是比即時資料串流簡單多了。


