- 学习:知识的初次邂逅
- 复习:知识的温故知新
- 练习:知识的实践应用
目录
在 Spark 中,RDD(Resilient Distributed Dataset,弹性分布式数据集)的缓存机制是一种重要的性能优化手段。以下是关于 RDD 缓存机制的详细介绍:
一、缓存的目的
RDD 的缓存主要是为了提高 Spark 应用程序的性能。当一个 RDD 被多次使用时,如果每次都重新计算该 RDD,会消耗大量的时间和计算资源。通过缓存机制,可以将 RDD 存储在内存或磁盘中,以便在后续的操作中直接读取,避免重复计算,从而加快程序的执行速度。
缓存到内存之中
checkpoint缓存到HDFS中
二、缓存的方式
1,直接缓存
缓存是将数据存储在内存或者磁盘上,缓存的特点时,计算结束,缓存自动清空
-
缓存级别
-
指定缓存的数据位置
-
默认是缓存到内存上
-
torageLevel.DISK_ONLY # 将数据缓存到磁盘上
StorageLevel.DISK_ONLY_2 # 将数据缓存到磁盘上 保存两份
StorageLevel.DISK_ONLY_3 # 将数据缓存到磁盘上 保存三份
StorageLevel.MEMORY_ONLY # 将数据缓存到内存 默认
StorageLevel.MEMORY_ONLY_2 # 将数据缓存到内存 保存两份
StorageLevel.MEMORY_AND_DISK # 将数据缓存到内存和磁盘 优先将数据缓存到内存上,内存不足可以缓存到磁盘
StorageLevel.MEMORY_AND_DISK_2 = # 将数据缓存到内存和磁盘
StorageLevel.OFF_HEAP # 不使用 缓存在系统管理的内存上 heap jvm的java虚拟机中的heap
StorageLevel.MEMORY_AND_DISK_ESER
# 将数据缓存到内存和磁盘 序列化操作,按照二进制存储,节省空间
使用
-
persist
使用该方法 -
cache 内部调用persist
-
手动释放 unpersist
# encoding=utf-8
from pyspark import SparkContext
from pyspark.storagelevel import StorageLevel
sc = SparkContext()
rdd = sc.parallelize(['a','b','c','d','a'])
res = rdd.map(lambda x:(x,1))
#缓存机制
res.persist(storageLevel=StorageLevel.MEMORY_AND_DISK)
#NameError: name 'StorageLevel' is not defined
print(res.collect()) #触发缓存
res1 = res.reduceByKey(lambda x,y:x+y)
print(res1.collect())
# 缓存 实现持久化
from pyspark import SparkContext
from pyspark.storagelevel import StorageLevel
sc = SparkContext()
# 获取数据
rdd = sc.textFile('hdfs://node1:8020/data/students.txt')
rdd_line = rdd.map(lambda x:x.split(','))
# 将数据转为kv结构 (gender,age)
def func(x):
print('itcast')
return (x[2],int(x[3]))
rdd_gender_age = rdd_line.map(func)
# 进入reduce阶段
# 统计不同性别的学生数量
# 先对kv数据进行分组
rdd_groupby = rdd_gender_age.groupByKey()
# 对分组后的结果进行缓存
# # storageLevel 修改缓存级别
rdd_groupby.persist(storageLevel=StorageLevel.MEMORY_AND_DISK)
# 触发缓存
rdd_groupby.collect()
# 获取kv数据中value部分数据
rdd_count = rdd_groupby.mapValues(lambda x:len(list(x)))
# 统不同性别年龄最大值
rdd_max = rdd_groupby.mapValues(lambda x:max(list(x)))
# 统计不同性别的年龄最小值
rdd_min = rdd_groupby.mapValues(lambda x:min(list(x)))
# 统计不同性别的平均年龄
rdd_avg = rdd_groupby.mapValues(lambda x:sum(list(x))/len(list(x)))
# 查看数据
res_count = rdd_count.collect()
print(res_count)
res_max = rdd_max.collect()
print(res_max)
res_min = rdd_min.collect()
print(res_min)
res_avg = rdd_avg.collect()
print(res_avg)
2,checkpoint
也是将中间rdd数据存储起来,但是存储的位置实时分布式存储系统,可以进行永久保存,程序结束不会释放
如果需要删除就在hdfs上删除对应的目录文件
# checkpoint 持久化 将数据存储在hdfs上
from pyspark import SparkContext
# 创建对象
sc = SparkContext()
# 指定checkpoint存储的hdfs位置
sc.setCheckpointDir('hdfs://node1:8020/checkpoint')
# 生成rdd数据
rdd = sc.parallelize(['hadoop,spark','spark,python'])
# 字符串数据切割
rdd_split = rdd.map(lambda x:x.split(',')) # [[hadoop,spark],[spark,python]]
# 将二维列表转为一维
def func(x):
print('itheima')
return x
rdd_word = rdd_split.flatMap(func) # [hadoop,spark,spark,python]
# 持久化操作,可以使用缓存或checkpoint
# # 对rdd使用checkpoint
rdd_word.checkpoint()
# rdd_word.persist()
# # # 触发执行
print(rdd_word.getCheckpointFile())
# 将数据转为kv
rdd_kv1 = rdd_word.map(lambda x:(x,1))
rdd_kv2 = rdd_word.map(lambda x:(x,2))
rdd_kv3 = rdd_word.map(lambda x:(x,3))
rdd_kv4 = rdd_word.map(lambda x:(x,4))
rdd_kv5 = rdd_word.map(lambda x:(x,5))
# 查看kv数据
res = rdd_kv1.collect()
print(res)
res2 = rdd_kv2.collect()
print(res2)
res3 = rdd_kv3.collect()
print(res3)
res4 = rdd_kv4.collect()
print(res4)
res5 = rdd_kv5.collect()
print(res5)
# encoding=utf-8
from pyspark import SparkContext
sc = SparkContext()
rdd =sc.parallelize(['a','b','c'',d','a'])
rdd_tup = rdd.map(lambda x:(x,1))
#缓存到hdfs上面 设置checkpoint缓存存放的位置
sc.setCheckpointDir('hdfs://node1:8020/checkpoint')
rdd_tup.checkpoint()
# 触发执行
print(rdd_tup.getCheckpointFile(),'有东西麽')
print(rdd_tup.collect())
三、缓存的管理
1,自动清理
-
Spark 会自动管理缓存的 RDD,当内存不足时,会根据一定的策略清理一些不再使用的 RDD,以释放内存空间。
-
清理策略通常是基于 LRU(Least Recently Used,最近最少使用)算法,即优先清理最近最少使用的 RDD。
2,手动清理
-
用户也可以手动清理缓存的 RDD,使用
unpersist()
方法可以将一个缓存的 RDD 从内存和磁盘中移除。 -
在某些情况下,手动清理缓存可能是必要的,例如当缓存的 RDD 占用了大量的内存空间,而后续的操作不再需要这个 RDD 时。
四,两种缓存方式的区别
1,生命周期的区别
- 直接缓存,程序计算结束之后自动删除
- checkpoint 程序结束之后数据依然保留在HDFS中
2,存储位置的区别
- 缓存 邮箱存储在内存之中,也可以选择存储在本地磁盘,是在计算任务所在的内存和磁盘上
- checkpoint 存储在hdfs上
3,依赖关系
- 缓存数据之后,会保留RDD之间的依赖关系, 缓存临时数据,数据可能会丢失,所以需要保留依赖,当缓存丢失后会按照原来的依赖重新计算
- checkint,数据存储后会断开依赖,数据保存在hdfs中,hdfs的多副本机制可以保证数据不丢失,所以就没有必要保留依赖关系
五、缓存的注意事项
1,内存管理
-
缓存 RDD 会占用内存空间,因此需要合理管理内存,避免内存溢出。可以通过调整 Spark 的内存参数,如
spark.executor.memory
和spark.driver.memory
,来控制可用内存的大小。 -
同时,选择合适的存储级别也可以帮助管理内存。如果 RDD 较大,可以考虑使用磁盘缓存或序列化的方式来减少内存占用。
2,数据一致性
-
当对一个缓存的 RDD 进行修改时,需要注意数据的一致性。如果多个操作同时对一个缓存的 RDD 进行修改,可能会导致数据不一致的问题。
-
在这种情况下,可以使用
checkpoint
机制来创建一个检查点,将 RDD 的状态保存到可靠的存储系统中,如 HDFS。这样可以确保在出现故障时,能够从检查点恢复 RDD 的状态,保证数据的一致性。
3,缓存的时机
-
并不是所有的 RDD 都需要缓存。只有那些会被多次使用的 RDD 才值得缓存。如果一个 RDD 只被使用一次,缓存它可能不会带来性能提升,反而会占用内存空间。
-
因此,需要根据应用程序的实际情况,选择合适的时机进行缓存。可以在 RDD 被多次使用之前进行缓存,或者在一些关键的操作之前进行缓存,以提高性能。
六,总结
总之,RDD 的缓存机制是 Spark 中一种重要的性能优化手段。通过合理地使用缓存机制,可以大大提高 Spark 应用程序的性能。在使用缓存时,需要注意内存管理、数据一致性和缓存的时机等问题,以确保应用程序的稳定和高效运行。
- 学习:知识的初次邂逅
- 复习:知识的温故知新
- 练习:知识的实践应用