什么是spark,是一个分布式计算平台,或者说是分布式计算引擎,他的职责就是将指定的数据读入到各个node的内存中,然后计算。所以spark是具有泛化性质的,只要数据源是可读入的,读到内存里面之后,处理就和数据源没有关系了,你是HBASE,kudu,还是parquet都无所谓了。
什么是RDD,弹性分布式数据集,其实RDD是一个抽象概念,因为RDD本身不包含数据,它只包含数据描述以及对于数据的算法,比如一个sparkSQL返回的RDD其实就是一个对数据的描述,告诉各个节点的executor要处理那些数据,那么map就是算法,map里面的函数体就是算法,所以map又叫做算子。
什么是spark分区,“需要把相同 key 的元素聚集到同一个 partition 下,所以造成了数据在内存中的重新分布,即 shuffle 操作”,简单讲就是设置数据分布,将相同key的数据分布到同一台机器;为什么要分区?首先明白分区的目的好处就是:
1)减少了网络开销;
2)提高并行计算度;
前者的实现是通过将join算子和hive参数放置到同一台机器,然后让发起join的表数据推送到spark的分区节点进行运算;至于后者,每个分区都有独立的线程(每个线程执行的逻辑称之为Task);可以保持彼此独立,并行进行计算,这个也是spark的机制所在。
但是spark的分区有俩个时间点,一个是创建的时候,通过partitionBy来指定,一个是repartition的时候;后者分区可能会引发shuffle;这提到了shuffle,什么是shuffle,就是跨节点传输;Shuffle发生有两个时间节点,一个是计算过程中,同key数据分布在不同的机器,需要进行数据传输,产生了shuffle,另外一个就是各个节点计算完毕后,向driver点汇聚,这个时候又会发生一次shuffle;后者的shuffle不可避免;前者的shuffle则是可以考虑进行优化;Mapreduce为什么会会发生shuffle,就是因为没有机制保证数据不在一台机器上面;
基于此,spark引入了分区机制。首先看一下没有分区的场景:如果不进行分区的话,就会造成join命令执行时一台机器,大表数据分散在各个节点要想join机器汇总,小表数据也要想join机器汇总。实现分区的本质好处就是把key值相同的数据放到一台机器上面;分区有两种机制,一种是Hash,一种是Range;对于大表join小表的场景下,shuffle被极大的减少,首先分区保证了(大表)相同的key是在一台机器上面,Spark将会分析,如果join的表有分区的话,将会在在大表的机器上面执行Join,这样只需要小表shuffle数据到大表(通过key做关联),这样网络开销减小了;
关于partition划分方式有两种:一个是有多到少,这个调用的coalesec()函数,注意设置shuffle=false,因为将单节点的多个分区合并为一个即可,不会引发shuffle;因为在代码实现上,可以看到返回的new CoalescedRDD(this, numPartitions, partitionCoalescer),第一个参数是shuffleRDD,还是历史的rdd;这种划分方式称之为窄依赖,窄,顾名思义,在自己的节点完成即可;
第二种由少到多,调用repartion函数;其实repartition的底层就是调用的coalesce()函数;只不过设定shuffle=true而已,这里shuffle是一定要设置为true,因为当分区数量增多之后,spark里面实现是数据分布就要发生变化,就需要对数据进行重排(默认是HashPartition);关于CoalescedRDD见下面的代码:
1 new CoalescedRDD( 2 new ShuffledRDD[Int, T, T](mapPartitionsWithIndex(distributePartition), 3 new HashPartitioner(numPartitions)), 4 numPartitions, 5 partitionCoalescer).values
第一个参数是shuffledRDD,看到已经是一个新的RDD,分区也是new了一个新的分区。这种划分方式又称之为宽依赖,就是分区需要多个节点协作完成;
窄依赖跟宽依赖的区别是是否发生 shuffle(洗牌) 操作.宽依赖会发生 shuffle 操作. 窄依赖是子 RDD的各个分片(partition)不依赖于其他分片,能够独立计算得到结果,宽依赖指子 RDD 的各个分片会依赖于父RDD 的多个分片,所以会造成父 RDD 的各个分片在集群中重新分片。
那么我们为什么要使用spark?spark使用的机制其实是和Map-Reduce是一样的。
1. spark的任务是fork出一个线程来执行,但是mr是一个进程;
2. mr则是每次运算之后都需要把数据写入到硬盘中;spark只是在shuffle的时候需要将数据写入到硬盘中,因为spark在Driver端生成了一个DAG,可以全局考虑数据处理(MR每个map都是独立的);
3. spark的cache做的比mr更好,因为spark在把RDD放入cache之后,将会对其进行“unroll”,将不连续的存储转化为连续存储。
注意,有一种观点描述spark是内存技术,这种说法是不正确的,因为spark其实是配置了内存上限,超过上限,将会基于LRU策略将内存数据进行处理(销毁,或者序列化到硬盘,基于缓存策略)。
参考
http://blog.csdn.net/databatman/article/details/53023818#4shuffle-%E5%92%8C-stage
https://www.cnblogs.com/licheng/p/6822376.html
https://0x0fff.com/spark-misconceptions/ 译文:https://www.cnblogs.com/intsmaze/p/7197420.html