簡體   English   中英

作為執行程序和線程數量的函數,spark中的分區數量是多少?

[英]What is a good number of partitions in spark as a function of number of executors and threads?

我在EMR上使用Spark。 我啟動集群,有時集群很小(在編寫/測試代碼時),例如5-10個實例。 其他時間則使用大量實例(例如30-50)執行同一代碼。

我知道我可以訪問配置以幫助設置分區數,選擇合適的分區數有助於運行時。

我想根據執行程序的數量和線程的數量來參數化分區的數量:

val instanceCount = sc.getConf.get("spark.executor.instances").toDouble
val coreCount = sc.getConf.get("spark.executor.cores").toDouble

有沒有人研究過這個問題,並且可以就分區數量的參數化提供任何建議?

我意識到沒有一個好的答案,而是某種函數形式,常量將有所幫助。 例如:

val partitionCount = instanceCount*coreCount*0.7 

在我的用例中似乎工作得很好,並描述您的用例(執行者的數量/范圍),這將有所幫助。

在答案中,如果您可以指出實例的范圍,那么您的工作也會很有幫助。 如果在某處對此進行了規范的調查,則指向該點的指針將有所幫助。

沒有針對所有用例的最佳配置,但是我將為您提供我在Spark體驗中收集的所有啟發式方法。

分區多於核心

首先,讓我們說明一下顯而易見的內容。 您需要的分區(給定階段中的任務)比內核更多,否則某些內核將無所事事。 此經驗法則是否有例外? 是:

  • 您也可以並行運行多個作業。 假設您有1000個小型數據集,則需要獨立於其他數據集對它們進行一些轉換。 您可能不想將每個數據集划分為128k文件,但是您可以並行運行128個分區的多個作業,以最大程度地利用核心數量。 請注意,我只知道如何通過設置spark.scheduler.mode=FAIR在單個步驟內或在自定義托管的YARN集群上spark.scheduler.mode=FAIR 我從來沒有嘗試過提交並行的EMR步驟,也不知道是否有可能,這不是常規的YARN概念(但同樣,如果需要,您可以在同一步驟中完成)。
  • 您的任務本身是並行的。 這絕對不是常規用例,我一般不建議這樣做,但是我不得不在Spark上並行化一些MXNet分類代碼。 Java代碼創建一個Python進程,該進程使用MXNet進行預測,然后將結果返回給Java。 由於MXNet在內部是並行的,並且非常善於使用內核,因此我發現通過擁有盡可能多的計算機(因此采用盡可能小的實例)並且每台計算機僅兩個執行程序(容器),吞吐量會大大提高。 每個執行者都在創建一個用於服務4個Spark任務(分區)的MXNet進程,這足以使我的CPU使用率最大化。 在不限制MXNet進程數量的情況下,CPU始終固定為100%,並且在上下文切換中浪費了大量時間。

每個分區有大量數據

小分區會導致作業變慢,因為驅動程序和從屬之間存在一定量的通信,如果您有10萬個小任務,這確實會占用大量時間。 如果您的任務在1秒內完成,則分區肯定太小。

反之,大分區會損害內存,尤其是在隨機播放期間。 隨機播放對內存的要求很高,將使您進行大量垃圾收集。 如果分區太大,則會增加內存用盡的風險,或者最好將50%以上的時間花費在GC上。 序列化形式的2GB是分區大小的絕對限制,因為Spark使用Java Java IO實用程序,該實用程序由字節數組支持,該字節數組只能容納2^31 - 1int大小)個元素。

通常,如果您要進行隨機播放(通常在這里談論JSON和文本數據),我建議壓縮格式大約為25MB-70MB。

廣播

如果您需要向所有執行者廣播一些對象(例如,布隆過濾器以在改組數據集之前減小其大小),則所需的容器數將由您願意在其上使用的內存量決定。每台機器都可以保存您的廣播。 實際上,每個執行器將廣播一次該對象,因此,假設同構集群,每台計算機的廣播數據量為object_size * num_executors / num_ec2_instances 網絡成本也隨着容器數量的增加而增加,因為該對象需要多次廣播到每個EC2實例。

但是,我遇到的情況是我的廣播對象是一個邏輯模型,該模型在分類過程中使用了一些內部可變狀態。 這意味着predict方法已同步,並且容器中的所有線程都在爭奪訪問此鎖的權限。 通過增加容器的數量(從而增加廣播的內存和網絡成本),我使這項工作快了4倍。

摘要

分區的數量由數據的大小決定,而不是由可用內核的數量決定。 如果您的數據不需要超過200個分區,那么就不要采用大於200個核心的群集,如果分區的大小已經足夠合理,那么增加分區和核心的數量可能不會有任何有意義的速度。

只要您的數據大小合適且分區平衡,則剩下的唯一試探法是:

  • 使用至少與分區一樣多的核心
  • 如果您想增加吞吐量,但並行運行多個作業(如果可以的話),但是您的分區已經足夠大了
  • 避免在任務中運行多線程代碼,但在極少數情況下需要使用它,請考慮將分區數少於核心數,這與我們之前所說的相反。
  • 您擁有的容器越多,廣播的費用就越高(廣播期間的網絡活動更多,直到銷毀之前的內存使用量更多)。 如果廣播的對象是完全不變的,請嘗試使用盡可能少的容器。 如果您的容器具有某種內部狀態並需要鎖定,則每個容器中的線程過多可能會增加爭用並降低速度。

暫無
暫無

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

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