設定 Spark 執行器的數量
1. 引言
Apache Spark 賦予我們強大的控制權,讓我們掌控應用程式在叢集上的運作方式。效能和資源利用率的關鍵因素之一是作業使用的執行器數量。執行器是執行 Spark 驅動程式指派的任務的工作節點。正確配置執行器有助於我們提升效能並充分利用叢集資源。
在本教程中,我們將解釋什麼是執行器,為什麼它們的配置很重要,以及如何在靜態和動態分配模式下設定它們。
2. 了解 Spark 執行器
執行器是在工作節點上啟動的 JVM 進程。執行器執行三個主要任務:
- 運行 Spark 驅動程式分配的任務
- 資料儲存在記憶體或磁碟上(用於快取和洗牌操作)
- 向司機報告執行狀態和指標。
每個執行器並行運行多個任務。 **The number of concurrent tasks depends on the number of CPU cores assigned to that executor. More executors usually increase parallelism, but only when sufficient data and cluster resources are available.**
Spark 應用總是只有一個驅動程序,但可以有多個執行器。叢集管理器(YARN、Kubernetes 或獨立運作)決定執行器的運作位置,而我們則決定 Spark 請求的執行器數量和大小。
為了有效率地管理資源,Spark 提供了兩種主要的執行器分配策略:
- 靜態分配:Spark 的執行器數量是固定的。
- 動態分配:Spark 會根據工作負載在運行時調整執行器的數量。
3. 靜態分配
**Static executor allocation means that the number of executors is fixed for the entire lifetime of the Spark application.**會向叢集管理器要求指定數量的執行器,並使其在應用程式的整個生命週期內保持運作。
執行器不會動態地進行擴展或縮減。這種方法適用於資源需求可預測的工作負載,例如每日批次作業。
配置靜態執行器主要有三種方法:
3.1. 使用spark-submit
啟動 Spark 應用程式的標準方法是使用spark-submit命令列工具。它是叢集上運行應用程式的主要入口點,允許我們在提交時定義資源需求。
提交 Spark 應用程式時,我們可以使用–num-executors選項來設定執行器的數量。我們通常會將其與–executor-cores和–executor-memory結合使用,以定義每個執行器的資源:
spark-submit \
--class com.example.MyApp \
--master yarn \
--num-executors 8 \
--executor-cores 4 \
--executor-memory 8G \
my-spark-app.jar
在這個例子中,Spark 啟動了 8 個執行器,每個執行器有 4 個核心和 8 GB 記憶體。這些執行器在應用程式的整個運行時期間都會保持分配狀態。
3.2. 使用 Spark 設定文件
我們也可以在spark-defaults.conf或其他設定檔中定義靜態執行器。當我們想要外部化資源設定時,這非常有用:
spark.executor.instances 8
spark.executor.cores 4
spark.executor.memory 8G
停用動態分配後,Spark 將在每次提交作業時使用這些設定。這種方法非常適合跨多個應用程式標準化資源分配。
3.3. 在應用程式中以程式設計方式
我們可以透過在執行任何操作之前,在程式碼中設定 Spark 屬性,以程式設計方式配置靜態執行器:
SparkSession spark = SparkSession.builder()
.appName("StaticExecutorExample")
.config("spark.executor.instances", "8")
.config("spark.executor.cores", "4")
.config("spark.executor.memory", "8G")
.getOrCreate();
這種方法允許應用程式在運行時決定執行器配置,這在動態部署管道中非常有用,儘管它不如其他兩種方法常見。
**Static allocation works best when the workload size is known and stable, especially on a dedicated or lightly shared cluster. It is best when predictable performance matters more than flexibility.**
4. 動態分配
**Dynamic executor allocation allows Spark to adjust the number of executors at runtime based on workload.**當有待處理任務時,會新增執行器;當執行器閒置一段時間後,則會移除執行器。這種方法可以提高叢集利用率,尤其是在多個應用程式並發運行的共享環境中。
與靜態分配不同,我們不設定固定數量的執行器。相反,我們定義最小和最大執行器數量,並讓 Spark 在此範圍內進行擴展。
我們可以使用與靜態分配相同的方法來配置動態分配,例如透過 spark-submit、設定檔或程式化設定。要透過spark-submit啟用動態分配,我們可以使用以下配置:
spark-submit \
--conf spark.dynamicAllocation.enabled=true \
--conf spark.dynamicAllocation.minExecutors=2 \
--conf spark.dynamicAllocation.maxExecutors=20 \
--conf spark.dynamicAllocation.initialExecutors=4 \
--conf spark.shuffle.service.enabled=true \
my-app.jar
在這個例子中,我們配置動態分配的下限和上限:
-
minExecutors:定義最小執行器數量,以確保基本的並行度。 -
maxExecutors:設定執行器的最大數量,防止 Spark 請求過多的叢集資源。 -
initialExecutors:控制 Spark 在應用程式啟動時指派的執行器數量。
在這些設定下,Spark 初始配置為 2 個執行器,並可根據工作負載增加擴展到最多 20 個。每個執行器並行運行 4 個任務。當執行器在配置的逾時時間內保持空閒時,Spark 會自動將其移除,使叢集能夠有效率地回收未使用的資源。
**Dynamic allocation is ideal for jobs with unpredictable or fluctuating resource requirements. It ensures efficient use of cluster resources without manually tuning executor counts for every job.**
5. 執行器和並行性
**Executors determine how Spark runs tasks in parallel** 。每個執行器都擁有固定數量的 CPU 核心。 Spark 會為每個核心調度一個任務。這表示一個作業的總平行度大致為:
total_parallel_tasks = number_of_executors × executor_cores
例如,8 個每台有 4 個核心的執行器可以同時執行 32 個任務。
並行性也取決於分區。每個分區對應一個任務。如果分區數少於核心總數,則部分核心會處於空閒狀態。如果分割區數很多,Spark 會將任務分批分配到可用的核心上進行處理。
平衡執行器數量和每個執行器的核心數非常重要:
- 使用更少核心的多執行器:更好的負載分配,尤其適用於許多小任務。
- 較少的執行器搭配較多的核心:對於 CPU 密集型任務來說效率可能很高,但可能會造成爭用。
**In addition, Spark has settings like spark.default.parallelism, which control how many tasks it creates.**這些設定會與執行器交互,但不會直接指派執行器。
6. 結論
本文探討如何為 Spark 應用程式設定執行器。配置執行器對 Spark 的效能和資源效率至關重要。
靜態分配提供可預測的執行結果,而動態分配則可根據不斷變化的工作負載進行調整。選擇合適的方法有助於我們有效地平衡並行性和群聚利用率。
和往常一樣,程式碼已上傳至GitHub。