簡體   English   中英

如何減少我的代工廠數據集中的文件數量?

[英]How do I reduce the number of files in my foundry dataset?

我的數據集有 20000 個文件,每個文件都很小。 我將如何減少文件數量以及最佳數量是多少?

執行此操作的最直接方法是在轉換結束時顯式執行repartition() (如果分區計數從原始數字嚴格減少,則為coalesce()

這需要是您返回/寫出結果之前的最后一次調用。

這看起來像:

# ...

@transform_df(
  # ... inputs
)
def my_compute_function(my_inputs):
  # ... my transform logic ...

  df = df.coalesce(500) 
  # df = df.repartition(500) # this also works but is slightly slower than coalesce
  return df

這是稱為“bucketing”以供參考的先行步驟。

最佳存儲桶數取決於您操作的數據規模。 成功構建后,通過觀察磁盤上數據集的總大小來計算最佳存儲區數量有些簡單。

如果您的數據集大小為 128GB,您最終會希望得到 128MB 的文件,因此您的存儲桶數為:

128 GB * (1000 MB / 1 GB) * (1 file / 128MB) -> 1000 files

注意:這不是一個精確的計算,因為由於 Snappy + Parquet 寫出中使用的數據壓縮,更改存儲桶計數后的最終數據集大小會有所不同。 您會注意到文件大小與您預期的略有不同,因此在上述示例中您可能最終需要 1100 或 900 個文件

由於這是一個我不得不多次解決的問題,因此我決定編寫一份更詳細的指南,其中包含許多不同的技術、優缺點以及存在的理由。

為什么要減少文件數?

避免使用包含許多文件的數據集有幾個很好的理由:

  • 讀取性能可能會更差 當數據分散在許多小文件中時,輪廓(分析)等應用程序的性能會受到嚴重影響,因為執行程序必須承擔從后備文件系統下載許多小文件的開銷。
  • 如果后備文件系統是 HDFS ,許多小文件會增加 hadoop name-nodes 和 gossip 協議的堆壓力。 HDFS 不能很好地處理許多小文件,因為它不會對文件系統中的文件列表進行流式處理/分頁,而是構造包含所有文件的完整枚舉的消息。 當您在 HDFS 中有數千萬甚至數億個文件系統對象時,這最終會遇到名稱節點 RPC 消息大小限制(您可以在配置中增加)和可用堆內存(您可以在配置中增加) ...如果您有更多可用內存。)節點間通信變得越來越慢。
  • 轉換變得更慢,因為(目前甚至對於增量轉換)驅動程序線程必須從目錄中檢索當前視圖中所有文件的完整列表,以及事務的元數據和出處(這只是切線相關,但這並不罕見許多文件與許多事務相關)
  • 轉換可以 OOM 驅動程序,因為文件集和事務集在某些時間點保存在內存中。 這可以通過為驅動程序分配更大的內存配置文件來解決——但這會增加成本和/或減少可用於其他管道的資源。

為什么我們最終會在數據集中得到許多文件?

以包含許多文件的數據集結束通常是由以下三個原因之一引起的:

  • 攝取許多小文件的文件攝取
  • 產生許多小文件的(行為不端的)轉換。 每次執行 spark 中的廣泛操作時,都會發生改組。 例如,當執行groupBy時(這意味着 shuffle),spark 默認選擇將數據重新分區為 200 個新分區,這對於增量轉換來說太多了。 由於分區不當(下面討論),轉換也可能產生過多的輸出文件。
  • 增量運行且頻繁運行的管道。 每次管道運行並處理一段(通常很小)數據時,都會在每個數據集上創建一個新事務,每個數據集至少包含一個文件。

接下來,我將列出我所知道的減少數據集中文件數的所有方法,以及它們的缺點和優點,以及適用時的一些特征。

攝入時(magritte 變壓器)

最好的選擇之一是首先避免擁有許多文件。 當從類似文件系統的源中攝取許多文件時,像“連接轉換器”這樣的 magritte 轉換器可能有助於將許多 CSV、JSON 或 XML 文件組合成一個單一的文件。 在適用時,串聯然后應用 gzip 轉換器是一種特別有效的策略,因為它通常可以將 XML 和類似文本格式的大小減少 94% 左右。

主要的限制是要應用這個,你需要

  • 每當攝取運行時都有多個文件可用(因此對於在頻繁更新數據源上非常頻繁地運行的攝取而言效果不佳)
  • 有一個數據源,為您提供可以連接的文件

也可以將許多文件壓縮成更少的文件(使用 .tar.bz2、.tar.gz、.zip、.rar 等格式),但這隨后需要知道這種文件格式的下游轉換並手動解包(文檔中提供了一個示例),因為代工廠無法透明地提供這些檔案中的數據。 但是,沒有預制的 magritte 處理器可以執行此操作,並且在我應用此技術的情況下,我會在攝取之前使用 bash 腳本來執行此任務,這無疑不太理想。

后台壓縮

Foundry 中有一種新機制可以將您寫入的數據集與讀取的數據集分離。 本質上有一個后台作業在運行,它在您追加文件時將文件洗牌到優化的索引中,以便數據集的讀取(大部分)可以轉到這個優化的索引,而不是作者留下的(通常有點隨意)數據布局。

這具有多種好處(例如自動生成針對最常見讀取模式優化的數據布局),其中之一是它可以在后台“壓縮”您的數據集。

從這樣的數據集中讀取時,您的讀取基本上會命中索引以及輸入數據集(其中包含尚未被后台進程合並到索引中的任何文件。)

最大的優點是這會在后台自動發生,無論您的數據攝取或轉換有多混亂,您都可以簡單地寫出數據(在寫入時沒有性能命中並盡快將數據提供給消費者),同時仍然結束一個很好的分區數據集,文件很少(最終。)

這里的主要限制是,這僅適用於 Spark 本身可以理解的格式的數據集,例如 parquet、avro、json、csv ......在攝入前將它們打包成例如鑲木地板。 這樣,隨着時間的推移,鑄造廠仍然可以合並多個這些鑲木地板文件。

此功能尚未對最終用戶完全可用(但計划默認為所有內容啟用。)如果您認為這是您的管道之一最理想的解決方案,您的 palantir POC 可以與團隊一起開票啟用此功能。

重新分配和合並

合並是 spark 中的一個操作,它可以減少分區的數量而沒有廣泛的依賴(spark 中唯一的這樣的操作)。 合並很快,因為它最大限度地減少了混洗。 它的工作方式與以前的 spark 版本相比發生了變化(並且那里有很多相互矛盾的信息),但它通常比repartition快。 但是,它有一個很大的警告:它減少了整個 transform 的並行度

即使您在寫入數據之前的最后coalesce ,spark 也會調整整個查詢計划以使用更少的分區,從而減少使用的執行程序,這意味着您獲得的並行度更低。

重新分區是類似的,但它插入了一個完整的洗牌階段。 這帶來了更高的性能成本,但這意味着從這個階段出來的數據基本上可以保證分區良好(無論輸入如何)。 雖然repartition本身有點昂貴,但它不會遇到在整個轉換過程中減少並行度的問題。

這意味着總體而言,如果您最終寫出的數據量與您之前所做的工作量相比不是那么大,那么使用repartition不是coalesce通常會獲得更好的性能,因為處理數據的能力更多的執行者最終超過了shuffle的缺點。 根據我的經驗,除非您的轉換非常簡單,否則repartition通常會在這里勝出。

一個值得討論的特定用例是增量管道。 如果您的增量管道相對簡單並且只執行例如映射和過濾,那么進行coalesce就可以了。 然而,許多增量管道也會讀取非常大的數據集的快照視圖。 例如,增量管道可能會接收一行新數據,並讀取整個先前的輸出數據集(可能數百萬行),因此請查看該行是否已存在於輸出數據集中。 如果它已經存在,則不發出任何行,如果它不存在,則附加該行。 將一小段增量數據與大型靜態數據集等連接起來時,會發生類似的情況。

在這種情況下,轉換是增量的,但它仍然受益於高並行性,因為它仍然處理大量數據。

我的粗略指導方針是:

  • 轉換作為快照運行: repartition到一個合理的數字
  • 變換以增量方式運行並且不需要高並行度: coalesce(1)
  • 變換以增量方式運行,但仍然受益於並行性: repartition(1)

如果寫入速度/流水線延遲非常重要,那么這些選項都不能接受。 在這種情況下,我會考慮背景壓縮。

定期快照

作為前一點的擴展,為了保持增量管道的高性能,我喜歡在它們上安排定期快照,這允許我每隔一段時間重新分區數據集,執行基本上是“壓縮”的操作。

我已經在這里描述了如何設置它的機制: 如何強制增量 Foundry Transforms 作業以非增量方式構建而不影響語義版本?

我通常會在周末安排快照。 在整個星期中,管道中的每個數據集(可能有數百個數據集)將累積數千或數萬個事務和文件。 然后在周末,隨着計划的快照在管道中滾動,每個數據集將被重新分區,例如,一百個文件。

空氣質量指數

最近,AQE 在代工廠中可用。 AQE 本質上(出於本次討論的目的)將coalesce操作注入到您已經進行了混洗操作的階段,具體取決於前一個操作的結果。 這通常會改善分區(以及文件數量),但據報道在極少數情況下也會使情況變得更糟(但我自己沒有觀察到這一點)。

默認情況下啟用 AQE,但如果您想嘗試禁用它,您可以將其應用到轉換中。

分桶和分區

分桶和分區與此討論有些相關,因為它們主要是關於布置數據以優化讀取數據的特定方法。 這些技術目前都不適用於增量管道。

一個常見的錯誤是寫出由高基數列分區的數據集,例如時間戳。 在具有 1000 萬個唯一時間戳的數據集中,這將導致(至少)輸出數據集中有 1000 萬個文件。

在這些情況下,應該修復轉換,並通過應用保留刪除舊事務(包含數百萬個文件)。

其他黑客

其他壓縮數據集的技巧也是可能的,例如創建“環回”轉換以讀取先前的輸出並將其重新分區,或者手動打開數據集上的事務以重新寫入它。

這些是非常hacky的,但在我看來是不可取的,應該避免。 如今,背景壓縮主要以更優雅、更可靠和更少黑客的方式解決了這個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM