• 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
	}
}

spark shuffle read coalesce设置成200 spark shuffle spill memory_spark


当执行端的内存没有被占用的时候,存储端可以获得执行端的内存来进行使用,执行端的内存被存储端占用之后,如果此时执行端需要使用内存,那么会将存储端占用的那部分内存强制剔除

当存储端空闲,执行端繁忙的时候,执行端可以借用存储端的内存,当存储端需要用的时候,内存端是不会还的