一、分区的概念

分区是RDD内部并行计算的一个计算单元,RDD的数据集在逻辑上被划分为多个分片,每一个分片称为分区,分区的格式决定了并行计算的粒度,而每个分区的数值计算都是在一个任务中进行的,因此任务的个数,也是由RDD(准确来说是作业最后一个RDD)的分区数决定。

二、为什么要进行分区

 数据分区,在分布式集群里,网络通信的代价很大,减少网络传输可以极大提升性能。mapreduce框架的性能开支主要在io和网络传输,io因为要大量读写文件,它是不可避免的,但是网络传输是可以避免的,把大文件压缩变小文件,   从而减少网络传输,但是增加了cpu的计算负载。

  Spark里面io也是不可避免的,但是网络传输spark里面进行了优化:

  Spark把rdd进行分区(分片),放在集群上并行计算。同一个rdd分片100个,10个节点,平均一个节点10个分区,当进行sum型的计算的时候,先进行每个分区的sum,然后把sum值shuffle传输到主程序进行全局sum,所以进行sum型计算对网络传输非常小。但对于进行join型的计算的时候,需要把数据本身进行shuffle,网络开销很大。

spark是如何优化这个问题的呢?

  Spark把key-value rdd通过key的hashcode进行分区,而且保证相同的key存储在同一个节点上,这样对改rdd进行key聚合时,就不需要shuffle过程,我们进行mapreduce计算的时候为什么要进行shuffle?,就是说mapreduce里面网络传输主要在shuffle阶段,shuffle的根本原因是相同的key存在不同的节点上,按key进行聚合的时候不得不进行shuffle。shuffle是非常影响网络的,它要把所有的数据混在一起走网络,然后它才能把相同的key走到一起。进行shuffle是存储决定的。

  Spark从这个教训中得到启发,spark会把key进行分区,也就是key的hashcode进行分区,相同的key,hashcode肯定是一样的,所以它进行分区的时候100t的数据分成10分,每部分10个t,它能确保相同的key肯定在一个分区里面,而且它能保证存储的时候相同的key能够存在同一个节点上。比如一个rdd分成了100份,集群有10个节点,所以每个节点存10份,每一分称为每个分区,spark能保证相同的key存在同一个节点上,实际上相同的key存在同一个分区。

  key的分布不均决定了有的分区大有的分区小。没法分区保证完全相等,但它会保证在一个接近的范围。所以mapreduce里面做的某些工作里边,spark就不需要shuffle了,spark解决网络传输这块的根本原理就是这个。

  进行join的时候是两个表,不可能把两个表都分区好,通常情况下是把用的频繁的大表事先进行分区,小表进行关联它的时候小表进行shuffle过程。

  大表不需要shuffle。
  

  需要在工作节点间进行数据混洗的转换极大地受益于分区。这样的转换是  cogroup,groupWith,join,leftOuterJoin,rightOuterJoin,groupByKey,reduceByKey,combineByKey 和lookup。

  分区是可配置的,只要RDD是基于键值对的即可

三、Spark分区原则及方法

RDD分区的一个分区原则:尽可能是得分区的个数等于集群核心数目

无论是本地模式、Standalone模式、YARN模式或Mesos模式,我们都可以通过spark.default.parallelism来配置其默认分区个数,若没有设置该值,则根据不同的集群环境确定该值

3.1 本地模式

(1)默认方式

以下这种默认方式就一个分区

结果

(2)手动设置

设置了几个分区就是几个分区

结果

(3)跟local[n] 有关

n等于几默认就是几个分区

如果n=* 那么分区个数就等于cpu core的个数

结果

本机电脑查看cpu core,我的电脑--》右键管理--》设备管理器--》处理器

(4)参数控制

结果

3.2 YARN模式

进入defaultParallelism方法

继续进入defaultParallelism方法

这个一个trait,其实现类是(Ctrl+h)

进入TaskSchedulerImpl类找到defaultParallelism方法

继续进入defaultParallelism方法,又是一个trait,看其实现类

Ctrl+h看SchedulerBackend类的实现类

进入CoarseGrainedSchedulerBackend找到defaultParallelism

totalCoreCount.get()是所有executor使用的core总数,和2比较去较大值

如果正常的情况下,那你设置了多少就是多少

四、分区器

(1)如果是从HDFS里面读取出来的数据,不需要分区器。因为HDFS本来就分好区了。

    分区数我们是可以控制的,但是没必要有分区器。

(2)非key-value RDD分区,没必要设置分区器

al testRDD = sc.textFile("C:\\Users\\Administrator\\IdeaProjects\\myspark\\src\\main\\hello.txt")
.flatMap(line => line.split(","))
.map(word => (word, 1)).partitionBy(new HashPartitioner(2))

  

  没必要设置,但是非要设置也行。

(3)Key-value形式的时候,我们就有必要了。

HashPartitioner

val resultRDD = testRDD.reduceByKey(new HashPartitioner(2),(x:Int,y:Int) => x+ y)
//如果不设置默认也是HashPartitoiner,分区数跟spark.default.parallelism一样
println(resultRDD.partitioner)
println("resultRDD"+resultRDD.getNumPartitions)

  RangePartitioner

val resultRDD = testRDD.reduceByKey((x:Int,y:Int) => x+ y)
val newresultRDD=resultRDD.partitionBy(new RangePartitioner[String,Int](3,resultRDD))
println(newresultRDD.partitioner)
println("newresultRDD"+newresultRDD.getNumPartitions)

  

注:按照范围进行分区的,如果是字符串,那么就按字典顺序的范围划分。如果是数字,就按数据自的范围划分

自定义分区

需要实现2个方法

class MyPartitoiner(val numParts:Int) extends  Partitioner{
override def numPartitions: Int = numParts
override def getPartition(key: Any): Int = {
val domain = new URL(key.toString).getHost
val code = (domain.hashCode % numParts)
if (code < 0) {
code + numParts
} else {
code
}
}
} object DomainNamePartitioner {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("word count").setMaster("local") val sc = new SparkContext(conf) val urlRDD = sc.makeRDD(Seq(("http://baidu.com/test", 2),
("http://baidu.com/index", 2), ("http://ali.com", 3), ("http://baidu.com/tmmmm", 4),
("http://baidu.com/test", 4)))
//Array[Array[(String, Int)]]
// = Array(Array(),
// Array((http://baidu.com/index,2), (http://baidu.com/tmmmm,4),
// (http://baidu.com/test,4), (http://baidu.com/test,2), (http://ali.com,3)))
val hashPartitionedRDD = urlRDD.partitionBy(new HashPartitioner(2))
hashPartitionedRDD.glom().collect() //使用spark-shell --jar的方式将这个partitioner所在的jar包引进去,然后测试下面的代码
// spark-shell --master spark://master:7077 --jars spark-rdd-1.0-SNAPSHOT.jar
val partitionedRDD = urlRDD.partitionBy(new MyPartitoiner(2))
val array = partitionedRDD.glom().collect() }
}

  

Spark API--Spark 分区的更多相关文章

  1. spark api之一:Spark官方文档 - 中文翻译

    转载请注明出处:http://www.cnblogs.com/BYRans/ 1 概述(Overview) 2 引入Spark(Linking with Spark) 3 初始化Spark(Initi ...

  2. Spark:将RDD[List[String,List[Person]]]中的List[Person]通过spark api保存为hdfs文件时一直出现not serializable task,没办法找到"spark自定义Kryo序列化输入输出API"

    声明:本文转自<在Spark中自定义Kryo序列化输入输出API>   在Spark中内置支持两种系列化格式:(1).Java serialization:(2).Kryo seriali ...

  3. [Spark RDD_add_2] Spark RDD 分区补充内容

    [Spark & Hadoop 的分区] Spark 的分区是切片的个数,每个 RDD 都有自己的分区数. Hadoop 的分区指的是 Reduce 的个数,是 Map 过程中对 Key 进行 ...

  4. [Dynamic Language] pyspark Python3.7环境设置 及py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe解决!

    pyspark Python3.7环境设置 及py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spa ...

  5. 03、IDEA下Spark API编程

    03.IDEA下Spark API编程 3.1 编程实现Word Count 3.1.1 创建Scala模块 3.1.2 添加maven支持,并引入spark依赖 <?xml version=& ...

  6. spark shuffle:分区原理及相关的疑问

    一.分区原理 1.为什么要分区?(这个借用别人的一段话来阐述.) 为了减少网络传输,需要增加cpu计算负载.数据分区,在分布式集群里,网络通信的代价很大,减少网络传输可以极大提升性能.mapreduc ...

  7. py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe. : java.lang.IllegalArgumentException: Unsupported class file major version 55

    今天小编用Python编写Spark程序报了如下异常: py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apach ...

  8. 【转】科普Spark,Spark是什么,如何使用Spark

    本博文是转自如下链接,为了方便自己查阅学习和他人交流.感谢原博主的提供! http://www.aboutyun.com/thread-6849-1-1.html http://www.aboutyu ...

  9. Spark记录-spark编程介绍

    Spark核心编程 Spark 核心是整个项目的基础.它提供了分布式任务调度,调度和基本的 I/O 功能.Spark 使用一种称为RDD(弹性分布式数据集)一个专门的基础数据结构,是整个机器分区数据的 ...

  10. Spark记录-spark介绍

    Apache Spark是一个集群计算设计的快速计算.它是建立在Hadoop MapReduce之上,它扩展了 MapReduce 模式,有效地使用更多类型的计算,其中包括交互式查询和流处理.这是一个 ...

随机推荐

  1. Git config文件

    查看该文件: git config --global --list Ref: https://blog.csdn.net/themagickeyjianan/article/details/79683 ...

  2. 【洛谷4482】Border的四种求法(后缀自动机_线段树合并_链分治)

    这题我写了一天后交了一发就过了我好兴奋啊啊啊啊啊啊 题目 洛谷 4482 分析 这题明明可以在线做的,为什么我见到的所有题解都是离线啊 -- 什么时候有机会出一个在线版本坑人. 题目的要求可以转化为求 ...

  3. 【剑指offer】平衡二叉树

    题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 分析:采用后序遍历的方式判断左右子树的高度差是否大于1 class Solution { public: bool flag; int f(T ...

  4. [转帖]POW , POS 与 DPOS 一切都为了共识

    POW , POS 与 DPOS 一切都为了共识 https://www.jianshu.com/p/f99e8fe57c9a   共识机制的背景 加密货币都是去中心化的,去中心化的基础就是P2P节点 ...

  5. Django-12-auth认证组件

    1. 介绍 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能. Django作为一个完美主义者的终极框架,当然也会 ...

  6. 在Go中简单实现HTTP服务中间件

    通常一个简单http服务框架,就是注册一堆路由,然后根据路由调用不同的逻辑去处理. 但实际上可能有一些统一的处理对几乎所有的路由都涉及到,比如日志,比如权限等等. 那么这个时候搞一个中间做预处理,是一 ...

  7. mysql 8.0.17 安装与使用

    目录 写在前面 MySQL 安装 重置密码 使用图形界面软件 Navicat for SQL 写在前面 以前包括现在接到的项目,用的最多的关系型数据库就是SqlServer或者Oracle.后来因为接 ...

  8. command injection命令注入

    命令注入 是指程序中有调用系统命令的部分,例如输入ip,程序调用系统命令ping这个ip.如果在ip后面加一个&&.&.|.||命令拼接符号再跟上自己需要执行的系统命令 在pi ...

  9. Redis基础用法

    Redis-避免缓存穿透的利器之BloomFilter Redis相关的问题的时候,经常提到BloomFilter(布隆过滤器)这玩意的使用场景是真的多,而且用起来是真的香,原理也好理解,看一下文章就 ...

  10. MySQL数据库基本规范整理

    此篇文章是学习MySQL技术整理的,不足之处还望指教,不胜感激. 数据库基本规范涉及数据库命名规范.数据库索引设计规范.数据库基本设计规范.数据库字段设计规范.数据库SQL开发规范.数据库操作行为规范 ...