- Spark Shuffle 参数
- Spark 的内存管理
- 静态内存管理
- 统一内存管理
Spark Shuffle 参数
在工作过程中,我们需要用到Spark Shuffle 相关的参数
参数名称 | 默认值 | 释义 |
spark.shuffle.consolidateFiles | true | 合并shuffle期间产生的中间文件 |
spark.shuffle.file.buffer shuffle | 32 | 缓冲区的大小建议调大成64 或128 |
spark.reducer.maxSizeInFlight | 32 | 从每个reduce任务中同时获取的最大map输出大小。由于每个输出都要求我们创建一个缓冲区来接收它,这表示每个reduce任务有固定的内存开销,因此,除非您有大量的内存,否则请保持较小的内存开销。建议调大点例如96M |
spark.shuffle.io.maxRetries | 3 | huffle拉取数据失败的最大的尝试次数 |
spark.shuffle.io.retryWait | 5s | 等待拉取数据的时间间隔 |
spark.shuffle.sort.bypassMergeThreshold | 200 | |
spark.shuffle.spill.compress | true | 是否压缩shuffle过程中溢写的文件,会默认使用spark.io.compress.codec 压缩 |
spark.io.compression.codec | lz4 | 压缩内部的数据,比如RDD的Partition、event log、广播变量、shuffle的输出,可以设置为lz4,lzf,snappy,zstd |
spark.shuffle.compress | true | 是否压缩Map端的输出文件配合上面的codec使用进行压缩 |
spark.shuffle.manager | HASH | 默认是Hash Spark 1.1 中可以设置为SORT |
Spark 的内存管理
主要分为两个方面:
execution:用于做计算 Execution memory refers to that used for computation in shuffles, joins, sorts and aggregations,
sotrage:用于存储 while storage memory refers to that used for caching and propagating internal data across the cluster.
内存管理:MemoryManager类
- spark.memory.useLegacyMode false 是否启用历史的模式进行内存管理
从配置中获取 SparkEnv.scala
中
Spark1.6 之后使用的是统一内存管理,之前使用的是静态内存管理
val useLegacyMemoryManager = conf.getBoolean("spark.memory.useLegacyMode", false)
val memoryManager: MemoryManager =
if (useLegacyMemoryManager) {
new StaticMemoryManager(conf, numUsableCores)//静态内存管理
} else {
UnifiedMemoryManager(conf, numUsableCores) // 统一内存管理
}
静态内存管理
静态内存管理的执行内存和存储内存是分开 的,当分配1G的内存的时候,实际上的能够使用执行内存是160M左右,能够使用的存储内存为540M左右。
StaticMemoryManager(conf, numUsableCores){
private def getMaxExecutionMemory(conf: SparkConf): Long = {,// 得到最大的执行内存
val memoryFraction = conf.getDouble("spark.shuffle.memoryFraction", 0.2) // 0.2
val safetyFraction = conf.getDouble("spark.shuffle.safetyFraction", 0.8) // 0.8
(systemMaxMemory * memoryFraction * safetyFraction).toLong // 1000M * 0.2 * 0.8 = 160M
}
private def getMaxStorageMemory(conf: SparkConf): Long = {// 得到最大存储内存
val systemMaxMemory = conf.getLong("spark.testing.memory", Runtime.getRuntime.maxMemory)
val memoryFraction = conf.getDouble("spark.storage.memoryFraction", 0.6)// 0.6
val safetyFraction = conf.getDouble("spark.storage.safetyFraction", 0.9)// 0.9
(systemMaxMemory * memoryFraction * safetyFraction).toLong // 1000M* 0.6 * 0.9 = 540M
}
}
统一内存管理
在统一内存管理中Sprk的执行内存和存储内存不再单独出来,默认情况下execution和storage各占百分之50,这块是可以动态调整的。
object UnifiedMemoryManager {
private val RESERVED_SYSTEM_MEMORY_BYTES = 300 * 1024 * 1024 // 300M 的系统预留内存
def apply(conf: SparkConf, numCores: Int): UnifiedMemoryManager = {
val maxMemory = getMaxMemory(conf){
val usableMemory = systemMemory - reservedMemory // 系统内存减去 预留内存1000-300=700M
val memoryFraction = conf.getDouble("spark.memory.fraction", 0.6)// 0.6
(usableMemory * memoryFraction).toLong // 700M * 0.6 = 420M
}
}
当执行端的内存没有被占用的时候,存储端可以获得执行端的内存来进行使用,执行端的内存被存储端占用之后,如果此时执行端需要使用内存,那么会将存储端占用的那部分内存强制剔除
当存储端空闲,执行端繁忙的时候,执行端可以借用存储端的内存,当存储端需要用的时候,内存端是不会还的