Spark RDD的缓存
- Spark速度非常快的原因之一,就是在不同操作中可以在内存中持久化或者缓存数据集。当持久化某个RDD后,每一个节点都将把计算分区结果保存在内存中,对此RDD或衍生出的RDD进行的其他动作中重用。这使得后续的动作变得更加迅速。RDD相关的持久化和缓存,是Spark最重要的特征之一。可以说,缓存是Spark构建迭代式算法和快速交互式查询的关键。
- Spark RDD 是惰性求值的,而有时我们希望能多次使用同一个RDD。如果简单地对RDD 调用行动操作,Spark 每次都会重算RDD 以及它的所有依赖。这在迭代算法中消耗格外大,因为迭代算法常常会多次使用同一组数据。
var input = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7))
val result = input.map(x => x*x)
println(result.count())//7
println(result.collect().mkString(","))//1,4,9,16,25,36,49
- 为了避免多次计算同一个RDD,可以让Spark 对数据进行持久化。当我们让Spark 持久化存储一个RDD 时,计算出RDD 的节点会分别保存它们所求出的分区数据。如果一个有持久化数据的节点发生故障,Spark 会在需要用到缓存的数据时重算丢失的数据分区。如果希望节点故障的情况不会拖累我们的执行速度,也可以把数据备份到多个节点上。
- 出于不同的目的,我们可以为RDD 选择不同的持久化级别。在Scala,默认情况下persist() 会把数据以序列化的形式缓存在JVM 的堆空间中。在Python 中,我们会始终序列化要持久化存储的数据,所以持久化级别默认值就是以序列化后的对象存储在JVM 堆空间中。当我们把数据写到磁盘或者堆外存储上时,也总是使用序列化后的数据。
RDD缓存方式
缓存级别 |
userDisk 是否使用磁盘 |
useMemory 是否使用内存 |
useOffHeap 是否使用堆外内存 |
deserialized 是否反序列化 |
replication 副本数 |
NONE |
false |
false |
false |
false |
1 |
DISK_ONLY |
true |
false |
false |
false |
1 |
DISK_ONLY_2 |
true |
false |
false |
false |
2 |
MEMORY_ONLY |
false |
true |
false |
true |
1 |
MEMORY_ONLY_2 |
false |
true |
false |
true |
2 |
MEMORY_ONLY_SER |
false |
true |
false |
false |
1 |
MEMORY_ONLY_SER_2 |
false |
true |
false |
false |
2 |
MEMORY_AND_DISK |
true |
true |
false |
true |
1 |
MEMORY_AND_DISK |
true |
true |
false |
true |
2 |
MEMORY_AND_DISK_SER |
true |
true |
false |
false |
1 |
MEMORY_AND_DISK_SER_2 |
true |
true |
false |
false |
2 |
OFF_HEAP |
true |
true |
true |
false |
1 |
●总结
持久化级别 |
说明 |
MEMORY_ONLY(默认) |
将RDD以非序列化的Java对象存储在JVM中。 如果没有足够的内存存储RDD,则某些分区将不会被缓存,每次需要时都会重新计算。 这是默认级别。 |
MEMORY_AND_DISK(开发中可以使用这个) |
将RDD以非序列化的Java对象存储在JVM中。如果数据在内存中放不下,则溢写到磁盘上.需要时则会从磁盘上读取 |
MEMORY_ONLY_SER (Java and Scala) |
将RDD以序列化的Java对象(每个分区一个字节数组)的方式存储.这通常比非序列化对象(deserialized objects)更具空间效率,特别是在使用快速序列化的情况下,但是这种方式读取数据会消耗更多的CPU。 |
MEMORY_AND_DISK_SER (Java and Scala) |
与MEMORY_ONLY_SER类似,但如果数据在内存中放不下,则溢写到磁盘上,而不是每次需要重新计算它们。 |
DISK_ONLY |
将RDD分区存储在磁盘上。 |
MEMORY_ONLY_2, MEMORY_AND_DISK_2等 |
与上面的储存级别相同,只不过将持久化数据存为两份,备份每个分区存储在两个集群节点上。 |
OFF_HEAP(实验中) |
与MEMORY_ONLY_SER类似,但将数据存储在堆外内存中。 (即不是直接存储在JVM内存中) 如:Tachyon-分布式内存存储系统、Alluxio - Open Source Memory Speed Virtual Distributed Storage |
- 总结
1.RDD持久化/缓存的目的是为了提高后续操作的速度
2.缓存的级别有很多,默认只存在内存中,开发中使用memory_and_disk
3.只有执行action操作的时候才会真正将RDD数据进行持久化/缓存
4.实际开发中如果某一个RDD后面频繁的被使用,那么就可以将该RDD进行持久化/缓存
最后,RDD 还有一个方法叫作unpersist(),调用该方法可以手动把持久化的RDD 从缓存中移除。