【轉】Talend作業設計模式和最佳實踐-Part I

原文地址:https://mp.weixin.qq.com/s?__biz=MzA3OTg1Mzk4Nw==&mid=2453261363&idx=2&sn=e0f42602271d4bb0415b174dfad9963b&chksm=88604cffbf17c5e9b4a48daf5ec09341f34e0d4a44bba9e31501cbb1701bd8d995a5d173e3e8&mpshare=1&scene=1&srcid=0111PXlXmg0GVBeIsITB7zl5#rd

原文作者:talend官方


作爲Talend開發者,不管是入門新手還是資深人士,常常要處理同一個的問題:“在編寫這項作業時,哪種方式最好?”我們知道,通常應當高效、易讀易寫,並且尤其(多數情況下)要易於維護。我們也知道,Talend Studio好比自由形態的“畫布”,有全面而豐富的組件、存儲庫對象、元數據和鏈接選項,我們可以運用這些來“繪製”代碼。那麼,如何確定在創建作業設計時使用的是最佳實踐?

作業設計模式

自Talend版本3.4起,在每次使用時我都體會到作業設計對我的重要性。起初我在開發作業時並未思考模式。之前我用過Microsoft SSIS和其他類似工具,所以像Talend這樣的可視化編輯器對我來說並不陌生。相反,我關注的主要是基本功能、代碼可重用性;其次是畫布佈局;最後是命名規則。現如今,針對各種用例我已經開發了數百項Talend作業,我發現代碼變得更加精巧,可重用性更高,一致性也更好,此時,模式的意義才逐漸顯露出來。

加入Talend後,我有很多機會看到由客戶開發的作業,得以證實自己的看法:對於每位開發者,每個用例都有多種解決方案。我認爲這一點是不少人的問題所在。我們作爲開發者的確都這麼認爲,但是在開發特定作業時,往往認爲自己的方式是最佳或者唯一選擇,但實際上也知道“或許還有更好的方式”,這種聲音反覆縈繞於耳際。在此情況下,我們期待或尋覓最佳實踐,也就是作業設計模式!

制定基本規範

考慮實現最佳作業代碼所需元素時,通常用到一些基本法則。這些法則源於多年來從失敗中汲取的教訓以及積累的成功經驗。它們至關重要,爲構建代碼奠定堅實基礎。我個人認爲應該引起高度重視。我認爲這些法則包括(重要程度不分先後):

l 可讀性:創建明白易懂的代碼

l 可寫性:在最短時間內創建簡潔明瞭的代碼

l 可維護性:確定適當的複雜性,同時最大限度減少變更帶來的影響

l 功能性:創建滿足要求的代碼

l 可重用性:創建可共享對象和原子工作單元

l 符合性:創建跨團隊、項目、存儲庫和代碼的真正規則

l 易適應性:創建可以變通而不致破壞的代碼

l 可擴展性:創建可根據需要調整吞吐量的彈性模塊

l 一致性:確定所有內容之間的共性

l 效率:創建優化的數據流和組件利用率

l 分區:創建服務於單一目標的原子化重點模塊

l 優化:使用最少代碼創建最多功能

l 性能:創建提供最快吞吐量的有效模塊

重中之重是如何真正平衡這些法則,特別是前三條,因爲這三者總是相互矛盾,滿足其中兩條往往要犧牲另外一條。如果可以,嘗試按重要性對這些法則進行排序。

指導原則並非硬性標準,主要是爲了有章可循!

在真正深入研究作業設計模式之前,結合剛剛闡述的基本法則,我們首先要確保瞭解一些其他值得考慮的細節。我發現很多時候標準過於嚴苛,並未針對與其相悖的非預期場景留出足夠餘量。而另外一些時候則相反。不同開發者如出一轍地遵循刻板粗糙、有失協調的規範,更有甚者在作業設計中不連貫、缺乏規劃甚至毫無章法,形成不良風氣。坦率說來,我認爲這樣過於草率並會造成誤導,其實想要避免這些並不困難。

出於上述以及其他相當明顯的原因,首先要制定成文的“指南”,而非建立“標準

其中包含基本法則並隨附細則。參與SDLC(軟件開發生命週期)過程的所有團隊創建並採用“開發指南”文檔之後,這些基本法則即可爲開發中的結構、定義和上下文方面提供支持。對這一環節的投入具有長遠意義,日後所有相關人員都將從中獲益。

以下建議要點,您可根據自身情況予以採納(僅作指導參考,歡迎自行修改擴充)。

1. 方法:其中應詳細說明希望如何構建

1. 數據建模

1. 整體/概念/邏輯/物理

2. 數據庫、NoSQL、EDW、文件

2. SDLC流程控制

1. 瀑布式或敏捷式/Scrum

2. 要求和規範

3. 錯誤處理和審計

4. 數據治理與管理

2. 技術:其中應列出各種工具(內部工具和外部工具)以及各工具間如何相互關聯

1. 操作系統和基礎架構拓撲

2. 數據庫管理系統

3. NoSQL系統

4. 加密和壓縮

5. 第三方軟件集成

6. Web服務接口

7. 外部系統接口

3. 最佳實踐:其中應說明要遵循特定指南的內容和時間

1. 環境 (DEV/QA/UAT/PROD)

2. 命名規則

3. 項目、作業和小作業

4. 存儲庫對象

5. 記錄、監測和通知

6. 作業返回代碼

7. 代碼 (Java) 例程

8. 上下文組和全局變量

9. 數據庫和NoSQL連接

10. 源/目標數據和文件架構

11. 作業切入和退出點

12. 作業工作流程和佈局

13. 組件利用率

14. 並行化

15. 數據質量

16. 父/子任務和小作業(joblet)

17. 數據交換協議

18. 持續集成和部署

1. 集成源代碼控制 (SVN/GIT)

2. 發佈管理和版本控制

3. 自動化測試

4. 項目存儲庫和提升

19. 管理與運營

1. 配置

2. 用戶安全和授權

3. 角色和權限

4. 項目管理

5. 作業任務、計劃和觸發器

20. 存檔和災難恢復

我認爲應當開發和維護的一些其他文件包括:

l 模塊庫:描述所有可重用的項目、方法、對象、小作業和上下文組

l 數據字典:描述所有數據模式和相關的存儲過程

l 數據訪問層:描述與連接和操作數據相關的所有事項

誠然,創建這樣的文檔需要時間,但與之在整個生命週期中發揮的價值相比,這些成本物超所值。文檔應儘可能簡明扼要、直截了當並與時俱進(不必具有聲明性質),它將有助於大幅減少開發錯誤(否則日後會爲此付出高昂代價),爲您所有的項目取得成功大有助益。

是時候探討作業設計模式了吧?

當然,但首先還要說明一點。我認爲,每位開發者在編寫代碼時都可能形成或好或壞的習慣。所以培養良好的習慣至關重要。可以從一些簡單的習慣開始,比如爲每個組件添加標籤。這會讓代碼更具可讀性,並且便於理解(我們的基本法則之一)。人人都養成這樣的習慣後,確保所有作業都有序組織到存儲庫文件夾中,並且使用的名稱對項目有一定意義(也即符合性)。然後讓每個人都採用相同的日誌記錄消息樣式,比方說對於 System.out.PrintLn() 函數採用通用方法封裝器,並且對於作業代碼建立共同的切入/退出點標準(其中包含替代要求選項)。這兩者都有助於快速實現多個法則。隨着時間的推移,由於開發團隊採用並充分利用定義明確的開發指南,項目代碼將變得更易讀寫,並且可由團隊中任何人進行維護(這也是我最期望的效果)。

作業設計模式和最佳實踐

在我看來,Talend作業設計模式可爲我們提供建議的模板或框架佈局,其中涉及關注特定用例的重要和/或必需的元素。模式通常可重用於類似作業創建,如此一來,我們可以快速啓動代碼開發作業。如您預期,多個不同用例也可引入通用模式,經過正確識別和實施,能夠增強整體代碼庫、壓縮作業量並減少重複或相似的代碼。我們下面就此展開探討。

以下是要考慮的7項最佳實踐:

畫布工作流程和佈局

可通過多種方法在作業畫布上放置組件,並將這些組件相互關聯。我偏好的做法大體是首先“自上而下”,然後“從左至右”,其中左側邊界流程通常是錯誤路徑,右側邊界和/或下方邊界流程則爲期望的或正常的路徑。理想情況下應儘可能避免連線交叉,自6.0.1版開始引入巧妙的弧線連接,很好地體現了這種策略。

我自己不太認同“之”字型模式,也就是組件按順序“從左到右”放置,到達最右邊界後即向下排列,隨後再返回到左側邊界,依次類推。感覺這種模式既不方便也不好維護,不過的確容易編寫。如果必須要用這種模式,執行的作業可能較之前會增多,並且可能無法得以正確組織。

原子作業模塊 ~ 父/子作業

簡言之,包含大量組件的大型作業很難理解和維護。要避免這種情況,建議儘可能將大型作業分解爲較小作業或工作單元。之後以子作業形式執行(使用tRunJob組件),其目的即對他們加以控制和執行。這麼做也便於更好地處理錯誤和後續事件。請記住,雜亂的作業可能難以理解,難以調試/修復,並且幾乎無法維護。而簡單的小型作業具有明確目的,通過畫布即可確定意圖,絕大多數易於調試/修復,維護也相對輕而易舉。

創建嵌套的父/子作業層次結構雖然完全可以接受,但需要考慮實際限制。根據作業內存利用率、傳遞的參數、測試/調試問題以及並行化技術(如下所述),良好的作業設計模式不應超過3級嵌套tRunJob父/子調用。嵌套再深可能更安全,但我有充分理由認爲,對於任何用例5級足矣。

tRunJob與小作業

確定子作業與使用小作業之間的簡單區別在於,子作業是從作業中“調用”,而小作業“包含”在作業中。兩者都提供創建可重用和/或通用代碼模塊的機會,在任何作業設計模式中結合使用兩者都是一種非常有效的策略。

切入和退出點

所有Talend作業都需要在某個地方開始和結束。Talend提供兩個基本組件,即tPreJob和tPostJob,目的是幫助控制執行作業內容前後發生的情況。在我的代碼中,“初始化”和“收卷”步驟相當於這兩個組件。如您預期,首先執行tPreJob,然後執行實際代碼,最後執行tPostJob代碼。請注意,無論代碼正文中是否存在設計的退出(例如tDie組件,或者組件複選框選項“錯誤結束"),都將執行tPostJob代碼。

關於作業切入和退出點,也應考慮使用tWarn和tDie組件。這些組件提供對作業完成位置和方式的可編程控制,還支持改進錯誤處理、日誌記錄和恢復機會。

在作業設計模式中,我常使用tPreJob初始化上下文變量,建立連接並記錄重要信息。對於tPostJob,則關閉連接和其他重要清理以及更多記錄。相當簡單對嗎?您是這麼做的吧?

錯誤處理和日誌記錄

這一項非常重要,或者說至關重要,如果可以正確創建通用的作業設計模式,幾乎所有項目都能建立高度可重用的機制。我的作業模式是針對任何作業可能包含的具有一致性和可維護性的記錄處理器,創建“logPROCESSING”小作業,再附加包含具有符合性、可重用性和高效性的明確定義的“返回代碼”。其中的附加項易於編寫、易於閱讀且易於維護。我相信,如果您能以自己獨有的成熟方式來處理和記錄項目作業的錯誤,則必將收穫事半功倍的喜悅。建議合理借鑑,善加利用!

最新版Talend增加了對Log4j和日誌服務器使用的支持。只需啓用“項目設置 > Log4j”菜單選項,然後在TAC中配置Log Stash服務器即可。強烈建議您在作業中納入這項基本功能,實踐證明其效果卓越。

“OnSubJobOK /Error”與“OnComponentOK/Error”(及Run If)組件鏈接

有時候,Talend開發人員對於“OnSubJob”或“OnComponent”鏈接之間的差異心存一絲困惑。“OK”與“Error”的區別顯而易見,那麼這些“觸發連接”差異何在,如何影響作業設計流程?

組件之間的”觸發連接”可定義處理序列和數據流,其中組件之間的依賴關係存在於子作業中。子作業的特點是所用組件有一個或多個組件與其鏈接,從而處理當前數據流。單個作業中可能存在多個子作業,默認情況下所有相關子作業組件周圍帶有藍色高亮方框(可在工具欄予以開啓/關閉)。

1

子作業中的所有組件完成處理後,“OnSubJobOk /Error”觸發器將繼續處理下一個“鏈接”子作業。僅可從該子作業中的起始組件處使用。在該特定組件完成處理後,“OnComponenOK/Error”觸發器將繼續處理下一個“鏈接”組件。如果繼續處理的下一個“鏈接”組件是需要基於可編程java表達式(true|false判定執行的情況),則“Run If”觸發器會非常有用。

何爲作業循環?

對於幾乎每種作業設計模式,代碼中的“主循環”和“輔助循環”都非常重要。這些點用於控製作業執行的潛在退出位置。“主循環”通常表現爲數據流結果集的最頂層處理,完成主循環之後,作業即告完成。“輔助循環”嵌套在更高階循環中,且通常需藉助重要控制纔可確保作業正確退出。我每次會確定“主循環”並確保向控制組件添加tWarn和tDie組件。tDie通常設置爲立即退出JVM(但請注意,即便如此tPostJob代碼也會執行)。這些頂層出口點使用簡單的代碼,“0”表示成功,“1”表示失敗返回,不過遵循自己制定的“返回代碼”指南再好不過了。“輔助循環”(以及流程中的其他關鍵組件)中十分適合納入其他tWarn和tDie組件(其中tDie未設置爲“立即退出 JVM”)。

上面討論的大多數作業設計模式最佳實踐如下圖所示。請注意我用到了實用的組件標籤,不過仍對組件放置規則稍作變通。無論如何,最終結果是作業具有高度可讀性、可維護性並易於編寫。

2019-01-11_101942

結語

至此,雖說並未悉數解答您關於作業設計模式的疑問(實際上也不可能),但這總歸是良好的開端。我們介紹了一些基礎知識,提供了方向,並作了小結。希望這些有所幫助,並且能爲諸位讀者帶來一些有益的啓示。


如果您覺得此文章對您有幫助,請點擊右下方【推薦】讓更多人看到,thanks!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章