# Optimization Techniques for a Distributed In-Memory Computing Platform by Leveraging SSD
## 3 Optimization Techniques for the Spark Platform
### Spark JVM Heap  
A Spark job runs as a Java process on the Java Virtual Machine (JVM), and Spark exploits the Scala, a functional language extended from Java. The worker process of Spark also runs on the JVM of each datanode, so that on each datanode, the worker process has the JVM heap in the main memory as depicted in Figure 2. When Spark submits a job, the worker process that has the JVM heap executes the job as distributed tasks.  
We can customize the ratio of the JVM heap size of a Spark worker through the configuration file spark-defaults.conf in the spark/conf/ directory. In the spark-defaults.conf file, the value of spark.executor.memory is the JVM heap size where the default is 512 MB that each worker node can utilize in the datanode. In addition, the value of spark.storage.safetyFraction is fixed as 0.9, which means that Spark can actually use up to 90% of JVM heap size (also known as safety area). This is for preventing the JVM from generating OOM (out of memory) errors due to the lack of available main memory during the task processing.  
\begin{table}
\begin{tabular}{c c} \hline \hline
**Parts** & **Specifications** \\ \hline CPU & Intel Xeon E3-1240V3 \\ \hline Memory & 4 GB DRAM(DDR3-1600 Mhz ECC) \\ \hline Storage & 120 GB SSD SATA \\  & 512 GB SSD SATA \\ \hline Software & CentOS 6.6 \\  & Java Virtual Machine: OpenJDK 1.7.0 \\  & Hadoop: Apache Hadoop 2.6.2 \\  & Spark: Apache Spark 1.5.2 \\ \hline \hline \end{tabular}
\end{table}
Table 2: H/W and S/W configurations of a datanode.  
Figure 2: Spark JVM heap.  
In this safety area, the overall JVM heap space is divided into three sub-regions: _unroll_, _storage_, and _shuffle_ spaces, as we can see from Figure 2. The unroll space is used for unrolling data blocks in memory. When an RDD is cached on other storage media such as an SSD or HDD not on the main memory, the RDD should be _serialized_. Then, when Spark reads this RDD back to the memory, the RDD has to be _unrolled_. The storage space is used for _caching_ an RDD. If the storage space is not sufficient for caching the RDD, some RDDs can be evicted from this space based on the LRU (least recently used) policy, or they can be cached on other storage media, such as an SSD. The shuffle space is used for _shuffling_ the intermediate data. For iterative applications such as machine learning, this shuffle space can play an important role since it can substantially affect the overall job completion time.  
In the default Spark configuration, the storage and shuffle spaces of the JVM heap have capacity fraction ratios of 0.6 and 0.2, respectively (i.e., 60% of safety area for the storage and 20% for the shuffle). The unroll space takes 20% of the storage space by default. The capacity of these three spaces of JVM heap can be set by spark.storage.unrollFraction, spark.storage.memoryFraction, and spark.shuffle.memoryFraction. For example, in our testbed cluster, we can set the spark.executor.memory as 2.6 GB of the 4 GB memory of the worker node, which means that the JVM heap size is set to a maximum of 2.6 GB. Then, the actual capacities of storage space and shuffle space are 2.6 GB \(\times\) 0.9 \(\times\) 0.6 = 1.4 GB and 2.6 GB \(\times\) 0.9 \(\times\) 0.2 = 0.46 GB, respectively. Accordingly, the unroll space takes 1.4 GB \(\times\) 0.2 = 0.28 GB.