文章目录
1. RDD自身容错性
RDD的Lineage记录的是:粗颗粒度的特定数据Transformation操作(如filter、map、join等)行为。
在容错机制中,如果一个节点死机了,而且运算窄依赖,则只要把丢失的父RDD分区重算即可,不依赖于其他节点。而宽依赖需要父RDD的所有分区都存在,重算就很昂贵了。可以这样理解开销的经济与否:在窄依赖中,在子RDD的分区丢失、重算父RDD分区时,父RDD相应分区的所有数据都是子RDD分区的数据,并不存在冗余计算。在宽依赖情况下,丢失一个子RDD分区重算的每个父RDD的每个分区的所有数据并不是都给丢失的子RDD分区用的,会有一部分数据相当于对应的是未丢失的子RDD分区中需要的数据,这样就会产生冗余计算开销,这也是宽依赖开销更大的原因。
缺点:由于这样的粗颗粒的数据模型,限制了Spark的运用场合,所以Spark并不适用于全部高性能要求的场景。
2. checkpoint机制
2.1 问题
Spark 在生产环境下经常会面临 Transformation 的 RDD 非常多(例如一个Job 中包含1万个RDD) 或者是具体的 Transformation 产生的 RDD 本身计算特别复杂和耗时(例如计算时常超过1个小时) , 可能业务比较复杂,此时我们必需考虑对计算结果的持久化。如果采用 persists 把数据在内存中的话,虽然最快速但是也是最不可靠的;如果放在磁盘上也不是完全可靠的,例如磁盘会损坏,系统管理员可能会清空磁盘。
2.2 描述
在容错机制中,如果集群中一个节点死机了,而且运算窄依赖,则只需要把丢失的父RDD
分区重算即可,不依赖于其他节点。但对宽依赖,则需要父RDD
的所有分区都重算,这个代价就很昂贵了。因此,Spark
提供设置检查点的方式来保存Shuffle
前的祖先RDD
数据,将依赖关系删除。当数据丢失时,直接从检查点中恢复数据。为了确保检查点不会因为节点死机而丢失,检查点数据保存在磁盘中,通常是hdfs
文件。
2.3 总结
检查点(本质是通过将RDD写入Disk做检查点)是为了通过lineage做容错的辅助。lineage过长会造成容错成本过高。这样就不如在中间阶段做检查点容错,假设之后有节点出现故障而丢失分区。从做检查点的RDD开始重做Lineage,就会降低开销。
建议:做检查点的RDD
最好是已缓存在内存中,否则保存检查点的过程还需要重新计算,产生I/O
开销。
2.4 Cache(persist)原理 源码分析
2.4.1 Spark示例
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.PairFlatMapFunction;
import scala.Tuple2;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class demo9 {
private static String appName = "spark.demo";
private static String master = "local[*]";
public static void main(String[] args) {
JavaSparkContext sc = null;
try {
//初始化 JavaSparkContext
SparkConf conf = new SparkConf().setAppName(appName).setMaster(master);
sc = new JavaSparkContext(conf);
//设置检查点存放目录,window为例
sc.setCheckpointDir("hdfs://10.47.85.213/check");
//从test.txt 构建rdd
JavaRDD<String> rdd = sc.textFile("test.txt");