文章目录
-
-
-
-
- [1.Spark 的运行流程?](#1.Spark 的运行流程?)
- [2.Spark 中的 RDD 机制理解吗?](#2.Spark 中的 RDD 机制理解吗?)
- [3.RDD 的宽窄依赖](#3.RDD 的宽窄依赖)
- [4.DAG 中为什么要划分 Stage?](#4.DAG 中为什么要划分 Stage?)
- [5.Spark 程序执行,有时候默认为什么会产生很多 task,怎么修改默认 task 执行个数?](#5.Spark 程序执行,有时候默认为什么会产生很多 task,怎么修改默认 task 执行个数?)
- [6.RDD 中 reduceBykey 与 groupByKey 哪个性能好,为什么?](#6.RDD 中 reduceBykey 与 groupByKey 哪个性能好,为什么?)
- [7.Spark Master HA 主从切换过程不会影响到集群已有作业的运行,为什么?](#7.Spark Master HA 主从切换过程不会影响到集群已有作业的运行,为什么?)
- [8.Spark Master 使用 Zookeeper 进行 HA,有哪些源数据保存到](#8.Spark Master 使用 Zookeeper 进行 HA,有哪些源数据保存到)
- [9.Spark 主备切换机制原理知道吗?](#9.Spark 主备切换机制原理知道吗?)
- [10.RDD 持久化原理?](#10.RDD 持久化原理?)
- [11.Checkpoint 和持久化机制的区别?](#11.Checkpoint 和持久化机制的区别?)
- [12.Spark Streaming 以及基本工作原理?](#12.Spark Streaming 以及基本工作原理?)
- [13.DStream 以及基本工作原理?](#13.DStream 以及基本工作原理?)
- [18.Spark 中的数据倾斜问题](#18.Spark 中的数据倾斜问题)
-
-
-
1.Spark 的运行流程?
Spark 运行流程 具体运行流程如下:
- SparkContext 向资源管理器注册并向资源管理器申请运行 Executor
- 资源管理器分配 Executor,然后资源管理器启动 Executor
- Executor 发送心跳至资源管理器
- SparkContext 构建 DAG 有向无环图
- 将 DAG 分解成 Stage(
TaskSet)
- 把 Stage 发送给 TaskScheduler
- Executor 向 SparkContext 申请 Task
- TaskScheduler 将 Task 发送给 Executor 运行
- 同时 SparkContext 将应用程序代码发放给 Executor
10.Task 在 Executor 上运行,运行完毕释放所有资源
2.Spark 中的 RDD 机制理解吗?
rdd 分布式弹性数据集,是spark一种数据结构,是 spark 框架上的通用货币。所有算子都是基于 rdd 来执行的,不同的场景会有不同的 rdd 实现类, RDD之间可以进行互相转换,从而rdd 执行过程中会形成 dag 图,然后形成 lineage 保证容错性等。从物理的角度来看 rdd 存储的是 block 和 node 之间的映射。 RDD 在逻辑上是一个 hdfs 文件,在抽象上是一种元素集合,包含了数据。它是被分区的,分为多个分区,每个分区分布在集群中的不同结点上,从而让 RDD 中 的数据可以被并行操作(分布式数据集)
java
比如有个 RDD 有 90W 数据,3 个 partition,则每个分区上有 30W 数据。RDD通常通过 Hadoop 上的文件,即 HDFS 或者 HIVE 表来创建,还可以通过应用程序中的集合来创建;
RDD 最重要的特性就是容错性,由DAG的血缘关系可以自动从节点失败中恢复过来。即如果某个结点上的 RDD partition 因为节点故障,导致数据丢失,那么 RDD 可以通过自己的数据来源重新计算该 partition。这一切对使用者都是透明的。
RDD 的数据默认存放在内存中,但是当内存资源不足时,spark 会自动将 RDD 数据写入磁盘。RDD 的弹性体现在于 RDD 上自动进行内存和磁盘之间权衡和切换的机制。
java
比如某结点内存只能处理 20W 数据,那么这 20W 数据就会放入内 存中计算,剩下 10W 放到磁盘中。
- 不支持细粒度的写和更新操作,Spark 写数据是粗粒度的,所谓粗粒度, 就是批量写入数据,目的是为了高效率。但是 Spark 读数据是细粒度的, 也就是说可以一条条的读。
- 不支持增量迭代计算,如果对 Flink 熟悉,可以说下 Flink 支持增量迭代计算。
3.RDD 的宽窄依赖
窄依赖:父 RDD 的一个分区只会被子 RDD 的一个分区依赖;
宽依赖:父 RDD 的一个分区会被子 RDD 的多个分区依赖(涉及到 shuffle)。
- 对于窄依赖:
窄依赖的多个分区可以并行计算;
窄依赖的一个分区的数据如果丢失只需要重新计算对应的分区的数据就 可以了。
- 对于宽依赖:
划分 Stage(阶段)的依据:对于宽依赖,必须等到上一阶段计算完成才能计算下一阶段。
4.DAG 中为什么要划分 Stage?
并行计算。
一个复杂的业务逻辑如果有 shuffle,那么就意味着前面阶段产生结果后,才能执行下一个阶段,即下一个阶段的计算要依赖上一个阶段的数据。那么我们按照shuffle 进行划分(也就是按照宽依赖就行划分),就可以将一个 DAG 划分成多 个 Stage/阶段,在同一个 Stage 中,会有多个算子操作,可以形成一个pipeline 流水线,流水线内的多个平行的分区可以并行执行。
对于窄依赖,partition 的转换处理在 stage 中完成计算,不划分(将窄依赖尽 量放在在同一个 stage 中,可以实现流水线计算)。
对于宽依赖,由于有 shuffle 的存在,只能在父 RDD 处理完成后,才能开始接 下来的计算,也就是说需要要划分 stage。
核心算法:回溯算法
从后往前回溯/反向解析,遇到窄依赖加入本 Stage,遇见宽依赖进行 Stage 切分。 Spark 内核会从触发 Action 操作的那个 RDD 开始从后往前推,首先会为最后 一个 RDD 创建一个 Stage,然后继续倒推,如果发现对某个 RDD 是宽依赖,那 么就会将宽依赖的那个 RDD 创建一个新的 Stage,那个 RDD 就是新的 Stage的最后一个 RDD。 然后依次类推,继续倒推,根据窄依赖或者宽依赖进行 Stage的划分,直到所有的 RDD 全部遍历完成为止。
5.Spark 程序执行,有时候默认为什么会产生很多 task,怎么修改默认 task 执行个数?
- 输入数据有很多 task,尤其是有很多小文件的时候,有多少个输入 block就会有多少个 task 启动;
- spark 中有 partition 的概念,每个 partition 都会对应一个 task,task 越多,在处理大规模数据的时候,就会越有效率。不过 task 并不 是越多越好,如果平时测试,或者数据量没有那么大,则没有必要 task 数 量太多。
- 参数可以通过 spark_home/conf/spark-default.conf 配置文件设置:
针对 spark sql 的 task 数量:spark.sql.shuffle.partitions=50
非 spark sql 程序设置生效:spark.default.parallelism=10
6.RDD 中 reduceBykey 与 groupByKey 哪个性能好,为什么?
reduceByKey:reduceByKey 会在结果发送至 reducer 之前会对每个 mapper 在本地进行 merge,有点类似于在 MapReduce 中的 combiner。这样做的好处在于,在 map 端进行一次 reduce 之后,数据量会大幅度减小,从而减小传输,保证reduce 端能够更快的进行结果计算。
groupByKey:groupByKey 会对每一个 RDD 中的 value 值进行聚合形成一个序列(Iterator),此操作发生在 reduce 端,所以势必会将所有的数据通过网络进行传输,造成不必要的浪费。同时如果数据量十分大,可能还会造成OutOfMemoryError。
所以在进行大量数据的 reduce 操作时候建议使用 reduceByKey。不仅可以提高 速度,还可以防止使用 groupByKey 造成的内存溢出问题。
7.Spark Master HA 主从切换过程不会影响到集群已有作业的运行,为什么?
不会的。
因为程序在运行之前,已经申请过资源了,driver 和 Executors 通讯,不需要和 master 进行通讯的。
8.Spark Master 使用 Zookeeper 进行 HA,有哪些源数据保存到
Zookeeper 里面?
spark 通过这个参数 spark.deploy.zookeeper.dir 指定 master 元数据在zookeeper 中保存的位置,包括 Worker,Driver 和 Application 以及Executors。standby 节点要从 zk 中,获得元数据信息,恢复集群运行状态, 才能对外继续提供服务,作业提交资源申请等,在恢复前是不能接受请求的。
注:Master 切换需要注意 2 点:
1、在 Master 切换的过程中,所有的已经在运行的程序皆正常运行! 因为 SparkApplication 在运行前就已经通过 Cluster Manager 获得了计算资源,所以在运行时 Job 本身的 调度和处理和 Master 是没有任何关系。
2、在 Master 的切换过程中唯一的影响是不能提交新的 Job:一方面不能够提交新 的应用程序给集群, 因为只有 Active Master 才能接受新的程序的提交请求;另 外一方面,已经运行的程序中也不能够因 Action 操作触发新的 Job 的提交请求。
9.Spark 主备切换机制原理知道吗?
Master 实际上可以配置两个,Spark 原生的 standalone 模式是支持 Master主备切换的。当 Active Master 节点挂掉以后,我们可以将 Standby Master 切 换为 Active Master。
Spark Master 主备切换可以基于两种机制,一种是基于文件系统的,一种是基于 ZooKeeper 的。
基于文件系统的主备切换机制,需要在 Active Master 挂掉之后手动切换到 Standby Master 上;
而基于 Zookeeper 的主备切换机制,可以实现自动切换 Master。
10.RDD 持久化原理?
spark 非常重要的一个功能特性就是可以将 RDD 持久化在内存中。调用 cache()和 persist()方法即可。cache()和 persist()的区别在于,cache() 是 persist()的一种简化方式,cache()的底层就是调用 persist()的无参版本
persist(MEMORY_ONLY),将数据持久化到内存中。 如果需要从内存中清除缓存,可以使用 unpersist()方法。RDD 持久化是可以手 动选择不同的策略的。在调用 persist()时传入对应的 StorageLevel 即可。
11.Checkpoint 和持久化机制的区别?
最主要的区别在于持久化只是将数据保存在 BlockManager 中,但是 RDD 的lineage(血缘关系,依赖关系)是不变的。但是 checkpoint 执行完之后,rdd 已经没有之前所谓的依赖 rdd 了,而只有一个强行为其设置的 checkpointRDD,checkpoint 之后 rdd 的 lineage 就改变了。
持久化的数据丢失的可能性更大,因为节点的故障会导致磁盘、内存的数据丢失。但是 checkpoint 的数据通常是保存在高可用的文件系统中,比如 HDFS 中,所以数据丢失可能性比较低
12.Spark Streaming 以及基本工作原理?
Spark streaming 是 spark core API 的一种扩展,可以用于进行大规模、高吞吐量、容错的实时数据流的处理。 它支持从多种数据源读取数据,比如 Kafka、Flume、Twitter 和 TCP Socket, 并且能够使用算子比如 map、reduce、join 和 window 等来处理数据,处理后的数据可以保存到文件系统、数据库等存储中。
Spark streaming 内部的基本工作原理是:接受实时输入数据流,然后将数据拆 分成 batch,比如每收集一秒的数据封装成一个 batch,然后将每个 batch 交给 spark 的计算引擎进行处理,最后会生产处一个结果数据流,其中的数据也是一个一个的 batch 组成的。
13.DStream 以及基本工作原理?
DStream 是 spark streaming 提供的一种高级抽象,代表了一个持续不断的数 据流。
DStream 可以通过输入数据源来创建,比如 Kafka、flume 等,也可以通过其他DStream 的高阶函数来创建,比如 map、reduce、join 和 window 等。 DStream 内部其实不断产生 RDD,每个 RDD 包含了一个时间段的数据。
Spark streaming 一定是有一个输入的 DStream 接收数据,按照时间划分成一个一个的 batch,并转化为一个 RDD,RDD 的数据是分散在各个子节点的partition 中
18.Spark 中的数据倾斜问题
-
前提是定位数据倾斜,是 OOM 了,还是任务执行缓慢,看日志,看 WebUI
-
解决方法,有多个方面:
避免不必要的 shuffle,如使用广播小表的方式,将 reduce-side-join
提升为 map-side-join
分拆发生数据倾斜的记录,分成几个部分进行,然后合并 join 后的结果
改变并行度,可能并行度太少了,导致个别 task 数据压力大
两阶段聚合,先局部聚合,再全局聚合
自定义 paritioner,分散 key 的分布,使其更加均匀