Yelp 的 Spark 資料血緣建設實踐!

danny_2018發表於2022-08-19

在這篇博文中,我們介紹了 Spark-Lineage,這是一種內部產品,用於跟蹤和視覺化 Yelp 的資料是如何在我們的服務之間處理、儲存和傳輸的。

Spark 和 Spark-ETL:在 Yelp,Spark被認為是一等公民,處理各個角落的批次工作,從處理評論到識別同一地區的相似餐廳,到執行有關最佳化本地業務搜尋的報告分析。Spark-ETL 是我們圍繞 Spark 的內部包裝器,提供高階 API 來執行 Spark 批處理作業並抽象出 Spark 的複雜性。Spark-ETL 在 Yelp 被廣泛使用,幫助節省了我們的工程師編寫、除錯和維護 Spark 作業所需的時間。

問題:我們的資料在數百個微服務之間進行處理和傳輸,並以不同的格式儲存在包括 Redshift、S3、Kafka、Cassandra 等在內的多個資料儲存中。目前我們每天有數千個批處理作業在執行,越來越難以理解它們之間的依賴關係。想象一下你自己是一名軟體工程師,負責釋出由幾個關鍵 Yelp 服務使用的資料的微服務;您即將對批處理作業進行結構更改,並想知道您的服務的下游物件和內容將受到影響。或者想象自己扮演一個機器學習工程師的角色,他想在他們的模型中新增一個 ML 功能並問:“我可以自己執行檢查以瞭解這個功能是如何生成的嗎?”

Spark-Lineage: Spark-Lineage 就是為解決這些問題而構建的。它提供資料旅程的視覺化表示,包括從起點到目的地的所有步驟,並提供有關資料去向、誰擁有資料以及在每個步驟中如何處理和儲存資料的詳細資訊。Spark-Lineage 從每個 Spark-ETL 作業中提取所有必要的後設資料,構建資料移動的圖形表示,並讓使用者透過第三方資料治理平臺以互動方式探索它們。

圖片

圖 1. Spark-ETL 作業的 Spark-Lineage 檢視示例

圖片

圖 2. Spark-Lineage 概述

使用 Spark-ETL 執行 Spark 作業很簡單;使用者只需提供(1)透過 yaml 配置檔案提供源和目標資訊,以及(2)透過 python 程式碼從源到目標的資料轉換邏輯。

圖片

圖 3. Spark-ETL 作業的示例圖

在後端,我們直接在 Spark-ETL 中實現 Spark-Lineage,以從每個批處理作業中提取所有具有依賴關係的源表和目標表對。更準確地說,我們使用NetworkX庫來構建作業的工作流圖,並在該作業的相應有向無環圖 (DAG) 工作流中查詢在它們之間具有路徑的所有源表和目標表對。轉換中的所有中間表都不會記錄在 Lineage 中,因為它們是臨時的。例如,(輸入表 1,輸出表 2)是圖 3 中的一對,因為它們之間存在路徑,而(輸入表 2,輸出表 2)則不是。對於每一對這樣的對,我們向 Kafka 傳送一條訊息,包括源和目標的識別符號,以及其他必要的後設資料。然後這些訊息從 Kafka 傳輸到 Redshift 中的專用表。

我們採用兩步流程而不是直接將訊息傳送到一個地方的原因是 Redshift 有維護停機時間,而 Kafka 隨時可以接收新發出的訊息。另一方面,在 Redshift 中儲存資料非常持久且易於查詢以用於分析目的。在 Yelp,我們每天大約有數千個批次,平均每個作業發出大約 10 條訊息。總的來說,Lineage 表每年增長几百萬行,這可以由 Redshift 輕鬆處理。Spark-Lineage 然後使用 ETL 工具外掛從 Redshift 表中讀取併為使用者提供服務。

構建 Spark-Lineages UI

首先,我們解析 Redshift 中上述步驟提供的後設資料,並識別源和目標資訊。此後設資料首先被讀入 Redshift 資料庫中的臨時表。我們暫存此資料的原因是為了識別在日常負載中引入的任何新作業或捕獲對現有計劃作業的任何更新。

然後,我們為每個 Spark-ETL 表建立一個連結(表、檔案等的規範術語)以及從後設資料中提取的附加資訊。我們還使用它們各自的模式新增這些作業之間的關係。最後我們根據從 Spark-ETL 中提取的 DAG 建立源表和目標表之間的連線。

Spark-Lineages 的模擬 UI 如圖 1 所示,使用者可以在其中瀏覽或搜尋所有 Spark 表和批處理作業,讀取每個表和作業的詳細資訊,並跟蹤它們之間的從源到結束的依賴關係.

瞭解機器學習功能

研究機器學習模型的資料科學家經常在構建新功能時尋找現有資料。在某些情況下,他們發現的資料可能基於關於應包含哪些資料的不同假設。例如,當模型不希望包括此類事件時,一個團隊可能會將背景事件包括在給定使用者已執行的所有最近事件的計數中。在這種情況下,Spark-Lineage 允許團隊追蹤哪些資料用於識別這些不同的決策,以及哪些資料可以緩解差異。

瞭解影響

識別和記錄資料沿襲的主要優勢之一是,它使 Yelpers 能夠了解任何下游/上游依賴關係,以瞭解將合併到功能中的任何更改。它還提供了一種跨相關團隊輕鬆協調的能力,以主動衡量變更的影響並做出相應的決策。

修復資料事件

在分散式環境中,有很多原因會導致批處理作業脫軌,從而導致資料不完整、重複和/或部分損壞。此類錯誤可能會靜默一段時間,一旦被發現,就已經影響了下游作業。在這種情況下,響應包括凍結所有下游作業以防止損壞的資料進一步傳播,跟蹤所有上游作業以查詢錯誤源,然後從那裡回填所有下游不準確的資料。最後,我們在回填完成後恢復作業。所有這些步驟都需要儘快完成,Spark-Lineage 可能是快速識別腐敗嫌疑人的理想場所。

此外,在 Spark-Lineage 中提及負責團隊建立了工作職責,因此維護團隊或現場團隊可以在正確的時間與正確的團隊聯絡。這避免了與多個團隊進行多次對話以確定工作的所有者,並減少了可能對業務報告產生不利影響的任何延遲。

Feature Store

Yelp 的 ML Feature Store 收集和儲存特徵並將其提供給消費者以構建機器學習模型或執行 Spark 作業,併為資料分析師提供決策見解。Feature Store 提供了許多好處,其中包括:

避免重複工作,例如來自不同團隊嘗試構建相同功能;

確保訓練和服務模型之間的一致性;

幫助工程師輕鬆發現有用的功能。

Data Lineage 可以透過各種方式幫助改進 Feature Store。我們使用 Lineage 來跟蹤功能的使用情況,例如功能的使用頻率以及由哪些團隊使用,以確定功能的受歡迎程度,或者功能可以帶來多少效能提升。由此,我們可以執行資料分析來推廣或推薦好的特性,或者指導我們生成我們認為對我們的機器學習工程師有益的類似特性。

合規性和可審計性

Lineage 中收集的後設資料可供法律和工程團隊使用,以確保按照法規和政策處理和儲存所有資料。它還有助於在資料處理管道中進行更改以符合新法規,以防將來引入更改。

這篇文章介紹了 Yelp Spark-Lineage,並展示了它如何幫助跟蹤和視覺化我們服務之間的資料生命週期,以及 Spark-Lineage 在 Yelp 不同領域的應用。對於對 Spark-Lineage 的具體實現感興趣的讀者,我們在下面提供了伺服器端和客戶端的細分(附錄)。

服務端實現

資料識別符號

Spark-Lineage 需要跟蹤的最基本的後設資料是資料的識別符號。我們提供了 2 種方法來識別輸入/輸出表:schema_id和資料的位置。

Schema_id: Yelp 的所有現代資料都被模式化並分配了一個 schema_id,無論它們是儲存在 Redshift、S3、Data Lake 還是 Kafka 中。

位置:另一方面,資料儲存之間的表位置不是標準化的,但通常它是 (collection_name, table_name, schema_version) 的三元組,儘管它們通常為每個資料儲存稱為不同的東西,以符合術語該資料儲存的。

無論哪種方式,如果我們得到一個識別符號,我們就可以得到另一個。查詢模式資訊可以透過 CLI 或 PipelineStudio——一個簡單的 UI 以互動方式探索模式,或者直接在 Spark-Lineage UI 上完成,與 PipelineStudio 相比具有更高階的功能。透過提供兩個識別符號之一,我們可以看到表中每一列的描述以及表的模式如何隨著時間的推移而演變等。

這兩個識別符號中的每一個都有自己的優點和缺點,並且相互補充。例如:

schema_id 提供了一種更規範的方式來訪問資料資訊,但該位置更容易記住並且對使用者更友好。

在模式更新的情況下,schema_id 將不再是最新的,而使用對 (collection_name, table_name) 查詢時將始終返回最新的模式。

使用schema_id,我們也可以發現最新的schema,但需要多一步。

跟蹤其他資訊

Spark-Lineage 還提供以下資訊:

執行日期:我們收集每次執行作業的日期。由此我們可以推斷出它的執行頻率,這比根據yaml檔案中的描述更可靠,因為未來可以改變頻率。如果我們一個月沒有收到任何執行,我們仍然保持作業的輸出表可用,但將它們標記為已棄用,以便使用者知道這一點。

結果:我們還跟蹤每次作業執行的結果(成功/失敗)。

如果出現故障,我們不會通知作業的所有者,因為在 Yelp,我們有專門的監控和警報工具。

我們將這些資料用於與上述相同的目的;

如果服務多次失敗,我們將標記輸出表,讓使用者知道這一點。

作業名稱和 yaml 配置檔案:這有助於使用者快速找到必要的資訊以瞭解作業的邏輯,以及作業的所有者,以防使用者想聯絡以獲取後續問題。

Spark-ETL 版本、服務版本和 Docker 標籤:每次執行時也會跟蹤此資訊,並用於更多技術目的,例如除錯。

一個用例是,如果 ML 工程師最近發現了某個特性的統計變化,他可以查詢並比較今天執行的特定程式碼與上個月的執行程式碼。

客戶端實現

Spark ETL 作業的表示:作為表示 Spark ETL 作業的第一步,建立一個名為“Spark ETL”的新域。這樣可以輕鬆進行目錄搜尋,並在專用區域中儲存 Redshift 臨時表中的 Spark-ETL 作業的詳細資訊。一旦域可用,就會在資料治理平臺中建立唯一連結(用於 spark ETL 作業),作業名稱作為識別符號。

新增後設資料資訊: Spark ETL 作業的詳細資訊(例如,儲存庫、源 yaml 等)附加到上面建立的相應連結。每個後設資料資訊都被賦予一個與相關作業相關的唯一 ID 和值。為 Spark ETL 作業實現的當前機制可以擴充套件以表示將來的附加資訊。

分配責任:當所有者的資訊從 Kafka 提取到 Redshift 時,資料治理平臺中作業連結的責任部分可以修改為包括“技術管家”——負責 Spark ETL 作業的工程團隊,包括生產和維護實際的源資料,並負責資料的技術文件和資料問題的故障排除。

建立沿襲:一旦 Spark-ETL 作業和所需的後設資料資訊在資料治理平臺中可用,我們建立 2 向關係來描述源到 Spark ETL 作業和 Spark ETL 作業到目標關係。這些關係是使用 REST POST API 呼叫建立的。建立關係後,將自動建立沿襲並可供使用。有多個檢視可用於描述關係,但“沿襲檢視”一直捕獲依賴關係,直到 Tableau 儀表板。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31547898/viewspace-2911128/,如需轉載,請註明出處,否則將追究法律責任。

相關文章