spark|spark调优(三):持久化减少二次查询

spark|spark调优(三):持久化减少二次查询


1. 起因在我们接收到数据的时候 , 通常都需要etl处理一下 , 但原始数据最好也是入库保存一下最好 , 这样一份数据 , 我们就使用了2次 。
Spark中对于一个RDD执行多次算子的默认原理是这样的:每次你对一个RDD执行一个算子操作时 , 都会重新从源头处计算一遍 , 计算出那个RDD来 , 然后再对这个RDD执行你的算子操作 。 这种方式的性能是很差的 。
所以如果你先保存原始数据 , 再筛选一下的时候 , 会发现数据会重新被加载 , 这样是很浪费时间的 。
2. 优化开始对多次使用的RDD进行持久化 。 此时Spark就会根据你的持久化策略 , 将RDD中的数据保存到内存或者磁盘中 。 以后每次对这个RDD进行算子操作时 , 都会直接从内存或磁盘中提取持久化的RDD数据 , 然后执行算子 , 而不会从源头处重新计算一遍这个RDD , 再执行算子操作 。
如果要对一个RDD进行持久化 , 只要对这个RDD调用cache()和persist()
cache()方法表示:使用非序列化的方式将RDD中的数据全部尝试持久化到内存中 。
persist()方法表示:手动选择持久化级别 , 并使用指定的方式进行持久化 。
df = sc.sql(sql)
df1 = df.persist()
df1.createOrReplaceTempView(temp_table_name)
subdf = sc.sql(select * from temp_table_name)

这种情况就不会重新加载RDD 。
对于persist()方法而言 , 我们可以根据不同的业务场景选择不同的持久化级别 。

持久化级别
含义解释
MEMORY_ONLY
使用未序列化的Java对象格式 , 将数据保存在内存中 。 如果内存不够存放所有的数据 , 则数据可能就不会进行持久化 。 那么下次对这个RDD执行算子操作时 , 那些没有被持久化的数据 , 需要从源头处重新计算一遍 。 这是默认的持久化策略 , 使用cache()方法时 , 实际就是使用的这种持久化策略 。
MEMORY_AND_DISK
使用未序列化的Java对象格式 , 优先尝试将数据保存在内存中 。 如果内存不够存放所有的数据 , 会将数据写入磁盘文件中 , 下次对这个RDD执行算子时 , 持久化在磁盘文件中的数据会被读取出来使用 。
MEMORY_ONLY_SER
基本含义同MEMORY_ONLY 。 唯一的区别是 , 会将RDD中的数据进行序列化 , RDD的每个partition会被序列化成一个字节数组 。 这种方式更加节省内存 , 从而可以避免持久化的数据占用过多内存导致频繁GC 。
MEMORY_AND_DISK_SER
基本含义同MEMORY_AND_DISK 。 唯一的区别是 , 会将RDD中的数据进行序列化 , RDD的每个partition会被序列化成一个字节数组 。 这种方式更加节省内存 , 从而可以避免持久化的数据占用过多内存导致频繁GC 。
DISK_ONLY
使用未序列化的Java对象格式 , 将数据全部写入磁盘文件中 。
MEMORY_ONLY_2 MEMORY_AND_DISK_2 等等.
对于上述任意一种持久化策略 , 如果加上后缀_2 , 代表的是将每个持久化的数据 , 都复制一份副本 , 并将副本保存到其他节点上 。 这种基于副本的持久化机制主要用于进行容错 。 假如某个节点挂掉 , 节点的内存或磁盘中的持久化数据丢失了 , 那么后续对RDD计算时还可以使用该数据在其他节点上的副本 。 如果没有副本的话 , 就只能将这些数据从源头处重新计算一遍了 。
如何选择一种最合适的持久化策略