RDD分区可以减少通信开销,极大地提升Spark程序的整体性能。
1.RDD分区的作用
(1)增加并行度
(2)减少通信开销
Spark中所有的RDD都可以进行分区,系统会根据一个针对键的函数对元素进行分区。虽然Spark不能控制每个键具体划分到哪个节点上,但是可以确保相同的键出现在同一个分区上。
2.RDD的分区原则
分区的个数尽量等于集群中的CPU核心数目。
3.各种模式下的默认分区数目如下
(1)Local模式:默认为本地机器的 CPU数目,若设置了 local[N], 则默认为N。
(2)Standalone 或者 Yarn模式:在“集群中所有 CPU核数总和”和“2”这两者中取较大值作为默认值。
(3)Mesos 模式:默认的分区数是8。
Spark 框架为 RDD提供了两种分区方式,分别是哈希分区(HashPartitioner)和范围分区(RangePartitioner)。其中,哈希分区是根据哈希值进行分区;范围分区是将一定范围的数据映射到一个分区中。这两种分区方式已经可以满足大多数应用场景的需求。与此同时,Spark也支持自定义分区方式,即通过一个自定义的 Partitioner对象来控制 RDD的分区,从而进一步减少通信开销。需要注意的是,RDD的分区函数是针对(Key, Value)类型的RDD, 分区函数根据 Key 对 RDD 元素进行分区。因此,当需要对一些非(Key, Value)类型的RDD进行自定义分区时,需要先把 RDD元素转换为(Key, Value)类型,再通过分区函数进行分区操作。
Rn名称 .partiteons.stze 显示分区教日.
4.如果想要实现自定义分区,就需要定义一个类,使得这个自定义的类继承org.apache.
spark.Partitioner类,并实现其中的3个方法,具体如下。
(1) def numPartitions:Int:用于返回创建的分区个数。
(2)def getPartition(Key:Any):用于对输人的Key 做处理,并返回该Key的分区ID,分区ID的范围是0~numPartitions-1。
(3) equals (other: Any):用于 Spark 判断自定义的Partitioner 对象和其他的Partitioner对象是否相同,从而判断两个 RDD的分区方式是否相同。
5.设置RDD分区的个数
(1) 创建RDD时手动指定分区个数
在调用textFile()和parallelize()方法时手动指定分区个数即可。
sc.textFile(path, partitionNum)
path参数指定要加载的文件的地址 ,partitionNum参数 用于指定分区个数 ,例子如下:
val array=Array(1,2,3,4,5)
val rdd = sc.parallelize(array,2) //设置两个分区
(2)使用reparititon方法重新设置分区个数
通过转换操作得到新RDD 时,直接调用repartition方法即可。例如:
val data = sc.textFile("file:///usr/local/spark/mycode/rdd/word.txt",2)
data.partitions.size //显示data这个RDD的分区数量
val rdd = data.repartition(1) //对data这个RDD进行重新分区
rdd.partitions.size
6.RDD分区与分块的区别
(1)划分方式不同
分块是按顺序划分(默认128MB),分区是按函数来划分(把键相同的元素放在同一个分区)。
(2)大小不同
块大小固定,分区大小随意。
(3)分区可以减少后续处理,分块后内容比较杂乱,还需要进一步处理。
(4)划分要求不同
分块无要求,分区要求对象是(Key-Value)键值对。
(5)作用不同
分块的作用是增加并行度,分区不仅增加并行度而且减少通信开销。
(6)存放位置不同
分块在硬盘,分区在内存。