spark常见面试题

本文深入探讨了Spark的核心概念,包括RDD、常用算子的区别、宽窄依赖、Stage划分策略以及如何防止内存溢出。此外,还讨论了Spark中cache和persist的差异、数据倾斜现象及其解决方案,以及如何在Spark-submit时引入外部jar包。内容涵盖了面试中常见的Spark问题,如Flume和Kafka与SparkStreaming的整合,以及Spark在YARN上的部署模式和任务调度机制。最后,文章提到了RDD的容错机制checkpoint的重要性和使用场景。

1、spark中的RDD是什么,有哪些特性

RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。

Dataset:就是一个集合,用于存放数据的

Distributed:分布式,可以并行在集群计算

Resilient:表示弹性的

弹性表示

1、RDD中的数据可以存储在内存或者是磁盘

2、RDD中的分区是可以改变的

五大特性:

A list of partitions

一个分区列表,RDD中的数据都存在一个分区列表里面

A function for computing each split

作用在每一个分区中的函数

A list of dependencies on other RDDs

一个RDD依赖于其他多个RDD,这个点很重要,RDD的容错机制就是依据这个特性而来的

Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)

可选的,针对于kv类型的RDD才具有这个特性,作用是决定了数据的来源以及数据处理后的去向

Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)

可选项,数据本地性,数据位置最优

2、概述一下spark中的常用算子区别(map、mapPartitions、foreach、foreachPartition) map:用于遍历RDD,将函数f应用于每一个元素,返回新的RDD(transformation算子)。

foreach:用于遍历RDD,将函数f应用于每一个元素,无返回值(action算子)。

mapPartitions:用于遍历操作RDD中的每一个分区,返回生成一个新的RDD(transformation算子)。

foreachPartition: 用于遍历操作RDD中的每一个分区。无返回值(action算子)。

总结:一般使用mapPartitions或者foreachPartition算子比map和foreach更加高效,推荐使用。

3、谈谈spark中的宽窄依赖

RDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)。

宽依赖:指的是多个子RDD的Partition会依赖同一个父RDD的Partition

指子RDD的分区依赖于父RDD的所有分区,这是因为shuffle类操作,如图中的groupByKey和未经协同划分的join。

窄依赖:指的是每一个父RDD的Partition最多被子RDD的一个Partition使用。

指父RDD的每一个分区最多被一个子RDD的分区所用,表现为一个父RDD的分区对应于一个子RDD的分区,和两个父RDD的分区对应于一个子RDD 的分区。图中,map/filter和union属于第一类,对输入进行协同划分(co-partitioned)的join属于第二类。

4、spark中如何划分stage

rdd当中dag的划分

dag叫做有向无环图,rdd之间一系列的转换,就形成了DAG,dag的主要作用,就是用来划分stage的,

stage叫做一个个的阶段,通过划分stage可以得到taskSet

stage的划分:从最后一个rdd,往前划,遇到窄依赖,加入当前stage,遇到宽依赖,划开一个stage

Stage划分思路

因此spark划分stage的整体思路是:从后往前推,遇到宽依赖就断开,划分为一个stage;遇到窄依赖就将这个RDD加入该stage中。因此在图2中RDD C,RDD D,RDD E,RDDF被构建在一个stage中,RDD A被构建在一个单独的Stage中,而RDD B和RDD G又被构建在同一个stage中。
  在spark中,Task的类型分为2种:ShuffleMapTask和ResultTask;简单来说,DAG的最后一个阶段会为每个结果的partition生成一个ResultTask,即每个Stage里面的Task的数量是由该Stage中最后一个RDD的Partition的数量所决定的!而其余所有阶段都会生成ShuffleMapTask;之所以称之为ShuffleMapTask是因为它需要将自己的计算结果通过shuffle到下一个stage中;也就是说图2中的stage1和stage2相当于mapreduce中的Mapper,而ResultTask所代表的stage3就相当于mapreduce中的reducer。

总结:map,filtre为窄依赖, groupbykey为宽依赖 ,遇到一个宽依赖就分一个stage

5、spark-submit的时候如何引入外部jar包

在通过spark-submit提交任务时,可以通过添加配置参数来指定

–driver-class-path 外部jar包

–jars 外部jar包

6、spark 如何防止内存溢出

driver端的内存溢出

可以增大driver的内存参数:spark.driver.memory (default 1g)

这个参数用来设置Driver的内存。在Spark程序中,SparkContext,DAGScheduler都是运行在Driver端的。对应rdd的Stage切分也是在Driver端运行,如果用户自己写的程序有过多的步骤,切分出过多的Stage,这部分信息消耗的是Driver的内存,这个时候就需要调大Driver的内存。

map过程产生大量对象导致内存溢出

这种溢出的原因是在单个map中产生了大量的对象导致的,例如:rdd.map(x=>for(i <- 1 to 10000) yield i.toString),这个操作在rdd中,每个对象都产生了10000个对象,这肯定很容易产生内存溢出的问题。针对这种问题,在不增加内存的情况下,可以通过减少每个Task的大小,以便达到每个Task即使产生大量的对象Executor的内存也能够装得下。具体做法可以在会产生大量对象的map操作之前调用repartition方法,分区成更小的块传入map。例如:rdd.repartition(10000).map(x=>for(i <- 1 to 10000) yield i.toString)。

面对这种问题注意,不能使用rdd.coalesce方法,这个方法只能减少分区,不能增加分区,不会有shuffle的过程。

数据不平衡导致内存溢出

数据不平衡除了有可能导致内存溢出外,也有可能导致性能的问题,解决方法和上面说的类似,就是调用repartition重新分区。这里就不再累赘了。

shuffle后内存溢出

shuffle内存溢出的情况可以说都是shuffle后,单个文件过大导致的。在Spark中,join,reduceByKey这一类型的过程,都会有shuffle的过程,在shuffle的使用,需要传入一个partitioner,大部分Spark中的shuffle操作,默认的partitioner都是HashPatitioner,默认值是父RDD中最大的分区数,这个参数通过spark.default.parallelism控制(在spark-sql中用spark.sql.shuffle.partitions) , spark.default.parallelism参数只对HashPartitioner有效,所以如果是别的Partitioner或者自己实现的Partitioner就不能使用spark.default.parallelism这个参数来控制shuffle的并发量了。如果是别的partitioner导致的shuffle内存溢出,就需要从partitioner的代码增加partitions的数量。

standalone模式下资源分配不均匀导致内存溢出

在standalone的模式下如果配置了–total-executor-cores 和 –executor-memory 这两个参数,但是没有配置–executor-cores这个参数的话,就有可能导致,每个Executor的memory是一样的,但是cores的数量不同,那么在cores数量多的Executor中,由于能够同时执行多个Task,就容易导致内存溢出的情况。这种情况的解决方法就是同时配置–executor-cores或者spark.executor.cores参数,确保Executor资源分配均匀。使用rdd.persist(StorageLevel.MEMORY_AND_DISK_SER)代替rdd.cache()。rdd.cache()和rdd.persist(Storage.MEMORY_ONLY)是等价的,在内存不足的时候rdd.cache()的数据会丢失,再次使用的时候会重算,而rdd.persist(StorageLevel.MEMORY_AND_DISK_SER)在内存不足的时候会存储在磁盘,避免重算,只是消耗点IO时间。

7、spark中cache和persist的区别

cache:缓存数据,默认是缓存在内存中,其本质还是调用persist

persist:缓存数据,有丰富的数据缓存策略。数据可以保存在内存也可以保存在磁盘中,使用的时候指定对应的缓存级别就可以了。

8、spark中的数据倾斜的现象、原因、后果

大量相同的key的数据都跑到同一个分区里面去了,如何解决数据倾斜的问题:将数据的key尽量的打散,甚至还可以做重新分区 partitionby(HashPartitioner,3)

(1)、数据倾斜的现象

多数task执行速度较快,少数task执行时间非常长,或者等待很长时间后提示你内存不足,执行失败。

(2)、数据倾斜的原因

数据问题

1、key本身分布不均衡(包括大量的key为空)

2、key的设置不合理

spark使用问题

1、shuffle时的并发度不够

2、计算方式有误

(3)、数据倾斜的后果

1、spark中的stage的执行时间受限于最后那个执行完成的task,因此运行缓慢的任务会拖垮整个程序的运行速度(分布式程序运行的速度是由最慢的那个task决定的)。

2、过多的数据在同一个task中运行,将会把executor撑爆。

9、如何解决spark中的数据倾斜问题

发现数据倾斜的时候,不要急于提高executor的资源,修改参数或是修改程序,首先要检查数据本身,是否存在异常数据。

1、数据问题造成的数据倾斜

找出异常的key

如果任务长时间卡在最后最后1个(几个)任务,首先要对key进行抽样分析,判断是哪些key造成的。

选取key,对数据进行抽样,统计出现的次数,根据出现次数大小排序取出前几个。

比如: df.select(“key”).sample(false,0.1).(k=>(k,1)).reduceBykey(+).map(k=>(k._2,k._1)).sortByKey(false).take(10)

如果发现多数数据分布都较为平均,而个别数据比其他数据大上若干个数量级,则说明发生了数据倾斜。

经过分析,倾斜的数据主要有以下三种情况:

1、null(空值)或是一些无意义的信息()之类的,大多是这个原因引起。
2、无效数据,大量重复的测试数据或是对结果影响不大的有效数据。
3、有效数据,业务导致的正常数据分布。
解决办法

第1,2种情况,直接对数据进行过滤即可(因为该数据对当前业务不会产生影响)。

第3种情况则需要进行一些特殊操作,常见的有以下几种做法

(1) 隔离执行,将异常的key过滤出来单独处理,最后与正常数据的处理结果进行union操作。

(2) 对key先添加随机值,进行操作后,去掉随机值,再进行一次操作。

(3) 使用reduceByKey 代替 groupByKey(reduceByKey用于对每个key对应的多个value进行merge操作,最重要的是它能够在本地先进行merge操作,并且merge操作可以通过函数自定义.)

(4) 使用map join。

案例

如果使用reduceByKey因为数据倾斜造成运行失败的问题。具体操作流程如下:

(1) 将原始的 key 转化为 key + 随机值(例如Random.nextInt)

(2) 对数据进行 reduceByKey(func)

(3) 将 key + 随机值 转成 key

(4) 再对数据进行 reduceByKey(func)

案例操作流程分析:

假设说有倾斜的Key,我们给所有的Key加上一个随机数,然后进行reduceByKey操作;此时同一个Key会有不同的随机数前缀,在进行reduceByKey操作的时候原来的一个非常大的倾斜的Key就分而治之变成若干个更小的Key,不过此时结果和原来不一样,怎么破?进行map操作,目的是把随机数前缀去掉,然后再次进行reduceByKey操作。(当然,如果你很无聊,可以再次做随机数前缀),这样我们就可以把原本倾斜的Key通过分而治之方案分散开来,最后又进行了全局聚合

注意1: 如果此时依旧存在问题,建议筛选出倾斜的数据单独处理。最后将这份数据与正常的数据进行union即可。

注意2: 单独处理异常数据时,可以配合使用Map Join解决。

2、spark使用不当造成的数据倾斜

提高shuffle并行度

dataFrame和sparkSql可以设置spark.sql.shuffle.partitions参数控制shuffle的并发度,默认为200。

rdd操作可以设置spark.default.parallelism控制并发度,默认参数由不同的Cluster Manager控制。

局限性: 只是让每个task执行更少的不同的key。无法解决个别key特别大的情况造成的倾斜,如果某些key的大小非常大,即使一个task单独执行它,也会受到数据倾斜的困扰。

使用map join 代替reduce join

在小表不是特别大(取决于你的executor大小)的情况下使用,可以使程序避免shuffle的过程,自然也就没有数据倾斜的困扰了.(详细见http://blog.csdn.net/lsshlsw/article/details/50834858、http://blog.csdn.net/lsshlsw/article/details/48694893)

局限性: 因为是先将小数据发送到每个executor上,所以数据量不能太大。

10、flume整合sparkStreaming问题

(1)、如何实现sparkStreaming读取flume中的数据

可以这样说:

前期经过技术调研,查看官网相关资料,发现sparkStreaming整合flume有2种模式,一种是拉模式,一种是推模式,然后在简单的聊聊这2种模式的特点,以及如何部署实现,需要做哪些事情,最后对比两种模式的特点,选择那种模式更好。

推模式:Flume将数据Push推给Spark Streaming

拉模式:Spark Streaming从flume 中Poll拉取数据

(2)、在实际开发的时候是如何保证数据不丢失的

可以这样说:

flume那边采用的channel是将数据落地到磁盘中,保证数据源端安全性(可以在补充一下,flume在这里的channel可以设置为memory内存中,提高数据接收处理的效率,但是由于数据在内存中,安全机制保证不了,故选择channel为磁盘存储。整个流程运行有一点的延迟性)

sparkStreaming通过拉模式整合的时候,使用了FlumeUtils这样一个类,该类是需要依赖一个额外的jar包(spark-streaming-flume_2.10)

要想保证数据不丢失,数据的准确性,可以在构建StreamingConext的时候,利用StreamingContext.getOrCreate(checkpoint, creatingFunc: () => StreamingContext)来创建一个StreamingContext,使用StreamingContext.getOrCreate来创建StreamingContext对象,传入的第一个参数是checkpoint的存放目录,第二参数是生成StreamingContext对象的用户自定义函数。如果checkpoint的存放目录存在,则从这个目录中生成StreamingContext对象;如果不存在,才会调用第二个函数来生成新的StreamingContext对象。在creatingFunc函数中,除了生成一个新的StreamingContext操作,还需要完成各种操作,然后调用ssc.checkpoint(checkpointDirectory)来初始化checkpoint功能,最后再返回StreamingContext对象。

这样,在StreamingContext.getOrCreate之后,就可以直接调用start()函数来启动(或者是从中断点继续运行)流式应用了。如果有其他在启动或继续运行都要做的工作,可以在start()调用前执行。

流失计算中使用checkpoint的作用:

保存元数据,包括流式应用的配置、流式没崩溃之前定义的各种操作、未完成所有操作的batch。元数据被存储到容忍失败的存储系统上,如HDFS。这种ckeckpoint主要针对driver失败后的修复。

保存流式数据,也是存储到容忍失败的存储系统上,如HDFS。这种ckeckpoint主要针对window operation、有状态的操作。无论是driver失败了,还是worker失败了,这种checkpoint都够快速恢复,而不需要将很长的历史数据都重新计算一遍(以便得到当前的状态)。

设置流式数据checkpoint的周期

对于一个需要做checkpoint的DStream结构,可以通过调用DStream.checkpoint(checkpointInterval)来设置ckeckpoint的周期,经验上一般将这个checkpoint周期设置成batch周期的5至10倍。

使用write ahead logs功能

这是一个可选功能,建议加上。这个功能将使得输入数据写入之前配置的checkpoint目录。这样有状态的数据可以从上一个checkpoint开始计算。开启的方法是把spark.streaming.receiver.writeAheadLogs.enable这个property设置为true。另外,由于输入RDD的默认StorageLevel是MEMORY_AND_DISK_2,即数据会在两台worker上做replication。实际上,Spark Streaming模式下,任何从网络输入数据的Receiver(如kafka、flume、socket)都会在两台机器上做数据备份。如果开启了write ahead logs的功能,建议把StorageLevel改成MEMORY_AND_DISK_SER。修改的方法是,在创建RDD时由参数传入。

使用以上的checkpoint机制,确实可以保证数据0丢失。但是一个前提条件是,数据发送端必须要有缓存功能,这样才能保证在spark应用重启期间,数据发送端不会因为spark streaming服务不可用而把数据丢弃。而flume具备这种特性,同样kafka也具备。

(3)Spark Streaming的数据可靠性

有了checkpoint机制、write ahead log机制、Receiver缓存机器、可靠的Receiver(即数据接收并备份成功后会发送ack),可以保证无论是worker失效还是driver失效,都是数据0丢失。原因是:如果没有Receiver服务的worker失效了,RDD数据可以依赖血统来重新计算;如果Receiver所在worker失败了,由于Reciever是可靠的,并有write ahead log机制,则收到的数据可以保证不丢;如果driver失败了,可以从checkpoint中恢复数据重新构建。

11、kafka整合sparkStreaming问题

kafka消费模型:
at least once :至少消费一次,重复消费
at most once : 至多消费一次 丢失数据
exactly once :消费且仅消费一次 保证每一条数据都会被消费,既不会数据丢失,也不会 数据重复消费

两个大的版本

0.8版本:
Receiver DStream :使用zk的high level API进行消费,所有消费的数据的offset全部都是维护在zk当中,有可能会造成数据的重复消费。,每隔一段时间提交一次offset,一旦中间出现中断,offset没有来得及提交,就会造成重复消费的问题 at least once 会造成重复消费
Direct DStream :使用zk的low level api进行消费,所有消费的offset全部都是维护在kafka当中的自带的一个topic里面,会造成数据的丢失 at most once 会造成数据丢失

0.10版本:
通过手动的提交offset消费完成的数据马上提交offset,保证所有的数据消费且仅消费一次
Direct DStream 通过手动提交每一个rdd当中的offset,实现数据消费一次,所有的offset全部都是保存到了kafka当中内置的一个topic里面去了

13、driver的功能是什么?

1)一个Spark作业运行时包括一个Driver进程,也是作业的主进程,具有main函数,并且有SparkContext的实例,是程序的人口点;

2)功能:负责向集群申请资源,向master注册信息,负责了作业的调度,,负责作业的解析、生成Stage并调度Task到Executor上。包括DAGScheduler,TaskScheduler。

14、Spark为什么比mapreduce快?

1)基于内存计算,减少低效的磁盘交互;

2)高效的调度算法,基于DAG;

3)容错机制Linage,精华部分就是DAG和Lingae

15、hadoop和spark的shuffle相同和差异?

1)从 high-level 的角度来看,两者并没有大的差别。 都是将 mapper(Spark 里是 ShuffleMapTask)的输出进行 partition,不同的 partition 送到不同的 reducer(Spark 里 reducer 可能是下一个 stage 里的 ShuffleMapTask,也可能是 ResultTask)。Reducer 以内存作缓冲区,边 shuffle 边 aggregate 数据,等到数据 aggregate 好以后进行 reduce() (Spark 里可能是后续的一系列操作)。

2)从 low-level 的角度来看,两者差别不小。 Hadoop MapReduce 是 sort-based,进入 combine() 和 reduce() 的 records 必须先 sort。这样的好处在于 combine/reduce() 可以处理大规模的数据,因为其输入数据可以通过外排得到(mapper 对每段数据先做排序,reducer 的 shuffle 对排好序的每段数据做归并)。目前的 Spark 默认选择的是 hash-based,通常使用 HashMap 来对 shuffle 来的数据进行 aggregate,不会对数据进行提前排序。如果用户需要经过排序的数据,那么需要自己调用类似 sortByKey() 的操作;如果你是Spark 1.1的用户,可以将spark.shuffle.manager设置为sort,则会对数据进行排序。在Spark 1.2中,sort将作为默认的Shuffle实现。

3)从实现角度来看,两者也有不少差别。 Hadoop MapReduce 将处理流程划分出明显的几个阶段:map(), spill, merge, shuffle, sort, reduce() 等。每个阶段各司其职,可以按照过程式的编程思想来逐一实现每个阶段的功能。在 Spark 中,没有这样功能明确的阶段,只有不同的 stage 和一系列的 transformation(),所以 spill, merge, aggregate 等操作需要蕴含在 transformation() 中。如果我们将 map 端划分数据、持久化数据的过程称为 shuffle write,而将 reducer 读入数据、aggregate 数据的过程称为 shuffle read。那么在 Spark 中,问题就变为怎么在 job 的逻辑或者物理执行图中加入 shuffle write 和 shuffle read 的处理逻辑?以及两个处理逻辑应该怎么高效实现? Shuffle write由于不要求数据有序,shuffle write 的任务很简单:将数据 partition 好,并持久化。之所以要持久化,一方面是要减少内存存储空间压力,另一方面也是为了 fault-tolerance。

16、常规的容错方式有哪几种类型?RDD通过Linage(记录数据更新)的方式为何很高效?

1).数据检查点,会发生拷贝,浪费资源

2).记录数据的更新,每次更新都会记录下来,比较复杂且比较消耗性能

——————

1) ​lazy记录了数据的来源,RDD是不可变的,且是lazy级别的,且rDD之间构成了链条,lazy是弹性的基石。由于RDD不可变,所以每次操作就产生新的rdd,不存在全局修改的问题,控制难度下降,所有有计算链条将复杂计算链条存储下来,计算的时候从后往前回溯900步是上一个stage的结束,要么就checkpoint

2) ​记录原数据,是每次修改都记录,代价很大如果修改一个集合,代价就很小,官方说rdd是粗粒度的操作,是为了效率,为了简化,每次都是操作数据集合,写或者修改操作,都是基于集合的rdd的写操作是粗粒度的,rdd的读操作既可以是粗粒度的也可以是细粒度,读可以读其中的一条条的记录。

3) ​简化复杂度,是高效率的一方面,写的粗粒度限制了使用场景如网络爬虫,现实世界中,大多数写是粗粒度的场景

17、RDD有哪些缺陷?

1)不支持细粒度的写和更新操作(如网络爬虫),spark写数据是粗粒度的所谓粗粒度,就是批量写入数据,为了提高效率。但是读数据是细粒度的也就是说可以一条条的读

2)不支持增量迭代计算,Flink支持

18、Spark中数据的位置是被谁管理的?

每个数据分片都对应具体物理位置,数据的位置是被blockManager,无论数据是在磁盘,内存还是tacyan,都是由blockManager管理

19、Spark的数据本地性有哪几种?

答:Spark中的数据本地性有三种:a.PROCESS_LOCAL是指读取缓存在本地节点的数据b.NODE_LOCAL是指读取本地节点硬盘数据c.ANY是指读取非本地节点数据通常读取数据PROCESS_LOCAL>NODE_LOCAL>ANY,尽量使数据以PROCESS_LOCAL或NODE_LOCAL方式读取。其中PROCESS_LOCAL还和cache有关,如果RDD经常用的话将该RDD cache到内存中,注意,由于cache是lazy的,所以必须通过一个action的触发,才能真正的将该RDD cache到内存中

20、rdd有几种操作类型?

1)transformation,rdd由一种转为另一种rdd
2)action,
3)cronroller,crontroller是控制算子,cache,persist,对性能和效率的有很好的支持三种类型,不要回答只有2中操作

21、Spark程序执行,有时候默认为什么会产生很多task,怎么修改默认task执行个数?

1)因为输入数据有很多task,尤其是有很多小文件的时候,有多少个输入block就会有多少个task启动;

2)spark中有partition的概念,每个partition都会对应一个task,task越多,在处理大规模数据的时候,就会越有效率。不过task并不是越多越好,如果平时测试,或者数据量没有那么大,则没有必要task数量太多。

3)参数可以通过spark_home/conf/spark-default.conf配置文件设置:spark.sql.shuffle.partitions 50 spark.default.parallelism 10第一个是针对spark sql的task数量第二个是非spark sql程序设置生效

13、为什么Spark Application在没有获得足够的资源,job就开始执行了,可能会导致什么什么问题发生?
答:会导致执行该job时候集群资源不足,导致执行job结束也没有分配足够的资源,分配了部分Executor,该job就开始执行task,应该是task的调度线程和Executor资源申请是异步的;如果想等待申请完所有的资源再执行job的:需要将spark.scheduler.maxRegisteredResourcesWaitingTime设置的很大;spark.scheduler.minRegisteredResourcesRatio 设置为1,但是应该结合实际考虑否则很容易出现长时间分配不到资源,job一直不能运行的情况。

21、join操作优化经验?

join其实常见的就分为两类: map-side join 和 reduce-side join。当大表和小表join时,用map-side join能显著提高效率。将多份数据进行关联是数据处理过程中非常普遍的用法,不过在分布式计算系统中,这个问题往往会变的非常麻烦,因为框架提供的 join 操作一般会将所有数据根据 key 发送到所有的 reduce 分区中去,也就是 shuffle 的过程。造成大量的网络以及磁盘IO消耗,运行效率极其低下,这个过程一般被称为 reduce-side-join。如果其中有张表较小的话,我们则可以自己实现在 map 端实现数据关联,跳过大量数据进行 shuffle 的过程,运行时间得到大量缩短,根据不同数据可能会有几倍到数十倍的性能提升。

22、介绍一下cogroup rdd实现原理,你在什么场景下用过这个rdd?

答:cogroup的函数实现:这个实现根据两个要进行合并的两个RDD操作,生成一个CoGroupedRDD的实例,这个RDD的返回结果是把相同的key中两个RDD分别进行合并操作,最后返回的RDD的value是一个Pair的实例,这个实例包含两个Iterable的值,第一个值表示的是RDD1中相同KEY的值,第二个值表示的是RDD2中相同key的值.由于做cogroup的操作,需要通过partitioner进行重新分区的操作,因此,执行这个流程时,需要执行一次shuffle的操作(如果要进行合并的两个RDD的都已经是shuffle后的rdd,同时他们对应的partitioner相同时,就不需要执行shuffle

23、DStream的转换

有状态无状态转换

有状态转换 updateStateBykey 会将历史的数据保存起来

无状态装换:仅仅处理当前批次的DStream的数据,历史的数据不管 map flatMap reduceByKey filter

24、DStream的容错

所有的实时处理的框架,基本上都会遇到数据的容错的问题

1、检查点容错,我们可以在创建stremaingContext的时候设置checkpoint路径

2、驱动器容错:StreamingContext.getOrCreate(checkDir , createFunc) 可以定义某个checkpoint的路径进行创建streamingcontext,一旦启动streamingcontext,会优先读取到历史的数据

3、工作节点的容错 DStream最后转化成为一个RDD,通过RDD的血统关系,可以实现数据的容错,定义数据的存储级别,实现数据的容错

4、接收器的容错,尽量选择一些比较可靠的数据源,实现接收器的容错 例如 kafka

5、处理保证 保证所有的rdd都会被处理掉

25.spark的on yarn模式

spark onyarn有两种部署模式

一种是client模式,一种是cluster模式
client:将我们的任务提交到yarn集群上面去运行,分配多少资源,yarn说了算,避免了我们手动的资源的分配
cluster:将我们的任务提交到yarn集群上面去运行,分配多少资源我们自己手动指定 ,指定完成之后,yarn就会给我们这些资源

26.spark的任务调度

第一步:根据客户端提交的jar包,生成DAG,根据rdd之间的依赖关系生成的DAG
第二步:根据DAG,划分stage
第三步:根据划分好的stage,形成taskSet,每一个taskset里面的task都是可以并行运行的
第四步:将划分好的taskSet送给taskScheduler,taskScheduler根据划分好的taskSet,启动对应的task,每一个taskset里面的task都是可以并行的进行计算的

第一步:客户端提交jar包
第二步:master接收jar包保存,启动driver驱动程序
第三步:driver通过客户端提交的jar包,将代码送给DAGScheduler
第四步:DAGScheduler 主要干了四件事,第一件:划分DAG,第二件事:划分stage 第三件事而:根据stage划分一个个的taskSet,每一个taskset里面包含了很多个task 第四件事:将taskset送给taskScheduler
第五步:taskScheduler 接收送过来的taskSet,分解成为一个个的task,运行在worker节点上,executor里面

27、rdd的容错机制 checkpoint

rdd为了防止数据的丢失,产生的一种数据持久化的机制,checkpoint,checkpoint可以手动的被触发,将rdd当中计算出来的数据,保存到本地磁盘或者hdfs上面去
persist 可以将数据保存到本地磁盘或者缓存里面去,缓存会失效,保存到本地磁盘存在误删的风险
为了解决数据误删除或者缓存失效的问题,spark引入checkpoint机制,checkpoint可以将rdd当中计算出来的数据放到hdfs上面去,常用于一些比较珍贵的rdd,特别是产生了shuffle的rdd,尽量做缓存或者持久化
分区的规则:如果文件小于128M,默认两个分区,如果大于128M,分区的个数等于block块的个数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值