home
diamond Go Premium
Data Engineering Path  ·  PySpark

Scenario: Memory Intensive Join

Scenario: Resolving Executor Out-Of-Memory During Skewed Join

The Challenge

A data engineer is running a Spark SQL query that joins a giant transactional table (1 TB) with a medium-sized advertiser metadata table (5 GB). The join key is heavily skewed (e.g., a few advertising IDs account for 70% of the transactions). When submitting the job with standard parameters, Spark tasks fail repeatedly on worker nodes with YARN errors like: ExecutorLostFailure (executor 4 exited caused by JVM parameter limits / Container killed by YARN for exceeding memory limits).


1. Optimal Spark-Submit Configuration

spark-submit \
    --master yarn \
    --deploy-mode cluster \
    --name "Skewed-Advertiser-Join-ETL" \
    --num-executors 15 \
    --executor-cores 4 \
    --executor-memory 24g \
    --driver-memory 8g \
    --conf spark.yarn.executor.memoryOverhead=6144m \
    --conf spark.sql.adaptive.enabled=true \
    --conf spark.sql.adaptive.skewJoin.enabled=true \
    --conf spark.sql.autoBroadcastJoinThreshold=104857600 \
    --conf spark.memory.fraction=0.8 \
    hdfs:///scripts/skewed_join_job.py

2. Parameter Explanations & Rationale

  • --executor-memory 24g / --conf spark.yarn.executor.memoryOverhead=6144m: We significantly increase executor memory and increase the YARN container memory overhead buffer to 6 GB (25% of executor memory instead of the default 10%). This extra buffer prevents YARN from killing containers due to memory overhead spikes during heavy data shuffles.
  • spark.sql.adaptive.enabled=true & skewJoin.enabled=true: Activates Adaptive Query Execution (AQE). When Spark detects a skewed partition during execution, it automatically splits the skewed partition into smaller sub-partitions and joins them independently, preventing a single task from running out of memory.
  • spark.sql.autoBroadcastJoinThreshold=104857600: Sets the broadcast limit to 100 MB. Since our metadata table is 5 GB, we do not want to force a broadcast join (which would copy 5 GB to all executors and cause Driver/Executor OOMs). This enforces a safe Shuffle Hash Join or Sort Merge Join.
  • spark.memory.fraction=0.8: Increases the memory fraction allocated to Spark execution and storage (from the default 0.6 to 0.8) to maximize available heap space for caching skewed partitions during joins.
  • Reduced Cores (--executor-cores 4): Allocating 4 cores instead of 5 gives each active thread more available memory (6 GB per core instead of 4.8 GB per core), helping tasks process larger data partitions without spilling to disk or crashing the JVM.
Find this content helpful? ☕ Buy me a coffee

Entity Details

Create New Item

celebration
Enjoying the free content?

Create a free account to track your progress and save your place.

Create Free Account
help

Submit Technical Query

Have a question or run into an issue? Describe it below, upload an optional screenshot, and our engineering team will answer it!

image Attach image (optional)

Submit Feedback

build Free Developer Utility Free Tool
gavel

Privacy & Legal Disclaimer

1. Client-Side Browser Processing

All utility tools on DeepEngineerHub (including Image to PDF, Text Formatters, JSON Converters, and Encryptors) execute 100% locally within your client browser using WebAssembly and JavaScript. No uploaded images, text, or documents are transmitted, collected, or stored on remote servers.

2. Limitation of Liability ("As-Is" Provision)

Tools and services are provided free of charge for convenience and educational purposes "as-is" without warranties of any kind. DeepEngineerHub shall not be held liable for any data loss, formatting inconsistencies, or indirect damages resulting from tool usage.

3. Open Source & Third-Party Software

Certain utilities utilize open-source client libraries (such as jsPDF, Mermaid.js, Pyodide) licensed under MIT, Apache, or BSD open licenses. All intellectual property remains with their respective copyright holders.