文章目录
本文原地址在 www.zicesun.com icesuns.github.io
Spark是一个基于分布式内存的大数据计算框架,RDD (Resilient Distributed Dataset)是Spark最重要的一个数据抽象。这篇文章记录了我对RDD的一些理解,有不足和错误的地方,请留言指正。
什么是RDD
RDD (Resilient Distributed Dataset),弹性分布式数据集,是数据集合的抽象。它代表一个不可变、可分区、里面的元素可并行计算的集合。RDD具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。
RDD的计算具有惰性,只有在RDD需要讲计算结果提交到Driver或者需要把数据写到文件的时候,计算才真正开始。Spark为RDD的计算提供了两类接口,也就是转换(transformation)操作和动作(action)操作。其中转换操作,是将RDD转换成另一个RDD,这一步计算是具有惰性延迟的,不会立即执行计算。RDD不能改变,在转换的过程中只会生成一个新的RDD。动作操作,会激发计算。
RDD的转换操作和动作操作会在后续的博客中详细介绍。
RDD的接口
在介绍RDD的接口之前,先带着几个思考:
- RDD的结构是什么样子的,怎么表示并行计算单元。
- RDD是分布式数据集合的抽象,但是在分布式条件下,RDD怎么保证数据分布均匀?
- RDD的计算具有惰性,那么它怎么保证计算的准确性,计算流程是什么样的?
- 大数据计算,怎么容错?当Spark数据丢失之后,怎么保证数据的可靠性和完整性。
RDD通过实现一些接口来完成上述的一些问题。
分区(Partition)
RDD内部如何去表示并行计算的一个单元呢?其实是采用分区,也就是RDD的内部数据集合在逻辑上被划分为多个分片,这样每一个分片叫做分区(Partition)。分区的个数将决定并行计算的粒度,而每一个分区的数据的计算都是在一个单独的任务中进行,因此任务的个数是由RDD的分区的个数来决定的(准确来说应该是一个作业的最后一个RDD的分区数决定)。在下图中,每一个RDD里面的单元就是一个分区。
trait Partition extends Serializable{
def index:Int
override def hashCode():Int=index
}
上面的代码可以看出,分区在源码级别的实现是Partition类,其实是分区的一个标识,index表示这个分区在RDD中的编号。我们通过RDD的编号和Partition编号就可定位到具体的分区,通过接口,可以层存储介质中提取分区对应的数据。
RDD的分区的原则就是尽可能让分区的个数等于起核心的数目。当然用户也可以自指定分区的数