Explanation about Executor Summary in Spark Web UI - apache-spark

I have a few questions about the Executor section of Spark Web UI:
I see two numbers such as 0.0 B / 434.4 MiB under Storage Memory, On Heap Storage Memory, and Off Heap Storage Memory, what are those?
Also is Storage Memory the sum of On Heap Storage Memory and Off Heap Storage Memory?
With regard to Off Heap Storage Memory, does it purely come from OffHeap memory (set by spark.memory.offHeap.size) or include spark.executor.memoryOverhead? Not so sure the latter can be used for the dataframe storage though.
Thank you in advance!

I'm not exactly sure of which version you're on, so I'll make this answer for version 3.3.1 (latest version at the time of writing this post):
We can understand what those 2 numbers are by looking at the HTML code that generates this page.
Storage Memory: Memory used / total available memory for storage of data like RDD partitions cached in memory.
On Heap Storage Memory: Memory used / total available memory for on heap storage of data like RDD partitions cached in memory.
Off Heap Storage Memory: Memory used / total available memory for off heap storage of data like RDD partitions cached in memory.
Storage Memory is indeed the sum of On Heap and Off heap memory usage, both for:
the memory used
/**
* Storage memory currently in use, in bytes.
*/
final def storageMemoryUsed: Long = synchronized {
onHeapStorageMemoryPool.memoryUsed + offHeapStorageMemoryPool.memoryUsed
}
as for the total available memory
/** Total amount of memory available for storage, in bytes. */
private def maxMemory: Long = {
memoryManager.maxOnHeapStorageMemory + memoryManager.maxOffHeapStorageMemory
}
The off heap storage memory comes purely from the spark.memory.offHeap.size parameter, as can be seen here:
protected[this] val maxOffHeapMemory = conf.get(MEMORY_OFFHEAP_SIZE)
protected[this] val offHeapStorageMemory =
(maxOffHeapMemory * conf.get(MEMORY_STORAGE_FRACTION)).toLong
This MEMORY_OFFHEAP_SIZE is defined by spark.memory.offHeap.size:
private[spark] val MEMORY_OFFHEAP_SIZE = ConfigBuilder("spark.memory.offHeap.size")
.doc("The absolute amount of memory which can be used for off-heap allocation, " +
" in bytes unless otherwise specified. " +
"This setting has no impact on heap memory usage, so if your executors' total memory " +
"consumption must fit within some hard limit then be sure to shrink your JVM heap size " +
"accordingly. This must be set to a positive value when spark.memory.offHeap.enabled=true.")
.version("1.6.0")
.bytesConf(ByteUnit.BYTE)
.checkValue(_ >= 0, "The off-heap memory size must not be negative")
.createWithDefault(0)

Related

Spark evicting storage memory beyond the limit defined by spark.memory.storageFraction

I am running a small pyspark experiment on a dataproc cluster. I am not able to put together the dynamic memory allocation with what I am observing in the sparkUI
cluster configuration (directly from the env tab of the sparkUI):
spark.executor.instances = 4
spark.executor.memory = 6G
spark.executor.memoryOverHead = 2G
spark.executor.pyspark.memory = 2G
spark.memory.fraction = 0.6
spark.memory.offHeap.size = 2G
spark.memory.storageFraction = 0.5
So, my immune to eviction part of the heap is (accounting for 300 MB reserved memory)
(6*(1024)-300)*0.6*0.5
1753.2 MBs per executor
Since I have 4 executors, my overall heap immune to eviction should be
1753.2*4
7012.8 MBs or 6.85 GBs
Now, I read in a dataset (It is around 9.5 GB) and put it in the cache
df_sales = spark.read.option("format","parquet").option("header",True).option("inferSchema",True).load("gs://monsoon-credittech.appspot.com/spark_datasets/sales_parquet")
from pyspark import StorageLevel
df_sales = df_sales.persist(StorageLevel.MEMORY_AND_DISK)
df_sales.count()
My storage tab in the spark UI shows that I have been able to put all of the data in the memory and no disk spill occurred. It has just one row (expected) for the df_sales
Storage Level: Disk Memory Serialized 1x Replicated
Cached Partitions 83
Fraction Cached 100%
Size in Memory 9.5 GiB
Size on Disk 0.0B
Now, the part of the storage that is immune to eviction (6.5 GBs) should never be overtaken by execution unless I unpersist some data and make that memory available.
To test that I ran an operation that uses heavy execution memory (join) and then persisted the output and checked how the persisted output got divided between the disk and the memory. I used StorageLevel.MEMORY_AND_DISK
This is how I am doing it:
df_sales_copy = spark.read.option("format","parquet").option("header",True).option("inferSchema",True).load("gs://monsoon-credittech.appspot.com/spark_datasets/sales_parquet")
df_merged = df_sales.join(df_sales_copy,df_sales.order_id==df_sales_copy.order_id,'inner')
df_merged = df_merged.persist(StorageLevel.MEMORY_AND_DISK)
df_merged.count()
Now, my storage tab shows me numbers that I cannot make sense of. The eviction should never have reduced the storage memory below 6.85 GBs. However, the storage shows that it is reduced to 3.5 GBs. The storage tab now has two rows (expected), one for df_sales and the other for the df_merged
df_sales:
Storage Level: Disk Memory Serialized 1x Replicated
Cached Partitions 83
Fraction Cached 100%
Size in Memory 0.0 B #evicted as earlier it was 9.5 GiB
Size on Disk 9.5 GiB
df_merged:
Storage Level: Disk Memory Serialized 1x Replicated
Cached Partitions 200
Fraction Cached 100%
Size in Memory 3.4 GiB
Size on Disk 15.8 GiB
I have not called unpersist anywhere then why is spark allowed to evict memory below the hard threshold set by spark.memory.storageFraction

In spark what is the meaning of spark.executor.pyspark.memory configuration option?

Documentation explanation is given as:
The amount of memory to be allocated to PySpark in each executor, in MiB unless otherwise specified. If set, PySpark memory for an executor will be limited to this amount. If not set, Spark will not limit Python's memory use, and it is up to the application to avoid exceeding the overhead memory space shared with other non-JVM processes. When PySpark is run in YARN or Kubernetes, this memory is added to executor resource requests.
Note: This feature is dependent on Python's resource module; therefore, the behaviours and limitations are inherited. For instance, Windows does not support resource limiting, and actual resource is not limited on macOS.
There are two other configuration options. One controlling the amount of memory allocated to each executor - spark.executor.memory and, another controlling the amount of memory that each python process within an executor can use before it starts to spill memory over to disk - spark.python.worker.memory
Can someone please explain what then is the behaviour and use of spark.executor.pyspark.memory configuration and in what ways is it different from spark.executor.memory and spark.python.worker.memory?
I extended my answer a little bit. And please, follow the links, at the end of the article, they are pretty useful and have some pictures that help to understand the whole picture of spark memory management.
We should dig into spark memory management(mm) to figure out what is spark.execution.pyspark.memory.
So, first of all, there are two big parts of spark mm:
Memory inside JVM;
Memory outside JVM.
Memory inside JVM is divided into 4 parts:
Storage memory - this memory is for spark cached data, broadcast variables, etc;
Execution memory - this memory is for storing data required during execution spark tasks;
User memory - this memory is for user purposes. You can store here your custom data structure, UDFs, UDAFs, etc;
Reserved memory - this memory is for spark purposes and it hardcoded to 300MB as of spark 1.6.
Memory outside JVM is divided into 2 parts:
OffHeap memory - this memory of things outside JVM, but for JVM purposes or this memory is used for Project Tungsten;
External process memory - this memory is specific for SparkR or PythonR and used by processes that resided outside of JVM.
So, the parameter spark.executor.memory(or --executor-memory for spar-submit) responds how much memory will allocate inside JVM Heap per exectuor. This memory will split between: reserved memory, user memory, execution memory, storage memory. To control this splitting we need 2 more parameters: spark.memory.fraction and spark.memory.storageFraction
According to spark documentation:
spark.memory.fraction is responsible for fraction of heap used for execution and storage;
spark.memory.storageFraction is responsible for to amount of
storage memory immune to eviction, expressed as a fraction of the
size of the region set aside by spark.memory.fraction. So if
storage memory isn't used, execution memory may acquire all the
available memory and vice versa. This parameter controls how much
memory execution can evict if necessary.
More details here
Please look pictures of Heap memory parts here
Finally, Heap will be split in a next way:
Reserved memory is hardcoded to 300MB
User memory will calculate as (spark.executor.memory - reserved memory) * (1 - spark.memory.fraction)
Spark memory(which consists of Storage memory and Execution memory) will calculate as (spark.executor.memory - reserved memory) * spark.memory.fraction. Then all this memory will split between Storage memory and Execution memory with spark.memory.storageFraction parameter.
The next parameter you asked about is spark.execution.pyspark.memory. It's a part of External process memory and it's responsible for how much memory python daemon will able to use. Python daemon is used, for example, for executing UDFs had written on python.
And the last one is spark.python.worker.memory. In this article I had found the next explanation: JVM process and Python process communicate to each other with py4J bridge that exposes objects between JVM and Python. So spark.python.worker.memory is controlling how much memory can be occupied by py4J for creating objects before spilling them to the disk.
You can read about mm more in the next articles:
Memory management inside JVM;
Decoding Memory in Spark — Parameters that are often confused;
One more SO answer which explaining offheap memory configuration
Hot to tune apache spark jobs

Compaction cause OutOfMemoryError

I'm getting OutOfMemoryError when run compaction on some big sstables in production, table size is around 800 GB, compaction on small sstables is working properly though.
$ noodtool compact keyspace1 users
error: Direct buffer memory
-- StackTrace --
java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:693)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
at org.apache.cassandra.io.compress.BufferType$2.allocate(BufferType.java:35)
Java heap memory(Xms and Xmx) have been set to 8 GB, wondering if I should increase Java heap memory to 12 or 16 GB?
It's not the Heap size, but it's instead so-called "direct memory" - you need to check what amount you have (it's could be specified by something like this -XX:MaxDirectMemorySize=512m, or it will take the same max size as heap). You can increase it indirectly by increasing the heap size, or you can control it explicitly via -XX flag. Here is the good article about non-heap memory in Java.

Right Spark executor memory size given certain data size

A lot of the discussions I found on the internet on resource allocation was about the max memory config for --executor-memory, taking into account a few memory overheads.
But I would imagine that for simple job like reading in a 100MB file and then count # of rows, with a cluster of a total 500GB memory available across nodes, I shouldn't ask for # of executors and memory allocation that, with all memory overheads accounted for, could take all 500GB memory, right? Even 1 executor of 3GB or 5GB memory seems to be an overkill. How should I think about the right memory size for a job?
Thank you!

The actual executor memory does not match the executoy-memory I set

I hava a spark2.0.1 cluster with 1 Master(slaver1) and 2 worker(slaver2,slaver3),every machine has 2GB RAM.when I run the command
./bin/spark-shell --master spark://slaver1:7077 --executor-memory 500m
when I check the executor memory in the web (slaver1:4040/executors/). I found it is 110MB.
The memory you are talking about is Storage memory Actually Spark Divides the memory [Called Spark Memory] into 2 Region First is Storage Memory and Second is Execution Memory
The Total Memory can Be calculated by this Formula
(“Java Heap” – “Reserved Memory”) * spark.memory.fraction
Just to give you an overview Storage Memory is This pool is used for both storing Apache Spark cached data and for temporary space serialized data “unroll”. Also all the “broadcast” variables are stored there as cached blocks
If you want to check total memory provided you can go to Spark UI Spark-Master-Ip:8080[default port] in the start you can find Section called MEMORY that is total memory used by spark.
Thanks
From Spark 1.6 version, The memory is divided according to the following picture
There is no hard boundary between execution and storage memory. The storage memory is required more then it takes from execution memory and viceversa. The
Execution and storage memory is given by (ExecutorMemory-300Mb)* spark.memory.fraction
In your case (500-300)*).75 = 150mb there will be 3 to 5% error in Executor memory that is allocated.
300Mb is the reserved memory
User memory = (ExecutorMemory-300)*).(1-spark.memory.fraction).
In your case (500-300)*).25 = 50mb
Java Memory : Runtime.getRuntime().maxMemory()

Resources