2.4 RDD 分区数目
在讲解 RDD 属性时,多次提到了分区(partition)的概念。分区是一个偏物理层的概念,也是 RDD 并行计算的核心。数据在 RDD 内部被切分为多个子集合,每个子集合可以被认为是一个分区,运算逻辑最小会被应用在每一个分区上,每个分区是由一个单独的任务(task)来运行的,所以分区数越多,整个应用的并行度也会越高。
获取RDD分区数目两种方式
RDD分区的数据取决于哪些因素?
第一点:RDD分区的原则是使得分区的个数尽量等于集群中的CPU核心(core)数目,这样可以充分利用CPU的计算资源;
第二点:在实际中为了更加充分的压榨CPU的计算资源,会把并行度设置为cpu核数的2~3倍;
第三点:RDD分区数和启动时指定的核数、调用方法时指定的分区数、如文件本身分区数有关系,具体如下说明:
- 1)、启动的时候指定的CPU核数确定了一个参数值:
- spark.default.parallelism=指定的CPU核数(集群模式最小2)
- 2)、对于Scala集合调用parallelize(集合,分区数)方法
- 如果没有指定分区数,就使用spark.default.parallelism
- 如果指定了就使用指定的分区数(不要指定大于spark.default.parallelism)
- 3)、对于textFile(文件, 分区数)
- defaultMinPartitions
- 如果没有指定分区数sc.defaultMinPartitions=min(defaultParallelism,2)
- 如果指定了就使用指定的分区数sc.defaultMinPartitions=指定的分区数rdd的分区数
- rdd的分区数
- 对于本地文件
- rdd的分区数 = max(本地file的分片数, sc.defaultMinPartitions)
- 对于HDFS文件
- rdd的分区数 = max(hdfs文件的block数目, sc.defaultMinPartitions)
- 所以如果分配的核数为多个,且从文件中读取数据创建RDD,即使hdfs文件只有1个切片,最后的Spark的RDD的partition数也有可能是2
- 对于本地文件
- defaultMinPartitions
第三章 RDD 函数
有一定开发经验的读者应该都使用过多线程,利用多核 CPU 的并行能力来加快运算速率。在开发并行程序时,可以利用类似 Fork/Join 的框架将一个大的任务切分成细小的任务,每个小任务模块之间是相互独立的,可以并行执行,然后将所有小任务的结果汇总起来,得到最终的结果。
一个非常好的例子便是归并排序。对整个序列进行排序时,可以将序列切分成多个子序列进行排序,然后将排好序的子序列归并起来得到最终的结果。
对 Hadoop 有所了解的读者都知道 map、reduce 操作。对于大量的数据,我们可以通过map 操作让不同的集群节点并行计算,之后通过 reduce 操作将结果整合起来得到最终输出。
3.1 函数分类
对于 Spark 处理的大量数据而言,会将数据切分后放入RDD作为Spark 的基本数据结构,开发者可以在 RDD 上进行丰富的操作,之后 Spark 会根据操作调度集群资源进行计算。总结起来,RDD 的操作主要可以分为 Transformation 和 Action 两种。
官方文档:http://spark.apache.org/docs/latest/rdd-programming-guide.html#rdd-operations
RDD中操作(函数、算子)分为两类:
- 1)、Transformation转换操作:返回一个新的RDD
- which create a new dataset from an existing one
- 所有Transformation函数都是Lazy,不会立即执行,需要Action函数触发
- 2)、Action动作操作:返回值不是RDD(无返回值或返回其他的)
- which return a value to the driver program after running a computation on the datase
- 所有Action函数立即执行(Eager),比如count、first、collect、take等
此外注意RDD中函数细节:
第一点:RDD不实际存储真正要计算的数据,而是记录了数据的位置在哪里,数据的转换关系(调用了什么方法,传入什么函数);
第二点:RDD中的所有转换都是惰性求值/延迟执行的,也就是说并不会直接计算。只有当发生一个要求返回结果给Driver的Action动作时,这些转换才会真正运行。之所以使用惰性求值/延迟执行,是因为这样可以在Action时对RDD操作形成DAG有向无环图进行Stage的划分和并行优化,这种设计让Spark更加有效率地运行。