Spark面试大全
众人拾柴火焰高,这里贴了面经的共享在线文档,大家可以自由编辑,共同丰富题库。
整理不易,关注+收藏不迷路赞
在线文档:
-----------------------------------------分界线-----------------------------------------
1.基础
1.1 介绍下Spark
Spark 是一个快速、通用的大数据处理框架,它提供了一整套开发 API,包括流计算和机器学习。它支持批处理和流处理。Spark 的一个显著特点是它能够在内存中进行迭代计算,从而加快数据处理速度。尽管 Spark 是用 Scala 开发的,但它也为 Java、Scala、Python 和 R 等高级编程语言提供了开发接口。
1.2 Spark计算的灵活性体现在哪里
- 支持多种数据源
- 弹性的集群扩展性
- 多语言支持
- 灵活的数据处理模型
1.3 Spark的架构
(1)资源管理
Master
Worker
(2)任务运维
Driver
运行Main()函数的地方
构建DAG
划分任务
task生成和调度
数据的分发和广播
结果的汇总
监控和错误处理
Executor
任务执行,并将结果返回给Driver
为RDD提供内存式存储
1.4 Spark的使用场景
- 快速处理大数据
- 多次操作特定数据集
- 基于大数据的流式计算,图计算,机器学习场景
- 支持多种语言的开发场景
1.5 Spark为什么比Hadoop速度快?
Spark多任务之间通信是基于内存,而Hadoop是基于磁盘;
消除了冗余的读写:Hadoop每次shuffle操作后,必须要写到磁盘,Spark在shuffle后不一定要落盘,可以cache到内存中;
消除了冗余的MR阶段:Hadoop每次shuffle操作一定连着完整的MR操作,Spark基于RDD提供了丰富的算子,且reduce操作产生的shuffle数据,可以缓存到内存中;
JVM的优化:Spark启动采用了fork线程的方式,每次的MR操作都是基于线程的,Hadoop采用的是创建线程的方式,启动Task便会启动一次JVM。
2.Spark执行流程
2.1 Yarn-Client模式
a. 客户端提交一个Application,在客户端启动一个Driver进程
b. 应用程序启动后向RM(ResourceManager)发送请求,启动AM(ApplicationMaster)的资源
c. RM收到请求,随机选择一台NM(NodeManager)启动AM,这里的NM相当于Standalone中Worker节点
d. AM启动后,会向RM请求一批container资源,用于启动Executor
e. RM会找一批NM返回给AM,用于启动Executor
f. AM会向这些NM发送命令启动Executor
g. Executor启动后,会反向注册给Driver,Driver发送task到Executor,执行情况和结果返回给Driver端
2.2 Yarn-Cluster模式
a. 客户端提交application,发送请求到RS(ResourceManager),请求启动AM(ApplicationMaster)
b. RS收到请求后随机在一台NM(NodeManager)上启动AM,这里AM相当于Driver端
c. AM启动,AM发送请求到RS,请求一批container用于启动Executor
d. RS返回一批NM节点给AM
e. AM连接这些NM,发送请求启动Executor
f. Executor启动后,会反向注册给AM所在的节点的Driver,Driver发送task到Executor,执行情况和结果返回给Driver端
2.3 Spark Yarn-Cluster模式Yarn-Client模式对比
Yarn-Cluster模式主要用于生产环境中,因为Driver运行在Yarn集群中某一台NodeManager中,每次提交任务的Driver所在的机器都是随机的,不会产生某一台机器网卡流量激增的现象。这种模式在客户端看不到task的执行和结果,要到webui中查看。
Yarn-Client模式适用于程序测试,不适合生产环境。当客户端提交多个application时,每个application都有自己独立的Driver,Driver会与Yarn集群中的Executor进行大量的通信,造成客户机网卡流量的激增问题。Yarn-client模式在客户端可以看到task执行和结果。
ApplicationMaster在Client模式中作用:为当前的Application申请资源,给NodeManager发送消息启动Executor。在Cluster模式中作用除了上述之外还有任务调度的作用。
2.4 Spark的cluster模式有什么好处
Cluster的Driver存在于集群上,Client提价作业后就可以关闭了;
Driver就在Yarn集群中,进行复杂调度的时候,网络通信性能较好。
https://www.cnblogs.com/ITtangtang/p/7967386.html
2.5 Spark内部执行原理
a. 构建Spark Application的运行环境(启动SparkContext),SparkContext向资源管理器(可以是Standalone、Mesos或YARN)注册并申请运行Executor资源
b. 资源管理器分配Executor资源并启动StandaloneExecutorBackend,Executor运行情况将随着心跳发送到资源管理器上
c. SparkContext构建成DAG图,并发往DAG Scheduler,DAG Scheduler基于DAG图划分Stage,并以Taskset形式发送给Task Scheduler。Executor向SparkContext申请Task
d. Task Scheduler将Task发放给Executor运行,同时SparkContext将应用程序代码发放给Executor
e. Task在Executor上运行,运行完毕释放所有资源
2.6 介绍DAGScheduler、TaskScheduler、SchedulerBackend
DAGScheduler:划分Stage,从Job后往前逆推,遇到宽依赖划分新的Stage,遇到窄依赖就压栈。同时为避免重复运算,访问过的RDD会存入Hashset中,递归调用getParentStage来递归创建Stage,进而分配StageId,越往前StageId越小。最终将一组包含了task的stage提交给TaskScheduler。
TaskScheduler:在不同的job之间调度,同时接收被分配的资源,再给每一个task分配到executor上,资源调度策略常用FIFO和公平调度。
SchedulerBackend:与cluster manager资源管理器交互取得应用被分配的资源。
3.RDD
3.1 介绍下RDD
RDD是Spark中的弹性分布式数据集,是一个不可变的分布式对象集合,每个RDD被分为多个分区,这些分区可以运行在集群的不同节点上。
分布式:RDD的数据是分布在各个分区之上的,各个分区被托管在多个Excutor上
弹性:
容错弹性——数据丢失可以自动恢复;
存储弹性——内存/磁盘;
计算弹性——计算出错可重试;
分区弹性——可根据需求重新分区。
数据集:存储数据的集合。
3.2 RDD的特点
- RDD是有分区的的
- 算子作用在每一个分区之上
- RDD之间是有血缘关系的
- 针对K-V型RDD,可以自定义分区器(默认的分区规则是Hash规则)
- RDD加载数据将会就近加载(移动数据不如移动计算)
3.3 RDD算子分类
算子是作用在分布式数据集上的API,作用在本地对象的API称之为方法/函数。
(1)Transformation
将一个RDD转化为一个新的RDD
(2)Action
返回值不再是RDD,用于将Transformation生成的DAG图进行调用开启,汇总计算记过到Driver;
Action算子中有两个特殊算子:foreach、saveAsText,由RDD分区直接执行,和Driver无交互。
3.4 RDD的属性
(1)分区列表
每一个分区都会被一个计算任务(Task)处理,分区数决定了并行计算的数量。
(2)每一个分区都有一个计算函数
Spark的RDD的计算函数是以分片为基本单位的,每个RDD都会实现 compute函数,对具体的分片进行计算,不需要保存每次计算的结果。
(3)依赖关系
宽窄依赖
(4)key-value数据类型的RDD分区器
(5)首选位置
按照移动数据不如移动计算原则,Spark在执行任务时,尽可能将计算任务分配到其要处理的数据块所在节点。
3.5 RDD缓存级别
a. 默认使用memory_only级别;
b. 不够则用memory_only_ser补充,指将数据序列化后存入内存;
c. 如果内存还不够用则使用MEMORY_AND_DISK或memory_and_disk_ser;
d. 很少用disk_only;
e. 除此之外还有only_heap,将数据存放在堆外内存。
3.6 Spark的cache和persist的区别?它们是transformaiton算子还是action算子?
相同点:都是将一个RDD进行缓存
区别:RDD中cache()本质是调用了无参的persist(),无参的persist()内部调用了torageLevel.MEMORY_ONLY;而有参的persist()可以根据情况设置其他缓存级别;
DataFrame中cache()依然是调用了persist(),但是persist调用了cacheQuery,而cacheQuery的默认级别是MEMORY_AND_DISK;
它们都属于Transformations型算子。
3.7 DataFrame和RDD的区别
DF存储二维表结构(必须结构化),RDD则不限制存储结构;
DF可以自动优化,RDD则不能自动优化;
DF底层依然是基于RDD实现的。
3.8 RDD中持久化
RDD的数据是过程数据,一旦新的RDD产生,旧的RDD数据将不存在;如果多次使用某个RDD,如果没有缓存,就需要通过依赖重新生成这个RDD,因此RDD提供了持久化技术对中间计算过程进行保存。
- 缓存
保持血缘关系,设计是不安全的,可以存储在本地磁盘,也可以存储在Executor内存中。
- CheckPoint
不保留血缘关系,设计上是安全的,可以存储在本地硬盘、HDFS中,不能存储在内存中。
3.9 Spark有了RDD,为什么还要有Dataform和DataSet?
- 后者具有更高级的API,支持SQL查询;
- DataFrame和DataSet建立在DataFrame Catalyst优化引擎之上,使用了许多查询优化技术,如谓词下推、列式存储、代码生成等;
- DataSet是强类型的数据抽象,与RDD和DataFrame相比,它提供了更高的类型安全性。通过编译时的类型检查,可以在开发阶段捕获错误,降低运行时错误的风险,提高代码的可靠性和可维护性;
- DataFrame使用列式存储和查询优化引擎,具有更高的执行效率。
3.10 Spark的RDD、DataFrame、DataSet、DataStream区别?
(1)概念
RDD是Spark最早的数据抽象,对应于弹性分布式数据集,具有更低级别的API。
DataFrame是一种以结构化形式组织的分布式数据集合,提供了更高级别的API和SQL查询能力,适用于大规模数据处理和数据分析。
DataSet提供了类型安全、编译时检查和优化的特性,适用于更好的错误检测和优化。
DataStream中用于表示连续数据流的数据抽象,适用于流式计算和实时数据分析。
(2)共性
都是Spark的分布式弹性数据集;
都有惰性机制,并且有许多共同函数;
三者都会根据Spark内存情况自动缓存运算;
都有partition概念。
(3)不同点
RDD一般同SparkMlib一起使用,不支持SparkSQL操作;
DataFrame每一行的类型固定为Row,每一列的值只有解析后才能获取;
DataFrame和DataSet一般不同SparkMlib使用,且均支持SparkSQL,支持方便的保存方式,如csv;
DataSet每一行的数据类型可以不同。
3.11 怎么创建DataFrame?
使用toDF函数:元组.toDF(列名)
createDataFrame函数:createDataFrame(数据, schema)
3.12 reduce,reduceByKey,groupByKey的区别?
reduce:针对RDD中元素做二元函数聚合操作。
reduceByKey:按照键对RDD中的元素分组,并对每组都做二元函数聚合操作。
groupByKey:按照键对RDD中的元素进行分组。
3.13 Spark的map和flatmap的区别?
map是对RDD中的元素逐一进行函数操作映射为另一个rdd;
flatMap的操作是将函数应用于RDD之中的每一个元素,将返回的迭代器的所有内容构成新的rdd。
3.14使用reduceByKey出现数据倾斜怎么办?
可以给倾斜的Key加上不同的前缀,先做一次聚合,然后去掉前缀做第二次聚合。
3.15 Spark SQL如何使用UDF?
例子:将字母大写
注册:spark.udf.register("x", (x:String)=>x.toUpperCase)
使用:spark.sql("select x(id) as new_id from frame").show()
4.SparkSQL
4.1 SparkSQL执行流程
(1)提交代码
(2)Catalyst优化器优化
a. Parser阶段:将Spark SQL解析为AST;
b. Analyzer阶段:遍历AST,对每个节点进行数据类型绑定以及函数绑定,并根据元数据信息Catalog对数据表中的字段进行解析;
c. Optimizer阶段:优化的核心,主要分为RBO和CBO两种优化策略,其中RBO是基于规则优化,CBO是基于代价优化,常见的规则:谓词下推、常量累加以及列值裁剪。该阶段是对逻辑计划的优化。
d. SparkPlanner阶段:Planner将OptimizedLogicPlan转为物理计划,该阶段针对优化后的逻辑计划生成了多个物理计划,CBO优化策略会选择其中执行代价最小的计划作为最终执行物理计划。
(3)执行物理计划
4.2 数据倾斜
(1)影响
任务执行慢;频繁或一直OOM。
(2)判断
- 查看任务-->查看Stage-->查看task运行时间是否差异较大;
- 少数情况是OOM问题,调大内存;
- task运行时间差异过大的话则查看相应代码,看是否有shuffle算子。
(3)典型场景&解决办法
a. 数据源中数据分布不平均
- Hive通过ETL对数据进行预处理
- Kafka数据源的话调整数据分发时尽量平均分发
优点:简单,效果好。
缺点:Hive中或Kafka中数据倾斜无法避免。
b. 增加并行度
- 增加shuffle read task的数量,原先分给一个task的多个key分配到多个task上。
优点:简单,有效。
缺点:治标不治本,只是缓解了数据倾斜,没有从根本上解决;极端情况存在key的数据量极大时,依旧无法处理;修改并行度可能影响后续的Stage。
c. 自定义Partitioner
使用自定义Partitioner实现类代替HashPartitioner,尽量将不同的Key均匀分布在不同的Task中。
优点:不影响原有并行度设计。
缺点:适用场景有限,只能将不同的key分开,不能对大量同一key的场景适用;需要自定义Partitioner,不够灵活。
d. 聚合操作分布不均匀
多段聚合,先将倾斜key加盐做初步聚合,再去盐做全局聚合。
优点:对聚合类倾斜效果很好。
缺点:只能用于聚合类倾斜。
e. join类倾斜——大小表join
广播小RDD全量数据+map算子来实现与join同样的效果。
优点:对join操作导致的数据倾斜效果特别好。
缺点:适用场景较少。
f. join类倾斜——大大表join少数key分布不均
- 将倾斜RDD中倾斜Key单独抽取出来加盐1-N形成新的RDD
- 将没有倾斜的RDD中对应的倾斜Key空充N倍,加盐1-N形成新的RDD
- 将两个RDD join后去盐
- 将剩余非倾斜Key数据join
- 最后通过union合并两次join后的数据
优点:相对于Map侧join,更适应“大数据”的join;
资源充足情况下,倾斜部分数据和非倾斜部分数据可以并行进行,效率提升显著;
只针对倾斜key做数据扩展,资源消耗有限。
缺点:如果倾斜的Key比较多,非倾斜RDD中倾斜key膨胀后特别大,不适用;
对倾斜key与非倾斜key分开处理,需要扫描两次数据集。
g. join类倾斜——大大表较多的key分布不均
- 将切斜RDD中每条数据都加上1-N的随机前缀
- 对非倾斜RDD进行扩容,每条数据扩容成N条数据,同时加上前缀1-N
- 最后对两个处理后的RDD进行join
优点:
适用于所有类型的join类数据倾斜;
效果显著。
缺点:
要对整个RDD进行扩容,对内存资源要求较高
h. 少数key数据量特别大,不均匀,但其他数据均匀
直接过滤掉少数倾斜key。
优点:实现简单;完全规避数据倾斜。
缺点:适用场景不多。
4.3 Spark SQL的优化?
只取需要用的数据(行列过滤);
避免笛卡尔积;
选择适合的join;
遇到数据倾斜时要处理数据倾斜。
4.4 Spark输出文件的个数,如何合并小文件?
使用coalesce(num)或reparation(num)方法调整分区数
设置一些参数https://www.jianshu.com/p/ac76c9bed557
4.5 Spark SQL的劣势?
稳定性:由于代码质量问题,Spark长时间运行会经常出错,在架构方面,由于大量数据被缓存在RAM中,Java回收垃圾缓慢的情况严重,导致Spark的性能不稳定。
处理数据量上限不如MR:单机处理数据过大时,或者中间数据结果超出RAM大小时,经常出现RAM空间不足或者无法得出结果。
不能支持复杂的SQL统计。
5.Spark Join
5.1 Spark Join分类有哪些
(1)Broadcast Hash Join
使用条件:数据集的总行数小于MAX_BROADCAST_TABLE_ROWS阈值
原理:将小表的数据广播(broadcast)到 Spark 所有的 Executor 端
过程:先利用 collect 算子将小表的数据从 Executor 端拉到 Driver 端,然后在 Driver 端调用 sparkContext.broadcast 广播到所有 Executor 端;然后在 Executor 端这个广播出去的数据会和大表进行 Join 操作,这种 Join 策略避免了 Shuffle 操作。
(2)Shuffle Hash Join
使用条件:仅限于等值join;较小的表要小于广播阈值和shuffle分区数的乘积;小数据集的3倍要小于大数据集。
过程:把大表和小表按照相同的分区算法和分区数进行分区(根据参与 Join 的 keys 进行分区),这样就保证了 hash 值一样的数据都分发到同一个分区中,然后在同一个 Executor 中两张表 hash 值一样的分区就可以在本地进行 hash Join。
(3)Suffle Sort Merge Join
使用条件:仅限于等值join;参与join的值可以排序。
过程:对两张表参与 Join 的 Keys 使用相同的分区算法和分区数进行分区,目的就是保证相同的 Keys 都落到相同的分区里面。分区完之后再对每个分区按照参与 Join 的 Keys 进行排序,最后 Reduce 端获取两张表相同分区的数据进行 Merge Join,也就是 Keys 相同数据Join。
(4)Cartesian Product Join
使用条件:等值join或不等值join都可;join类型为innerLike。
(5)Broadcast nested loop join
会对某张表多次扫描,效率极低
使用条件:支持等值和不等值join;支持所有join类型
5.2 Spark Map Join
(1)原理
将小份数据广播到各个计算节点,加载到内存建立map索引,大份数据作为MapTask的输入,map()去内存中直接进行匹配关联
(2)缺点
map索引在遇到相同的key时新数据会覆盖旧数据,因此key值存在重复时要做处理;
由于广播时要通过driver端进行,因此增大了driver端内存压力;
小数据要广播到每个executor中,因此增加了executor的内存压力。
5.3 Spark Reduce Join
(1)原理
map端:读取表的数据,Map 输出时候以关联条件中的列为 key ,如果 Join 有多个关联键,则以这些关联键的组合作为 key;Map 输出的 value 为 select或where用到的数据;同时在 value 中还会包含表的 Tag 信息,用于标明此 value 对应哪个表;
shuffle阶段:根据key的值进行hash,将不同的k-v推送到不同的分区中,确保不同表中相同key位于一个分区中;
reduce端:通过tag判断每个value的来源,分组后做笛卡尔积。
(2)缺点
分组后shuffle网络传输性能低
最后reduce阶段做笛卡尔积很耗内存
shuffle按照key分区,容易发生数据倾斜
5.4 Spark Join一定就是宽依赖吗?
Join的两个RDD采用相同的分区方式(例如,都是基于哈希分区或范围分区),并且两个RDD具有相同的分区数时,则join为窄依赖。源码:if (rdd.partitioner == Some(part))
5.5 Spark的哪些算子会有shuffle过程?
reduceByKey
groupByKey
aggregateByKey:按照不同规则进行分区内计算和分区间计算
foldByKey:分区内计算和分区间计算相同时,代替aggregateByKey
combineByKey:用于将相同键(key)的值进行分组并应用自定义的聚合函数来计算结果
sortByKey:按照键对RDD进行排序
repartition:移动RDD分区增加/减少分数数量,一定会shuffle
coalesce:仅用于减少分区数量,分区之间数据移动较低,可指定是否shuffle
join
6.Spark Shuffle
(1)HashShuffle
按照当前Stage中数据的key的Hash值进行重分区。
- 未优化前
下一个Stage有多少个Task,当前Stage的每个Task就需要创建多少份磁盘文件。
- 优化后
每个executor(假设单核)为下一个Stage的每个Task产生一个文件。
优点:可以省略不必要的排序开销;避免了排序所需的内存开销。
缺点:生产的文件数量过多,对文件系统造成压力;大量小文件的随机读写具有一定的磁盘开销;同时数据块写入时所需的缓存空间也随之增加,对内存造成较大压力。
(2)Sort Shuffle
- 未优化前
类似于MR的shuffle,每个task的计算结果都会写入到内存中,达到阈值后溢写到磁盘,溢写时文件内部有序,task结束后,生成所有的小文件合并成一个文件,并生成一个索引文件,下一个Stage的task读取文件时,首先解析索引文件,再去拉取相应数据。
- 优化后——bypass
使用条件:shuffle map task数量小于spark.shuffle.sort.bypassMergeThreshold=200参数的值,并且为非聚合类算子。
原理:在下个Stage中task较少时,没必要对当前阶段数据进行排序,同Hash Shuffle类似,按照key的hash值将数据写入磁盘文件,同样的先写入内存缓冲,再溢写磁盘,最终合并使得每个task只产出一个文件。不同的是,最后还是会合并为一个文件,并且生成一个索引文件。
- “钨丝”SortShuffle
使用基于内存的序列化和列式存储来提高排序和 Shuffle 的性能,排序的不是数据本身,而是内容序列化后字节数组的指针(元数据)。
7.其它
7.1 Spark为什么适合迭代处理
spark中间计算数据优先存放于内存中复用,对于迭代计算有一定的优势;
容错性,迭代处理时即使出现了错误,也可以自动恢复故障并重新计算。
7.2 Spark源码中怎么判断Shuffle Map Stage或Result Stage?
根据DAG中依赖关系判断,存在Shuffle依赖,表示需要对数据进行Shuffle,则该Stage被标记为Shuffle Map Stage。
划分阶段时会检查当前Stage是否有未Shuffle的依赖。如果有未Shuffle的依赖,那么该Stage将被标记为Result Stage。
7.3 Application、job、Stage、task之间的关系
Application:独立的Spark应用程序,它包含了用户编写的一系列数据处理代码。一个Spark应用程序通常由一个或多个Job组成。
Job:Spark执行层级的最高层,每个Job对应一个action。
Stage:Job的划分,它表示一组可以并行执行的任务集合,每个Stage在各自所在executor中进行运算。
Task:Spark任务执行的最小层级单位,表示对数据的实际处理动作,每个task负责处理一个RDD分区。
7.4 Stage的数量等于什么?为什么要划分Stage
Stage的数量等于DAG中的层数,每一层对应一个阶段。每个Stage内的任务可以并行执行,提高了整体的计算效率和性能。执行任务前Spark就会将一个Stage所需数据发到所在节点,Stage内的任务执行时,数据不用再进行网络传输。
7.5 Spark广播变量的实现和原理?
实现:调用SparkContext的broadcast(v)函数即可。
原理:将要发送的数据向每个executor发一份只读数据,而不是向task发送,因此节省了很多时间。
使用场景:任务跨多个Stage,因为执行任务前Spark就会将一个Stage所需数据发到所在节点,因此单个Stage所用数据不必再通过广播发送。
7.6 HashPartitioner,RangePartitioner的实现
(1)HashPartitioner
对于给定的key,计算其hashCode,并除于分区的个数取余,最后返回的值就是这个key所属的分区ID。
(2)RangePartitioner
主要作用就是将一定范围内的数映射到某一个分区内。
步骤:
- 先从整个RDD中抽取出样本数据,将样本数据排序,计算出每个分区的最大key值,形成一个Array[KEY]类型的数组变量rangeBounds;
- 判断key在rangeBounds中所处的范围,给出该key的分区ID。
7.7 Spark的水塘抽样
N个数随机抽样k个,创建一个k长的数组,前k个数字直接存入,k+1个开始随机抽取数组中已有元素进行替换。
7.8 Spark的lazy体现在哪里?
一句话概括:spark直到action动作之前,数据不会先计算。pipline思想:数据用的时候再算。
好处:
- 可以将代码的程序变成一块块的操作链(computer chain),这样就能够很好的兼顾代码的可读性和减少耦合;
- 只算需要算的,极大的减少中间的计算过程;
- 降低时间复杂度(2里面)和空间复杂度(中间结果落盘)。
7.9 Spark中的并行度等于什么
并行度概念:spark作业中,各个stage的task的数量,也就代表了spark作业在各个阶段stage的并行度;
为什么设置并行度:使计算机资源充分被利用;
如何设置:
- 增加task数量
至少要与core数相等,官方推荐设置为core总数的2~3倍
- 增加block数量
如果读取的数据在HDFS上,增加block数,默认情况下split与block是一对一的,而split又与RDD中的partition对应,所以增加了block数,也就提高了并行度
- RDD.repartition
给RDD重新设置partition的数量
- 算子指定partition的数量
例:val rdd2 = rdd1.reduceByKey(_+_,10) val rdd3=rdd2.map.filter.reduceByKey(_+_)
- 增加父RDD中partition数量
rdd3里面partiiton的数量是由父RDD中最多的partition数量来决定,因此使用join算子的时候,增加父RDD中partition的数量
7.10 Spark SQL读取文件,内存不够使用,如何处理?
增大Executor内存
调整分区大小,较小的分区可以减少每个任务读取的数据量,从而减少内存压力
选择合适的压缩格式压缩数据文件
优化SQL
#Spark##面经##大数据#