1. 产生来源
- 阅读以下代码
val lines = sc.textFile("hdfs://...")
lines.filter(_.contain("my")).count //第一个job
lines.filter(_.contain("my1")).count //第二个job
- 分析代码
上面的代码当执行到第一个job的时候触发一个job,当执行时会去hdfs中下载文件并执行; 当第二次count时又触发了一个job又需要去hdfs读取文件, 合理?
2. cache
- 此处如果使用了cache算子,那么在执行第二个count的时候数据可以直接从缓存中获取
- 实际上cache底层也是使用的persist算子
def cacheDemo(hdfsUrl:String, sc:SparkContext): Unit = {
var lines: RDD[String] = sc.textFile(hdfsUrl)
lines = lines.cache()
val s1 = System.currentTimeMillis()
lines.count()
val e1 = System.currentTimeMillis()
lines.count()
val e2 = System.currentTimeMillis()
println("first count " + (e1 - s1))
println("first count " + (e2 - e1))
}
3. persist
- persist他可以指定使用哪一个级别的缓存, 所有的缓存级别在StorageLevel中的有
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtFtHH6M-1586398176300)(en-resource://database/1415:1)]
- 使用案列
var lines: RDD[String] = sc.textFile(hdfsUrl)
lines = lines.persist(StorageLevel.MEMORY_AND_DISK)
val s1 = System.currentTimeMillis()
lines.count()
val e1 = System.currentTimeMillis()
lines.count()
val e2 = System.currentTimeMillis()
println("first count " + (e1 - s1))
println("first count " + (e2 - e1))
4. cache & persist
- 他们都是懒执行的, 并且持久化最小单元为为partition
- 调用方法后需要赋值给一个RDD, 之后直接使用生成的这个RDD
- 缓存的数据在Application执行完成之后自动清除
5. checkpoint
-
作用: 将数据直接持久化到指定目录,当lineage计算非常复杂,可以尝试使用checkpoint;checkpoint还可以切断RDD的依赖关系
-
注意: checkpoint的做法是先把job执行完, 然后回溯到第一个RDD一个一个的检查是否做了checkpoint然后重新计算缓存;为了解决这个问题可以对需要checkpoin 的RDD先进行cache
val lines: RDD[String] = sc.textFile(hdfsUrl)
sc.setCheckpointDir("/directory")
lines.checkpoint()
val s1 = System.currentTimeMillis()
lines.count()
val e1 = System.currentTimeMillis()
lines.count()
val e2 = System.currentTimeMillis()
println("first count " + (e1 - s1))
println("first count " + (e2 - e1))