0x00 前言
????????日常工作中大多數(shù)時(shí)候都是在做數(shù)據(jù)開發(fā),ETL 無處不在。雖然最近兩年主要做的大數(shù)據(jù)開發(fā),但感覺日常干的這些還是 ETL 那點(diǎn)事兒,區(qū)別只是技術(shù)組件全換了、數(shù)據(jù)量大了很多。
前幾年數(shù)倉(cāng)勢(shì)微,是因?yàn)閭鹘y(tǒng)的那些工具數(shù)據(jù)庫(kù)等無法解決數(shù)據(jù)量進(jìn)一步膨脹帶來的計(jì)算問題,大數(shù)據(jù)火爆也是因?yàn)楫?dāng)時(shí)大數(shù)據(jù)開發(fā)門檻很高。可是最近兩年隨著大數(shù)據(jù)技術(shù)的成熟開發(fā)門檻越來越低了,數(shù)據(jù)倉(cāng)庫(kù)反而重新火起來了。
ETL 的事情就跟 SQL 一樣入門很簡(jiǎn)單,但真要熟練運(yùn)用也沒那么容易,因?yàn)檫@兩類技能僅靠理論學(xué)習(xí)很難掌握,必須不斷的實(shí)踐堆積才行。
-
為什么有的人開發(fā)的程序動(dòng)不動(dòng)就延遲、動(dòng)不動(dòng)就報(bào)錯(cuò)?
-
為什么有的人開發(fā)的程序源端數(shù)據(jù)稍微來點(diǎn)臟數(shù)據(jù)就各種數(shù)據(jù)質(zhì)量問題??
-
為什么有的人開發(fā)的程序需求稍微一變就各種支持不了?隨之而來的各種踢皮球。
-
為什么有的代碼開發(fā)者自己都看不懂了?
-
為什么有的項(xiàng)目各種返工、各種推倒重來?
看完上邊羅列的日常開發(fā)中常見的現(xiàn)象后,大家還會(huì)覺得 ETL 開發(fā)簡(jiǎn)單嗎?
最后我們不妨總結(jié)下,高水平的數(shù)據(jù)開發(fā)者應(yīng)該具備什么樣的特質(zhì)?
-
努力用最簡(jiǎn)潔的方式實(shí)現(xiàn)復(fù)雜的需求。復(fù)雜的代碼理解和維護(hù)都很困難,且容易出現(xiàn)性能問題。
-
考慮功能實(shí)現(xiàn)的同時(shí)還要考慮性能和穩(wěn)定性。
-
花更多的精力在源端數(shù)據(jù)探查,能夠提前考慮導(dǎo)數(shù)據(jù)源端的各種問題從而開發(fā)出相對(duì)健壯的 ETL 代碼。
-
充分了解業(yè)務(wù),對(duì)需求有前瞻性預(yù)判,甚至能夠輔助需求方做出改進(jìn),使得需求更加合理同時(shí) ETL 開發(fā)更簡(jiǎn)單。極端情況下要有 A/B 預(yù)案(比如之前就有項(xiàng)目方提出了極不合理的需求又不聽勸告,我們只能按需求方需求實(shí)現(xiàn)的同時(shí),準(zhǔn)備了更好的方案,以便需求方將來更改需求時(shí)能夠從容應(yīng)對(duì))。
-
努力提高代碼的可讀性。
-
一般不會(huì)出現(xiàn)重大數(shù)據(jù)質(zhì)量問題,并且極少的出現(xiàn) Bug。
-
程序開發(fā)的同時(shí),也能兼顧考慮后續(xù)的流程和數(shù)據(jù)質(zhì)量監(jiān)控問題。
0x01 ETL架構(gòu)與規(guī)范
ETL 架構(gòu)
ETL 邏輯架構(gòu)圖
數(shù)據(jù)架構(gòu)圖
ETL 邏輯架構(gòu)需要跟數(shù)據(jù)架構(gòu)放在一起看:
-
抽取層:ETL 需要先將源端的數(shù)據(jù)抽取到數(shù)據(jù)倉(cāng)庫(kù) ODS 層保持源結(jié)構(gòu)。
-
集成轉(zhuǎn)換層:基于 ODS 層做集成轉(zhuǎn)換寫入數(shù)倉(cāng)明細(xì)層或維度層。集成主要是值編碼映射、消除冗余、不一致和錯(cuò)誤。轉(zhuǎn)換主要是將集成后的數(shù)據(jù)做進(jìn)一步處理,以便將數(shù)據(jù)存儲(chǔ)到統(tǒng)一設(shè)計(jì)的數(shù)倉(cāng)明細(xì)層。
-
特殊業(yè)務(wù)處理:數(shù)據(jù)明細(xì)層主要為了統(tǒng)一規(guī)范化的存儲(chǔ)全域數(shù)據(jù),但為了更好的支撐下游的各種數(shù)據(jù)應(yīng)用,還需要對(duì)數(shù)據(jù)做進(jìn)一步的加工匯總轉(zhuǎn)換。
抽取加載策略
抽取加載策略
抽取和加載策略這是數(shù)倉(cāng)面試中經(jīng)常問的問題(當(dāng)然有些面試官也會(huì)將其統(tǒng)稱為 ETL 策略),為了能夠更好的結(jié)構(gòu)化表達(dá),我們可以這樣描述:
ETL 策略可以分為兩類,抽取策略和加載策略。抽取策略我們需要考慮對(duì)源端系統(tǒng)的影響以及抽取行為的開銷。加載策略我們更多的是考慮對(duì)目標(biāo)端已有數(shù)據(jù)的影響、數(shù)據(jù)完整性、重復(fù)執(zhí)行也要保證冪等性。
抽取策略又分為三類:
-
抽取周期:按小時(shí)、按天、按周、按月。抽取周期的選擇,主要取決于業(yè)務(wù)對(duì)實(shí)時(shí)性的要求。周期越短實(shí)時(shí)性越高但成本也會(huì)越高。對(duì)于部分實(shí)時(shí)性要求高的需求每30分鐘抽取到 ODS 層然后直接從 ODS 層支撐業(yè)務(wù)也是一個(gè)選擇。
-
抽取時(shí)機(jī):這個(gè)需要根據(jù)抽取周期來定,如果按日抽取的話,我們通常選擇在凌晨業(yè)務(wù)不繁忙的時(shí)候進(jìn)行,同時(shí)不建議剛過0點(diǎn)就開始,避免部分?jǐn)?shù)據(jù)延遲到達(dá)。
-
抽取方式:增量、全量、新增。全量方式簡(jiǎn)單粗暴但耗費(fèi)資源適用于少量數(shù)據(jù)、需要識(shí)別刪除數(shù)據(jù)或者時(shí)點(diǎn)值(快照)數(shù)據(jù)抽取。增量是指新增和變化,我們需要識(shí)別數(shù)據(jù)插入和更新的時(shí)間這對(duì)源端數(shù)據(jù)有一定要求,適用于維度數(shù)據(jù)或者需要記錄狀態(tài)變化的事實(shí)數(shù)據(jù)例如訂單。新增主要用于業(yè)務(wù)流水?dāng)?shù)據(jù)的抽取場(chǎng)景,這些數(shù)據(jù)在源端只會(huì)插入不會(huì)更新就算有刪除我們也不關(guān)心。對(duì)于刪除數(shù)據(jù)的識(shí)別最好的辦法就是要求源端邏輯刪除,當(dāng)然現(xiàn)在我們還可以通過解析數(shù)據(jù)庫(kù)日志的方法來處理。
加載策略分為四類:
-
直接追加:對(duì)于抽取方式為新增的情況,我們直接追加即可。
-
直接覆蓋:對(duì)于抽取方式為全量抽取,又不需要保留歷史變化情況,我們可以采取直接覆蓋的方式。但 ODS 層不能使用這種加載策略需要每天新建一個(gè)分區(qū),且該任務(wù)不可重復(fù)執(zhí)行(在流程控制和運(yùn)維時(shí)候需要特別注意)。
-
更新追加:對(duì)于不需要考慮歷史變化,只需要記錄最新狀態(tài)的數(shù)據(jù)我們采用更新追加的方式。維度表不太重要的屬性也可以采用該方式。
-
歷史表加載:對(duì)于需要考慮歷史變化的數(shù)據(jù),我們不能更新追加,必須采用拉鏈表方式存儲(chǔ)。維度表或者事實(shí)表的狀態(tài)變更適合采用此種方式。
兩種重要的設(shè)計(jì)模板
、
設(shè)計(jì)模板-數(shù)據(jù)抽取加載策略
抽取加載策略設(shè)計(jì)文檔,最常用的地方是 ETL 抽取層。
-
方便數(shù)倉(cāng)開發(fā)與源端系統(tǒng)溝通,做為源端系統(tǒng)改造的參考依據(jù)、用于評(píng)估對(duì)源端系統(tǒng)的影響。
-
做為 ETL 元數(shù)據(jù),為數(shù)倉(cāng)開發(fā)者提供參考。
-
是數(shù)據(jù)同步工作的指導(dǎo)性文檔。
設(shè)計(jì)模板-ETL數(shù)據(jù)映射
規(guī)范的 ETL 映射設(shè)計(jì)文檔,包含數(shù)據(jù)流的在不同層次/階段的映射(Mapping)文檔。描述了 ETL 表/字段數(shù)據(jù)血緣、源表到目標(biāo)表的映射邏輯,是 ETL 開發(fā)的重要指導(dǎo)性文檔,同時(shí)也是 ETL 元數(shù)據(jù)的重要組成部分。
我們可以通過系統(tǒng)工具設(shè)計(jì),也可以直接使用 Excel 。
0x02 ETL 規(guī)范
ETL 規(guī)范是為保證 ETL 系統(tǒng)能夠正確、穩(wěn)定、高效運(yùn)行,保證多人開發(fā)過程中的風(fēng)格一致,而在 ETL 設(shè)計(jì)、實(shí)施和維護(hù)環(huán)節(jié)定義的一系列規(guī)則和方法,具體包括 ETL 設(shè)計(jì)規(guī)范、開發(fā)規(guī)范以及維護(hù)規(guī)范。
設(shè)計(jì)規(guī)范
抽取加載策略設(shè)計(jì)文檔
-
節(jié)點(diǎn)名稱,與目標(biāo)表一致
-
負(fù)責(zé)人
-
源表、目標(biāo)表
-
抽取方式、加載策略
-
增量新增數(shù)據(jù)的判斷條件
-
是否支持重復(fù)執(zhí)行
ETL 映射設(shè)計(jì)文檔
-
節(jié)點(diǎn)名稱,與目標(biāo)表一致
-
所在層級(jí)、所屬 Job
-
Job 中的位置、上游節(jié)點(diǎn)名稱
-
負(fù)責(zé)人
-
參數(shù)列表
-
源表、目標(biāo)表
-
字段映射轉(zhuǎn)換關(guān)系
-
是否支持重復(fù)執(zhí)行
調(diào)度設(shè)計(jì)文檔
-
頂層調(diào)度有幾個(gè)?
-
頂層 Job 調(diào)度時(shí)機(jī)
-
頂層調(diào)度參數(shù)列表
-
每個(gè) Job 內(nèi)的任務(wù)調(diào)度順序編排
-
調(diào)度是否支持重復(fù)執(zhí)行
-
調(diào)度是否支持并行
開發(fā)規(guī)范
命名規(guī)范
-
Job 命名規(guī)范:J_層次名_內(nèi)容描述。
-
節(jié)點(diǎn)命名規(guī)范:跟目標(biāo)表一致。
-
參數(shù)命名規(guī)范:統(tǒng)一命名,禁止私自創(chuàng)造。
代碼編寫原則
-
代碼清晰、整齊,具有一定的可觀賞性。
-
代碼編寫要充分考慮執(zhí)行速度最優(yōu)原則。
-
代碼行整體層次分明、結(jié)構(gòu)化強(qiáng)。
-
代碼中應(yīng)有必要的注釋以增強(qiáng)代碼的可讀性。
-
規(guī)范要求非強(qiáng)制性地約束代碼開發(fā)人員的代碼編寫行為。在實(shí)際應(yīng)用中,只要不違反常規(guī)要求,允許存在可理解的偏差。
代碼開發(fā)規(guī)范
-
腳本是否有備注、復(fù)雜計(jì)算邏輯是否有注釋。
-
任務(wù)是否支持多次重跑而輸出不變,不能有 insert into 語句。
-
分區(qū)表是否使用分區(qū)鍵過濾并且有有效裁剪。
-
外連接的過逑條件是否使用正確,例如在左連接的 where 語句存在右表的過濾條件。
-
關(guān)聯(lián)小表,是否使用/*+ map join * /。
-
不允許引用別的計(jì)算任務(wù)臨時(shí)表。
-
原則上不允許存在一個(gè)任務(wù)更新多個(gè)目標(biāo)表。
-
是否存在笛卡爾積。
-
禁止在代碼里面使用 drop、create、rename 等 DDL 語句。
-
使用動(dòng)態(tài)分區(qū)時(shí),有沒有檢查分區(qū)鍵值為 NULL 的情況。
-
對(duì)于重要的任務(wù) DQC 質(zhì)量監(jiān)控規(guī)則是否配置,嚴(yán)禁裸奔。
-
代碼中有沒有進(jìn)行適當(dāng)?shù)囊?guī)避數(shù)據(jù)傾斜語句。
日志輸出規(guī)范
-
每個(gè)任務(wù)節(jié)點(diǎn),都需要輸出成功/失敗標(biāo)志,如果失敗最好輸出錯(cuò)誤信息。
-
每個(gè) Job 也要輸出成功/失敗標(biāo)志,如果失敗必須輸出失敗任務(wù)節(jié)點(diǎn)名稱。
部署規(guī)范
需要定義清楚,每個(gè)工作流應(yīng)該部署到哪臺(tái)服務(wù)器的哪個(gè)目錄下邊。
需要定義清楚,ETL 服務(wù)器的目錄結(jié)構(gòu)。
以下是我們當(dāng)時(shí)的 ETL 部署規(guī)范(工具是 Kettle,ETL服務(wù)器有兩臺(tái),一臺(tái)做數(shù)據(jù)抽取如 ODS 層另一臺(tái)是剩余的數(shù)據(jù)處理 )。
更多數(shù)倉(cāng)規(guī)范,請(qǐng)參考文末的擴(kuò)展閱讀。
0x03 ETL 開發(fā)流程
以上流程適用于數(shù)倉(cāng)的 ETL 系統(tǒng)整體設(shè)計(jì)、細(xì)分模塊設(shè)計(jì),也適用于日常的數(shù)據(jù)開發(fā)。對(duì)于整體設(shè)計(jì)的數(shù)據(jù)探查針對(duì)的是所有數(shù)據(jù)源,細(xì)分模塊設(shè)計(jì)和日常數(shù)據(jù)開發(fā)針對(duì)的是需要用到的表。日常的臨時(shí)開發(fā)如果是一次性的則不需要過多考慮流程依賴和配置調(diào)度。
需求理解
我們需要結(jié)合對(duì)業(yè)務(wù)對(duì)項(xiàng)目的了解,去充分理解需求,明白需求方真正想要什么,并根據(jù)自己的專業(yè)知識(shí)做出有效評(píng)估,最好能拿著原型找需求方做個(gè)需求確認(rèn)。我們只有比需求方理解的更透徹深遠(yuǎn)才更有可能做的更好,減少返工同時(shí)得到客戶的認(rèn)可。
數(shù)據(jù)探查
當(dāng)我們充分理解需求后,就需要根據(jù)需求去尋找需要的數(shù)據(jù)了。如果是數(shù)倉(cāng)整體設(shè)計(jì)我們需要對(duì)源端數(shù)據(jù)充分了解;如果是日常數(shù)據(jù)開發(fā)我們需要非常熟悉手邊的數(shù)據(jù)或數(shù)據(jù)倉(cāng)庫(kù)中的表,實(shí)在不行可以找更熟悉的人去咨詢。
當(dāng)找到“需要的數(shù)據(jù)”后,在程序開發(fā)(或?qū)慡QL)前還需要深入的數(shù)據(jù)探查,去考察數(shù)據(jù)內(nèi)容、數(shù)據(jù)質(zhì)量以及數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)。否則容易造成兩類常見的后果:使用了錯(cuò)誤的數(shù)據(jù)或者錯(cuò)誤的使用了數(shù)據(jù)。
數(shù)據(jù)探查,需要我們摸清以下幾方面內(nèi)容:
-
簡(jiǎn)單看下表的元數(shù)據(jù)信息:重點(diǎn)關(guān)注命名、備注、字段類型、最后更新時(shí)間等。有時(shí)候也需要關(guān)注數(shù)據(jù)量級(jí)、數(shù)據(jù)增量等。
-
簡(jiǎn)單拿幾條數(shù)據(jù)出來看看:我們需要用到的列是查看的重點(diǎn),同時(shí)要確認(rèn)真實(shí)數(shù)據(jù)跟元數(shù)據(jù)信息是否一致,不一致的要進(jìn)一步求證(是自己理解錯(cuò)誤?還是臟數(shù)據(jù)影響?還是元數(shù)據(jù)錯(cuò)了?)。
-
對(duì)關(guān)鍵字段需要查詢下分布情況,如果發(fā)現(xiàn)跟常識(shí)或者跟自己對(duì)業(yè)務(wù)的理解存在偏差就需要進(jìn)一步求證(看是數(shù)據(jù)問題?還是自己認(rèn)知問題?還是單位或計(jì)算口徑問題?)??罩德?、異常數(shù)據(jù)等在這一步也能被發(fā)現(xiàn)。
-
著重看下數(shù)據(jù)的完整性:比如數(shù)據(jù)內(nèi)容(或列)缺失、數(shù)據(jù)條數(shù)缺失等。
-
看看有沒有其它數(shù)據(jù)質(zhì)量問題:比如重復(fù)數(shù)據(jù)、臟數(shù)據(jù)、編碼映射問題等。
-
需要使用多張表的時(shí)候,要確認(rèn)好 join 字段,并確保兩表之間是 1:m 的關(guān)系,m:n 的關(guān)系很少碰到并且多數(shù)情況下是自己用錯(cuò)了。
-
大致評(píng)估出實(shí)際的開發(fā)工時(shí):需要參考的因素如下,需求的復(fù)雜度、數(shù)據(jù)源的理解探查難度、數(shù)據(jù)源的數(shù)據(jù)質(zhì)量(是否需要特別的清洗、編碼映射、缺失數(shù)據(jù)補(bǔ)全)、數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換成最終需求的復(fù)雜度(有的需要分多步落中間表完成,有的源表數(shù)據(jù)直接就是最終需要的數(shù)值)、自身能力等等。
程序開發(fā)
需求理解透徹、數(shù)據(jù)探查這兩步算是分析階段了。經(jīng)過前兩步的充分分析后,具體的開發(fā)實(shí)現(xiàn)就是很簡(jiǎn)單的事情了。我們按照上文“代碼開發(fā)規(guī)范”的要求,努力拿文章開頭總結(jié)的“高水平的數(shù)據(jù)開發(fā)者應(yīng)該具備的特質(zhì)”去要求自己,努力將分析階段想好的實(shí)現(xiàn)方案高質(zhì)量、高效率落地即可。這同樣也是個(gè)純經(jīng)驗(yàn)問題,一年兩年三年多少都還是會(huì)有些差別的。
最后,我重新再列幾點(diǎn)比較重要的:
-
充分實(shí)現(xiàn)需求還是第一位。
-
盡可能提高代碼的可讀性。
-
用最簡(jiǎn)單的方式實(shí)現(xiàn)。
-
開發(fā)健壯性的代碼。特別是當(dāng)使用別人寫入的表的時(shí)候,為防止別人操作不規(guī)范,我們就要考慮是否需要去除空格、去重、空值的處理等等。
-
預(yù)估或測(cè)試性能問題。
-
結(jié)合加載策略,考慮重復(fù)執(zhí)行的冪等性問題。
-
如果需要上調(diào)度,還要考慮傳入?yún)?shù)的問題。
流程依賴
如果需要程序自動(dòng)執(zhí)行,就要考慮流程依賴了。根據(jù)節(jié)點(diǎn)間的依賴關(guān)系、每個(gè)節(jié)點(diǎn)的資源消耗和每個(gè)節(jié)點(diǎn)的執(zhí)行耗時(shí),去合理編排流程。有依賴的必須串行,無依賴可以并行用于降低總執(zhí)行時(shí)長(zhǎng),當(dāng)然我們也要明白任務(wù)并行會(huì)增加瞬時(shí)資源消耗。
此外我們還應(yīng)該清楚一點(diǎn):流程依賴?yán)锱渲玫膱?zhí)行先后順序,后執(zhí)行的不一定就真的依賴于先執(zhí)行的任務(wù)節(jié)點(diǎn)。工作流的編排邏輯是上邊提到的三方面因素的綜合考量結(jié)果。
最后,除了工作流編排外,我們還需要考慮以下三點(diǎn):
-
執(zhí)行過程中的日志記錄。
-
補(bǔ)數(shù)、重跑情況下的參數(shù)傳遞問題。內(nèi)層工作流或底層節(jié)點(diǎn)絕對(duì)不能把參數(shù)(主要是日期)寫死,我們需要在調(diào)度工作流的時(shí)候,工作流內(nèi)的所有節(jié)點(diǎn)都能接受到來自外層傳入的參數(shù)。
-
盡量的將可以重復(fù)跑的和不能重復(fù)跑的節(jié)點(diǎn)放到不同的工作流。
-
盡量的將可并行補(bǔ)多個(gè)日期數(shù)據(jù)的節(jié)點(diǎn)跟不能并行補(bǔ)數(shù)的節(jié)點(diǎn)放到不同的工作流。
配置調(diào)度
具體到調(diào)度層面,我們需要把每個(gè)工作流都打上如下標(biāo)簽(使用說明書):
-
允許的最早調(diào)度時(shí)間(需要考慮前置依賴或數(shù)據(jù)源就位時(shí)間)。
-
允許的最晚結(jié)束時(shí)間(如有)。
-
參數(shù)列表以及默認(rèn)值。
-
告警通知人列表。
-
是否支持重復(fù)跑。
-
是否支持并行補(bǔ)多個(gè)日期數(shù)據(jù)。
調(diào)度其實(shí)不需要過多了解工作流的內(nèi)部情況,只需根據(jù)工作流的使用說明書,做好如下二件事情即可:?
-
在合適的時(shí)間調(diào)度執(zhí)行。文章來源:http://www.zghlxwxcb.cn/news/detail-550448.html
-
監(jiān)控工作流的執(zhí)行情況,報(bào)錯(cuò)或超時(shí)的時(shí)候發(fā)出告警,開始或者結(jié)束的時(shí)候發(fā)出通知(如有)。文章來源地址http://www.zghlxwxcb.cn/news/detail-550448.html
到了這里,關(guān)于六、數(shù)據(jù)倉(cāng)庫(kù)詳細(xì)介紹(ETL)經(jīng)驗(yàn)篇的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!