这几天面试被问到了好几次RDD,感觉都没令面试官满意,下面做了一些简单总结,欢迎大家指出问题:
可以从几个方面来回答,概念、源码层、容错性、缓存、分区等
概念
RDD,全称是弹性分布式数据集(Resilient Distributed Dataset),是spark底层的抽象概念,
弹性主要体现在 :其数据默认是放在内存中,只有放不下了才会放到磁盘,并且每个task执行失败可以进行重新计算;
分布式是因为数据被分到了多台机器(所以为什么说他抽象,是因为他不是一个具体的数据),且里面的数据可以并行计算;
这是我个人理解
源码分析
在RDD的源码中,有四个方法(getPartitions、compute、getDependencies、getPreferedLocations)和一个属性(partitioner),分别对应了其五个特点:分区,算子操作、依赖、位置优先计算、分区器
借用别人的图,侵删:
getPartitions:定义分区的规则,常见有HadoopPartition, JdbcPartition, ParallelCollectionPartition。
compute:定义了以何种形式处理这个partition中的元素.。
getDependencies:定义了child RDD的partition对parent RDD的依赖。关系,是宽依赖还是窄依赖
getPreferedLocations:寻找partition的首选位置,就近原则,本地有数据就取本地的数据,没有就去远程拉取。
partitioner:分区器,默认hash,还有range,也可以自定义。
容错性
RDD很重要的一个特性,RDD计算可以从失败的节点自动恢复,如果某个节点的RDD partition因为节点故障导致数据丢了或者其他问题,那么RDD会自动通过自己的数据来源重新计算该partition,这里分两种情况
- 如果是窄依赖,那么会重新计算子RDD对应的父RDD,这个计算的数据利用率是百分百;
- 如果是宽依赖,重新计算子RDD对应的父RDD,但是因为子RDD的数据来自多台机器,所有的父RDD都计算,但是并不是所有父RDD的子RDD都出现了错误或者丢失,所有计算会有冗余,数据利用率不是百分百;
我估计这里大家不太理解,所以我用脚画了一张图,
图中子RDD依赖于父RDD,我们看红色的分区,如果此时这个分区出现了错误,所有的父RDD都会重算,但是紫色的分区有一部分数据跑到了绿色分区上,但是同样进行了计算所以有计算的冗余
缓存
缓存也是RDD的很重要的一个特性,当我们进行计算的时候,遇到了很复杂或者耗时很长、依赖链很长的计算,就可以对之前的RDD操作进行缓存,以后就可以复用这部分的数据;
可以用persist,可以自行选择缓存级别(十二种),磁盘或者内存,常用的是cache(Memory_Only级别的persist),存内存用的时候快但是可能会丢失;
还有一种就是可以用Checkpoint,把计算持久化到比如HDFS,这种做法相对cache安全,而且会消除RDD之间的依赖,计算更高效;
具体操作时候可以两者结合,先cache,再checkpoint。
关于分区
为什么分区?MapReduce框架的性能开支主要在io和网络传输,io因为要大量读写文件,它是不可避免的,但是网络传输是可以避免的,把大文件压缩成小文件,从而减少网络传输,但是增加了cpu的计算负载。
Spark里面io也是不可避免的,但是网络传输spark里面进行了优化:
把rdd进行分区(分片),放在集群上并行计算。
在实际开发的时候,分区数决定了task个数,在shuffleMaptask过后,有多少分区就会有多少个task,除了修改配置参数,我们可以在提交任务的时候选择合适的参数,比如executor core个数,官方给出的建议是,这个task数目要是core总数的2-3倍为佳,在写代码初始化时设置defaultParalism或者某些算子,比如重分区repartition,或者加载数据源的时候在传参时给定其分区数。
合理的设置分区数,提高性能,分区太多太少都不好,分区多了任务个数多,耗时,分区少了资源利用率不高,而且容易产生数据倾斜。
以上
转载请点赞并注明出处
欢迎提建议和意见