Apache Spark:分割槽和分桶 - Nivedita

banq發表於2022-05-30


分割槽和分用於最大化收益,同時最小化不利影響。它可以減少洗牌的開銷、序列化的需要和網路流量最後,它提高了效能叢集利用率成本效益

Apache Spark:分割槽和分桶 - Nivedita
Spark 中的分割槽
分割槽的主要思想是最佳化作業效能。作業效能可以透過確保每個工作負載平均分配給每個 Spark 執行器來獲得。不幸的是,沒有單一的經驗法則,但有幾件事我們需要注意。

為什麼要分割槽資料?

分割槽有助於本地化資料並減少跨網路節點的資料混洗,減少網路延遲,這是轉換操作的主要組成部分,從而減少完成時間。

Apache Spark:分割槽和分桶 - Nivedita
首先,我們需要確保沒有沒有工作的執行者,並且沒有一個執行者由於工作分配不平衡而成為瓶頸。

  • 避免使用大檔案,因為每個 Spark 執行器一次只能處理一個分割槽,如果我們的分割槽比 Spark 執行器少,剩餘的執行器將保持空閒狀態,我們無法充分利用現有資源。
  • 避免擁有大量小檔案,因為這需要更多的網路通訊來訪問位於資料湖(例如 AWS S3、Google Cloud Storage 等)上的每個小檔案,並且計算可能需要在磁碟空間上進行大量資料混洗。

一個好的分割槽策略瞭解資料及其結構和叢集配置。糟糕的分割槽會導致糟糕的效能,主要是在 3 個領域:

  • 關於您的叢集大小的分割槽太多,您將無法有效地使用您的叢集。例如,它會產生密集的任務排程。
  • 關於叢集大小的分割槽不足,您將不得不處理記憶體和 CPU 問題:記憶體是因為您的執行程式節點必須將大量資料放入記憶體(可能導致 OOM 異常),而 CPU 因為跨叢集的計算將不平等。
  • 分割槽中的資料可能會出現偏差。當在這些分割槽中執行 Spark 任務時,它們將分佈在執行器插槽和 CPU 上。如果您的分割槽在資料量方面不平衡,則某些任務與其他任務相比執行時間更長,並且會減慢任務的全域性執行時間(並且一個節點可能會比其他節點消耗更多的 CPU)。

如何確定分割槽鍵?

  • 選擇低基數列作為分割槽列(因為將為每個分割槽值組合建立一個 HDFS 目錄)。一般來說,分割槽組合的總數應該小於50K。(例如,不要使用 roll_no、employee_ID 等分割槽鍵,而是使用 state code、country code、geo_code 等)
  • 選擇過濾條件中經常使用的列。
  • 最多使用 2 個分割槽列,因為每個分割槽列都會建立一個新的目錄層。

如何選擇分割槽數:

  • 下限— 2 X 叢集中可供應用程式使用的核心數
  • 上限— 任務需要 100+ 毫秒才能執行。如果花費的時間更少,那麼您的分割槽資料太小,您的應用程式可能會花費更多時間來安排任務。

讓我們從瞭解 PySpark 中存在的不同方法開始

  • 重新分割槽管理分割槽的第一種方法是repartition操作。重新分割槽是減少或增加叢集中資料將被拆分的分割槽數量的操作。此過程涉及完全洗牌。因此,很明顯重新分割槽是一個昂貴的過程。在典型的場景中,大部分資料應該被序列化、移動和反序列化。

重新分割槽 = df.repartition(8)
除了直接指定分割槽數之外,您還可以傳入要對資料進行分割槽的列的名稱。
重新分割槽 = df.repartition('國家')
  • 合併管理分割槽的第二種方法是coalesce. 此操作減少了分割槽的數量並避免了 full shuffle。執行器可以安全地將資料保留在最少數量的分割槽上,僅從冗餘節點移動資料。因此,如果您需要減少分割槽的數量,最好使用合併而不是重新分割槽

合併 = df.coalesce(2)
  • PartitionBypartitionBy(cols)用於定義資料的資料夾結構。但是,對於要建立的分割槽數量沒有具體控制。與coalesce和repartition函式不同,partitionBy影響資料夾結構,對將要建立的分割槽檔案的數量和分割槽大小沒有直接影響。

green_df \ .write \ .partitionBy("pickup_year", "pickup_month") \ .mode ("overwrite") \ .csv("data/partitions/partitionBy.csv", header=True)

持有和傳播分割槽器的 RDD 操作是 -

  • 加入
  • 左外連線
  • 右外連線
  • GroupByKey
  • ReduceByKey
  • 按鍵摺疊
  • 種類
  • 分割槽依據
  • 按鍵摺疊

筆記:
1. 不要按基數高的列進行分割槽。2. 按特定列進行分割槽,主要用於 filter 和 groupBy 操作。3. 即使沒有最佳數字,建議每個分割槽檔案大小保持在 256MB 到 1GB 之間。4. 如果要增加分割槽數,請使用repartition()執行完全隨機播放)。5. 如果要減少分割槽數,請使用coalesce()(最小化隨機播放)。6. 預設分割槽數等於機器的CPU核數。7. GroupByKey ,ReduceByKey — 預設情況下,此操作使用帶有預設引數的雜湊分割槽。

什麼是分割槽器?
分割槽器是一個物件,它定義了鍵值對 RDD 中的元素如何按鍵分割槽,將每個鍵對映到從 0 到 numPartitions - 1 的分割槽 ID。
它在輸出端捕獲資料分佈。在分割槽器的幫助下,排程器可以最佳化未來的操作。分割槽器合約確保給定鍵的記錄必須駐留在單個分割槽上。我們應該選擇一個分割槽器用於類似 cogroup 的操作。如果任何一個 RDD 已經有一個分割槽器,我們應該選擇那個。否則,我們使用預設的 HashPartitioner。

Spark 中有不同型別的分割槽器:

a) Hash Partitioner :- 以這樣的方式分割我們的資料,使得具有相同雜湊的元素(可以是鍵、鍵或函式)將在同一個分割槽中。我們還可以傳遞想要的分割槽數,以便最終確定的分割槽為 hash % numPartitions。請注意,如果 numPartitions 大於具有相同雜湊的組數,則會有空分割槽。使用示例:df.repartiton(10, 'class_id')

Apache Spark:分割槽和分桶 - Nivedita
雜湊分割槽可以使分散式資料傾斜。

b) Range Partitioner : - 與雜湊分割槽非常相似,只是它基於一系列值。由於效能原因,此方法使用抽樣來估計範圍。因此,輸出可能不一致,因為取樣可以返回不同的值。樣本大小可以透過配置值來控制spark.sql.execution.rangeExchange.sampleSizePerPartition。使用示例:df.repartitionByRange(10, 'grade')

Apache Spark:分割槽和分桶 - Nivedita

c) 迴圈分割槽:將資料從源分割槽數以迴圈方式分配到目標分割槽數,以保持結果分割槽之間的均勻分佈。由於重新分割槽是一個shuffle操作,如果我們不傳遞任何值,它將使用上面提到的配置值來設定最終的分割槽數。使用示例:df.repartition(10).

Apache Spark:分割槽和分桶 - Nivedita
Spark 中的分桶

Bucketing是 Spark 和 Hive 中用於最佳化任務效能的一種技術。在分桶桶(叢集列)中確定資料分割槽並防止資料混洗。根據一個或多個分桶列的值,將資料分配給預定義數量的桶。

Apache Spark:分割槽和分桶 - Nivedita

分桶有兩個主要好處:

  • 改進的查詢效能:在連線時,我們可以在相同的分桶列上明確指定桶的數量。由於每個儲存桶包含相同大小的資料,因此對映端連線的效能優於儲存桶表上的非儲存桶表。在 map-side join 中,左側表儲存桶將準確知道右側儲存桶包含的資料集,以便以結構良好的格式執行表聯接。
  • 改進的取樣:資料已經被分成更小的塊,因此取樣得到了改進。

何時使用桶列

  • 表大小很大(> 200G)。
  • 該表具有高基數列,這些列經常用作過濾和/或連線鍵。
  • 中等大小的表,但主要用於連線一個巨大的桶化表,桶化它仍然是有益的
  • 排序合併連線(沒有儲存桶)由於隨機播放而不是由於資料傾斜而變慢

如何配置儲存桶列

  • 選擇高基數列作為桶列。
  • 儘量避免資料傾斜。
  • 至少 500 個桶(因為小桶數會導致並行執行不佳)。
  • 排序桶是可選的,但強烈推薦。

如何在 Spark 中建立資料桶

  • 下面是在 SparkAPI 中建立儲存桶的示例。bucketBy是在 spark 中建立儲存桶的函式。我們需要將桶的資訊儲存在某處,所以這裡需要使用saveAsTable來儲存桶表的後設資料資訊。

# n 是要建立的桶數df.write.mode(“save_mode”).option(“path”, “s3 path/hdfs path”) \.bucketBy(n, 'col1', 'col2'..) \.sortBy('col1', ' col2') \.saveAsTable('table_name', format='parquet')df = spark.table('table_name')
  • 在上面的示例中,我們使用了 bucketBy 和 sortBy,因為在某些情況下我們有多個連線鍵,並且希望將整數鍵放在 bucketBy 中,將字串鍵放在 sortBy 中。當我們做資料桶時,sortBy 是可選的。
  • 可以根據資料大小和我們對資料執行的查詢來決定儲存桶大小的數量。通常,每個儲存桶可能更喜歡 100 MB 到 200 MB。
  • 儲存桶表將使用以下命名約定將表儲存在路徑中。

如何在 Spark 上啟用分桶?
預設情況下啟用分桶。或者,您可以在 Spark Shell 或屬性檔案中設定以下屬性。

設定 spark.sql.sources.bucketing.enabled=true

Spark 中對錶進行分桶的優點

  • 最佳化表。
  • 使用預洗牌分桶表時最佳化聯接。
  • 當您在分桶列上定義謂詞時,啟用更有效的查詢。
  • 最佳化了對錶資料的訪問。在桶列上使用 WHERE 條件時,您將最小化給定查詢的表掃描。
  • 將資料均勻分佈在不同的儲存桶中,從而實現對錶資料的最佳訪問。

轉換列表
以下轉換將受益於分桶:

  • 加入
  • 清楚的
  • 透過...分組
  • 減少

Spark Bucket 的限制
Spark Bucketing 有其自身的侷限性,我們在建立分桶表以及將它們連線在一起時需要非常小心。
為了最佳化連線並在 Spark 中使用分桶,我們需要確保以下幾點:

  1. 兩個表都使用相同數量的儲存桶進行儲存。如果加入表中的桶號不同,則不會應用預洗牌。
  2. 兩個表都儲存在同一列上以進行連線。由於資料是根據給定的分桶列進行分割槽的,如果我們不使用同一列進行連線,那麼您就沒有使用分桶,它會影響效能。

Spark 分桶與 Hive 分桶有何不同?
在 Hive 中,我們需要根據需要建立檔案數量的 reducer。
而在 Spark 分桶中,我們沒有減速器。因此,它最終會根據任務的數量建立 n 個檔案。

Apache Spark:分割槽和分桶 - Nivedita

Apache Spark:分割槽和分桶 - Nivedita

相關文章