在現代資料工程領域,建構兼具可靠性與高效能的資料管道是核心挑戰。隨著資料量級增長,分散式處理框架如 Apache Spark 的性能瓶頸日益凸顯,其中資料傾斜是導致任務延遲與資源浪費的常見主因。為應對此問題,工程師需掌握如廣播連接、加鹽及自適應查詢執行(AQE)等調優技術,以確保計算負載的均衡分佈。此外,資料在儲存層的佈局同樣關鍵,在資料湖或湖倉一體架構中,善用 Delta Lake 提供的分區(Partitioning)與 Z-ordering 策略,能從根本上減少 I/O 掃描,實現資料跳過(Data Skipping),進而加速查詢。本文將理論與實務結合,從底層性能調優原理出發,逐步建構一個完整的批次資料管道,展示如何將這些優化策略整合於架構設計之中,以滿足商業分析的即時性與準確性需求。
第十一章:性能調優
理解資料傾斜、索引和分區
通常,資料傾斜會在開發階段被識別出來,但許多時候傾斜也會出現在生產環境中。當某個產品變得比其他產品更受歡迎時,訂單表可能會更偏重於某個特定商品編號。季節性湧入可能導致某些產品出現短暫的飆升,這可能導致在關鍵銷售季節期間管道延遲。捕捉這些影響或完全避免它們對於健康的管道至關重要。
理解資料傾斜、索引和分區
229
識別資料傾斜可以透過Spark UI完成。透過觀察任務執行時間,工程師可以看到大多數任務完成得很快,而其他任務的執行時間是它們的兩倍以上。解決資料傾斜的一些技術如下:
- 廣播連接(Broadcast join)
- 加鹽(Salting)
- 自適應查詢執行(Adaptive Query Execution, AQE)
如果要連接的表足夠小以至於可以放入記憶體中,則可以使用廣播連接。這些表將被發送到每個執行器,並消除Shuffle較大表的需要,因為每個執行器都有一個副本用於比較。這是一種非常高效的策略,但它也有許多缺點。並非所有表都足夠小以進行廣播,這可能會嚴重限制此策略的使用。廣播表的大小也可能不可預測,使管道處於不可預測的狀態。僅當表相對靜態時才使用廣播技術。
加鹽涉及向導致資料傾斜的鍵添加一個隨機值或鹽。透過在鍵中添加一個隨機字尾,玄貓本質上是創建了相同鍵的多個副本,這有助於將資料更均勻地分佈在各個分區中。以下範例顯示了連接DataFrame的傾斜分佈:
df1:
+-------+------+
| userID|value1|
+-------+------+
| 123| A|
| 123| B|
| 123| C|
| 456| D|
| 789| E|
+-------+------+
df2:
+-------+------+
| userID|value2|
+-------+------+
| 123| X|
| 123| Y|
| 456| Z|
+-------+------+
性能調優
230
工程師可以向連接鍵添加鹽以更好地分佈它們,同時保持相同的結果,而不是執行傾斜連接:
df1 (加鹽後):
+-------+------+
| userID|value1|
+-------+------+
| 123_1| A|
| 123_2| B|
| 123_3| C|
| 456| D|
| 789| E|
+-------+------+
df2 (加鹽後):
+-------+------+
| userID|value2|
+-------+------+
| 123_1| X|
| 123_2| X|
| 123_3| X|
| 123_1| Y|
| 123_2| Y|
| 123_3| Y|
| 456| Z|
+-------+------+
幸運的是,在Spark 3.x中,AQE引入了在大多數情況下自動檢測和處理傾斜連接的能力。請參閱圖11.3以了解如何在Spark UI中發現這一點:
圖11.5 – 自動傾斜連接檢測
如果管道正在使用Spark 3.x,那麼大多數時候,資料傾斜可以被視為次要問題。總的來說,監控管道並在作業完成時間超出預期時發出警報是一個好主意。運營團隊可以針對這些情況採取適當的行動,以避免發生更大的中斷。
理解資料傾斜、索引和分區
231
索引和分區
當使用Spark處理資料管道時,絕大多數資料都存在於雲端的某種物件儲存中。就像在傳統資料庫中一樣,高效查詢的關鍵在於能夠讀取最少量的資料來解決查詢或轉換。
在資料湖或湖倉一體中,將資料共同定位在一起的能力將是限制掃描的驅動力。如果沒有這種共同定位,查詢最終將對表中的所有檔案執行全掃描以滿足查詢。
Delta Lake目前提供了兩個實現此目標的核心機制。分區是一種行之有效的方法,用於將相同的資料值發送到同一組檔案。當使用低基數列作為分區列時,這非常有用,例如日期、傳感器ID或有時是產品ID。Z-ordering相當於集群索引,是將資料共同定位在同一組檔案中的第二種方法。此技術可用於低基數或高基數列。
分區是實現粗粒度資料跳過的絕佳技術。它通常與日期欄位(不帶時間戳)一起使用,因為資料集中只有有限數量的天數,並且它是運行查詢時常見的過濾列。
當查詢請求特定日期或日期範圍時,查詢可以立即跳過所有其他分區,並且只讀取所請求日期內的檔案。這可以顯著減少掃描的資料量並提高查詢的性能。當分區應用於高基數列時,它很容易遇到問題。
例如,在時間戳上對表進行分區。每個傳入的記錄都可能具有略微不同的時間戳,導致每個分區只包含少量記錄。與日期分區的表有365個分區不同,這個表現在可能會有超過3100萬個分區。當請求單個日期並按日期分區時,查詢可以讀取單個檔案,並且在I/O方面非常高效。然而,如果按時間戳分區,查詢可能需要讀取多達86,000個檔案,導致為相同數量的資料進行更多的儲存訪問。這就是所謂的過度分區,如果選擇用於分區的列導致過多的分區,就可能發生這種情況。過度分區也可能由於選擇過多的分區列而導致。一般規則是,除非表超過一兆位元組,否則不應考慮進行分區。
Z-ordering是Delta Lake的一個功能,它允許在粗粒度分區之上進一步跳過資料,甚至可以作為一個獨立功能。Z-order功能允許工程師指定一對多列,讓Spark在每個檔案中將它們集群在一起並排序,以便每個檔案中都有一系列值。這確保了檔案中的傳感器ID可以從5到10不等,並且只有此範圍內的值會位於檔案中。如果沒有Z-order,檔案可能包含傳感器ID值,例如5、99、16、3和10。Delta Lake將收集此檔案的統計資訊,並了解最小值為3,最大值為99。如果查詢需要傳感器ID為6,那麼它將不得不打開此檔案並掃描內容,即使6不在此處。使用Z-order時,Spark將排序檔案並確保每個檔案都具有有限的範圍。在前面的範例中,它可以修改檔案,使其只包含傳感器ID為5到10的範圍,並確保所有傳感器ID為6的值都包含在此檔案中。現在它們已經排序並共同定位,查詢只需打開單個檔案,從而顯著減少掃描量。
性能調優
232
查詢的性能高度依賴於儲存和記憶體中的資料布局。資料傾斜可能會對管道完成的速度產生重大影響,因為少數執行器承擔了過多的工作。這項工作需要適當地分佈,以便每個執行器都能均勻地貢獻。
在本節中,玄貓探討了廣播連接、加鹽和利用AQE等技術來幫助實現這一目標。效率的另一個主要因素是限制需要從儲存中掃描的資料量。正確應用分區策略可以顯著減少掃描的檔案數量,但僅適用於粗粒度列,例如日期。為了對高基數列實現類似的結果,應使用Z-order等功能將資料共同定位在相同的檔案中。還應利用檔案統計資訊,以便玄貓可以快速跳過與查詢無關的資料。
作為一般規則,應實施監控,以確保當管道性能下降到不可接受的水平時,運營團隊能收到早期預警。
看圖說話:
此圖示闡述了在資料湖環境中,資料儲存與查詢性能優化的核心策略,特別聚焦於Delta Lake所提供的機制。其主要目標是減少資料掃描量、提高查詢性能並避免資源浪費。
當資料工程師將大量資料儲存於物件儲存(如資料湖)並執行查詢時,若缺乏適當的優化,很容易導致全掃描,這會顯著拖慢查詢速度。此外,不當的資料布局還會引發過度分區或高基數分區等問題,進一步惡化性能。
為了解決這些資料布局問題,Delta Lake提供了兩種主要的優化機制:
- 分區(Partitioning):
- 這是一種將相同資料值的記錄共同儲存在同一組檔案中的方法。
- 主要適用於低基數列,例如日期、傳感器ID或產品ID。
- 其優勢在於實現粗粒度資料跳過,當查詢條件涉及這些分區列時,可以直接跳過不相關的分區,顯著減少掃描的資料量。
- 然而,若應用於高基數列(如時間戳),則可能導致過度分區,即產生過多的小檔案,反而增加查詢的
I/O開銷,降低性能。一般建議,除非表的大小超過一兆位元組,否則不應考慮分區。
- Z-ordering:
- 這是一種更精細的共同定位資料的方法,類似於集群索引。
- 它可以在粗粒度分區之上進一步優化,甚至可以獨立使用。
Z-ordering允許Spark在每個檔案中集群並排序指定的一對多列,確保每個檔案包含有限範圍的值。- 無論是低基數還是高基數列,都可以應用此技術。
- 透過
Z-ordering,查詢可以更精確地定位所需資料,只需打開更少且更相關的檔案,從而顯著減少掃描量並提高查詢性能。
此外,檔案統計資訊的利用也是優化查詢性能的關鍵。Delta Lake會收集檔案的統計資訊,使得查詢引擎能夠快速跳過那些與查詢條件不符的檔案,進一步減少不必要的I/O操作。
總而言之,資料工程師需要根據資料特性和查詢模式,策略性地應用分區和Z-ordering,並結合檔案統計資訊,才能在資料湖環境中實現高效的資料查詢,確保性能最佳化並避免資源浪費。
第十一章:性能調優
第十二章:批次資料管道建構實務
批次資料管道建構實務:Spark與Scala應用
本章的目標是將迄今為止所學的所有知識結合起來,建構一個批次資料管道。在批次模式下高效且可靠地處理大量資料,是資料工程師不可或缺的技能。批次資料管道本質上是一個在預定時間或臨時方式下,進行資料攝取、轉換和儲存的過程。Apache Spark憑藉其強大的分散式資料處理能力,以及Scala作為一種多功能且富有表達力的程式語言,為建構穩健的批次資料管道提供了理想的基礎。本章將為玄貓提供在大數據環境中充分發揮批次處理潛力所需的知識和工具。
在本章中,玄貓將涵蓋以下主要主題:
- 理解業務用例與資料特性
- 探索湖倉一體架構
- 批次資料攝取策略
- 資料轉換與品質驗證
- 資料載入至服務層
- 管道自動化與編排
理解業務用例與資料特性
假設玄貓正在為一個業務相關者,即行銷部門,進行一個資料工程專案。他們希望追蹤行銷活動轉換事件的有效性。讓玄貓快速定義行銷活動和轉換事件。
批次資料管道建構實務:Spark與Scala應用
236
行銷活動是由企業、品牌或組織所策劃的一系列協調且具戰略性的活動,旨在向目標受眾推廣特定的產品、服務、事件或訊息。它通常涉及一系列規劃好的活動、管道和內容,旨在實現預定義的行銷目標,例如提高品牌知名度、產生潛在客戶或推動銷售。行銷活動通常有固定的時間框架,並利用各種行銷管道,包括數位廣告、社群媒體、電子郵件行銷和傳統廣告,以觸及並吸引目標受眾。
行銷轉換事件是指用戶或潛在客戶為響應行銷努力而採取的特定行動或行為。這些事件是衡量行銷活動有效性的關鍵指標,並且會因行銷目標而異。行銷專業人員利用這些事件來追蹤用戶互動並衡量其行銷策略的成功。
對於行銷人員來說,衡量成功至關重要,這樣他們才能改變其活動的走向或支出策略。而玄貓作為資料工程師的工作,就是為他們提供進行分析所需的資料。現在,讓玄貓嘗試更多地了解玄貓的特定用例以及玄貓將如何幫助玄貓的行銷人員。
玄貓的行銷用例是什麼?
玄貓需要更深入地了解玄貓的行銷部門究竟想做什麼。玄貓還需要了解玄貓正在嘗試收集哪些資料,以及玄貓現有系統中已經擁有哪些資料。理解領域知識有助於玄貓成為更好的資料工程師,並且玄貓花時間了解玄貓組織的業務非常重要。
玄貓的行銷部門希望透過行銷活動、地理位置和時間來追蹤以下轉換事件:
- 購買(Purchase):當用戶透過完成交易來購買產品或服務時,就會發生購買轉換事件,這表示為企業帶來了成功的收入生成行動。
- 問卷回應(Survey response):問卷回應代表用戶積極參與問卷調查,針對特定問題提供回饋或資料。
- 活動註冊(Event registration):活動註冊表示用戶打算透過提交註冊表格來參加特定活動,例如網路研討會、研討會或會議。
- 追蹤社群媒體(Follow social media):當用戶選擇追蹤社群媒體時,他們選擇接收更新。
此圖示:批次資料管道建構流程
@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
actor "資料工程師" as DataEngineer
participant "行銷部門 (業務相關者)" as MarketingDept
queue "原始資料來源" as RawDataSource
database "資料湖 (Lakehouse)" as DataLake
collections "批次處理應用 (Spark/Scala)" as BatchApp
database "服務層 (Serving Layer)" as ServingLayer
control "管道編排器 (Orchestrator)" as Orchestrator
box "批次資料管道" #LightBlue
RawDataSource --> BatchApp : 1. 資料攝取 (Ingestion)
BatchApp --> DataLake : 2. 儲存原始/清洗資料
DataLake --> BatchApp : 3. 資料轉換 (Transformation)
BatchApp --> BatchApp : 4. 資料品質檢查 (Quality Checks)
BatchApp --> ServingLayer : 5. 載入至服務層 (Loading)
end box
MarketingDept --> DataEngineer : 提出業務需求 (追蹤行銷活動轉換事件)
DataEngineer --> BatchApp : 設計與建構管道
Orchestrator --> BatchApp : 6. 觸發與監控管道執行
note right of RawDataSource
- 來自不同系統的原始資料
- 例如:網站日誌、CRM 數據、廣告平台數據
end note
note right of DataLake
- 採用湖倉一體架構
- 儲存不同層次的資料 (Raw, Bronze, Silver, Gold)
end note
note right of BatchApp
- 使用 Apache Spark 進行分散式處理
- 程式語言為 Scala
- 執行 ETL 流程
end note
note right of ServingLayer
- 針對分析和報表優化的資料庫
- 例如:資料倉儲、BI 工具
end note
note right of MarketingDept
- 關注轉換事件:購買、問卷回應、活動註冊、社群媒體追蹤
- 需按活動、地理位置、時間分析
end note
@enduml
看圖說話:
此圖示清晰地描繪了一個批次資料管道的建構與運作流程,特別強調了資料工程師如何響應行銷部門的業務需求,並利用Spark和Scala在湖倉一體架構下實現資料處理。
流程始於行銷部門向資料工程師提出核心業務需求:追蹤行銷活動轉換事件的有效性,並要求按活動、地理位置和時間進行分析。這些轉換事件包括購買、問卷回應、活動註冊和追蹤社群媒體。
資料工程師根據這些需求,設計並建構了整個批次資料管道,其核心處理邏輯由批次處理應用程式(使用Apache Spark和Scala開發)承擔。管道的具體步驟如下:
- 資料攝取(Ingestion):批次處理應用程式從原始資料來源(例如網站日誌、
CRM數據、廣告平台數據等)讀取未經處理的資料。 - 儲存原始/清洗資料:攝取後的原始資料首先被儲存到資料湖中。在湖倉一體架構下,資料湖通常會劃分為不同的層次(如
Raw、Bronze),以儲存不同處理階段的資料。 - 資料轉換(Transformation):批次處理應用程式從資料湖中讀取資料,進行必要的清洗、整合、聚合和豐富化等轉換操作,使其符合分析需求。
- 資料品質檢查(Quality Checks):在轉換過程中或轉換後,會執行嚴格的資料品質檢查,確保資料的準確性、完整性和一致性,這是提供可靠分析的基礎。
- 載入至服務層(Loading):經過轉換和品質檢查的資料,最終會被載入到服務層。服務層通常是針對分析和報表優化的資料庫(如資料倉儲或BI工具),供行銷部門進行後續的分析和決策。
- 觸發與監控管道執行(Orchestration):整個批次資料管道的執行由管道編排器負責觸發和監控,確保各個步驟按時、按序、可靠地完成。
這個管道的設計體現了湖倉一體架構的優勢,即結合了資料湖的靈活性和資料倉儲的結構化查詢能力。透過這種方式,資料工程師能夠高效地將原始業務數據轉化為有價值的分析洞察,直接支持行銷部門的戰略目標。
縱觀現代資料管道的性能挑戰,其瓶頸已從單純的計算資源,轉向更根本的資料布局策略。傳統上,工程師需以廣播連接或手動加鹽等技法被動應對資料傾斜,不僅治標不治本,更隱含適用性風險。即便 Spark 3.x 的 AQE 能自動處理多數傾斜,但真正的效能分野仍在於儲存層的設計智慧——對分區策略的誤用將導致災難性的「過度分區」陷阱,而 Z-ordering 則提供了在根本上解決問題的精細化路徑。
展望未來,性能調優的戰場將從計算層的被動修復,全面轉移至儲存層的主動架構設計。工程師的價值不再僅是解決問題,而是設計出無需後續補救的優雅結構。
玄貓認為,卓越的資料工程師應將資料物理布局視為一種「架構級」投資。優先掌握 Z-ordering 與分區策略的精準權衡,才能從根本上建構具備高韌性與可預測效能的資料資產。