RDD,学名可伸缩的分布式数据集(Resilient Distributed Dataset)。初次听闻,感觉很高深莫测。待理解其本质,却发现异常简洁优雅。本文试图对其进行一个快速侧写,试图将这种大数据处理中化繁为简的美感呈现给你。
RDD 将数据集合进行三层组织:Dataset(数据集)- Partition(分片)- Record(单条记录)。三是一个很合适的层数,每层都有其着力点,多了显冗余,少了力不够。
举个生活中例子,高中某个班级(Dataset),我们把他们按列分成四个小组(Partition),每个小组有大概十来个同学(Record)。任何一群人来了,我们都可以以这种形式将其进行组织。同样,任何一个数据集,我们也可以按类似的三个层级进行划分。
单机资源总是有限的,RDD 生来就是为多机而设计的。将数据集划分为多个分片(Partition),就是为了能让一个数据集分散到不同机器上,从而利用多个机器的存储和计算资源,对数据进行并行处理。此外,分片还可以隔离故障阈,当某个机器故障后,只需要恢复该机器上对应分片即可,其他机器的分片不受影响。
相比 HDFS 或 GFS 基于外存,RDD 以内存为第一介质,以此可以显著降低计算延迟。当然,如果数据过多,也提供退化策略 —— 外溢(Spill)到外存。尤其对于一些重要的中间计算结果,多选择持久化到外存,以避免宕机时重新计算。
数据集不能被原地( in-place) 的修改,即不能只修改集合中某个 Record。只能通过算子将一个数据集整体变换成另一个数据集。只要知道起始集,和一个确定的变换序列,就能得到一个唯一确定的结果集,因此常用此方法来进行容错(lineage)。如某些分区数据丢了,只需要重放其所经历的算子序列即可。
那么,不可变有什么好处呢?可以安全的并发。对于不可变数据,不用处理各种读写冲突,也不需要加锁。这是一种典型的 tradeoff,牺牲空间,换来更快的计算,更好的并发。
使用算子可以将一个 RDD 变换到另一个 RDD,也可以终结计算过程进行输出。通过合理组合这些算子,可以实现对数据集的复杂处理。
算子是一些基本运算过程的抽象,我们可以简单的理解为:
常见的算子包括:
各种常见算子
如上图,算子可以分为两种:
从整体上理解,基于 RDD 的整个处理流程可以拆解为三个步骤:
RDD 的整个处理流程我们称为任务(Job),每个变换称为子任务(Task)。如果将 RDD 理解为点,施加算子进行变换的关系理解为边,则整个任务的执行过程可以构成一个有向无环图(DAG)。
为了逐步执行这个有向无环图,我们可以一步步来考虑:
正如河流往往有汇聚点,即所谓瓶颈。在变换算子中,也有一些特殊算子,我们称之为 shuffle 算子(reduce、join、sort)。这种算子会将 RDD 的所有分区打散重排(所谓 shuffle),从而打断分区的流水化执行。于是 Spark 就以这种算子为界,将整个 Job 划分为多个 Stage,逐 Stage 进行调度。这样,在每个 Stage 内的子任务可以流水线的执行。通常,在 Stage 内子任务执行完后,我们会将其中间结果 Persist 到外存,以避免任何一台相关机器宕机,丢失某个分片,在 Stage 边界处造成所有分区全部重新执行。
Spark 划分执行过程
在 RDD 的实现系统 Spark 中,对数据集进行一致性的抽象正是计算流水线(pipeline)得以存在和优化的精髓所在。依托 RDD,Spark 整个系统的基本抽象极为简洁:数据集+算子。理解了这两个基本元素的内涵,利用计算机的惯常实践,就可以自行推演其之后的调度优化和衍生概念(如分区方式、宽窄依赖)。
总结一下,RDD 承自 MapReduce 而来,常驻内存以优化 IO 开销、利用流水线调度以降低批处理延迟,使得在多机上交互式的执行处理成为可能。
更细节的,可以参考我之前翻译的这篇文章: Spark 理论基石 —— RDD
题图故事
初夏时、黄昏刻,当代 MOMA 的空中连廊。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有