3.Spark面试

第6章 spark
6.1 什么是spark
spark是基于内存计算大数据分析引擎,提高了在大数据环境下数据处理的实时性.
spark仅仅只涉及到数据的计算,没有涉及到数据的存储.
 
6.1.1 spark的特点及相对于MapReduce的优势\
MapReduce存在的问题:
MapReduce框架局限性
1.MapReduce只支持map和reduce两种操作
2.处理效率低效
a)map中间结果写磁盘,reduce写hdfs,多个mr之间通过HDFS交换数据;
任务调度和启动开销大
b)无法充分利用内存
c)map端和reduce端均需要排序
3不适合迭代计算(如机器学习/图计算等),交互式处理(数据挖掘)和流式处理(点击日志分析)
 
2.MapReduce编程不够灵活
1)尝试Scala函数式编程语言
 
spark的特点及优势
1.高效(比MapReduce快10-100倍)
1)内存计算引擎,提供cache机制来支持需要反复迭代计算或者多次数共享,减少数据读取的IO开销
2)DAG引擎,减少多次计算之间中间结果写到HDFS的开销
3)使用多线程模型来减少task启动开销,shuffle过程中避免不必要的sort操作以及减少磁盘IO操作
2.易用
1)提供了丰富的API,支持java,Scala,python和R四种语言
2)代码量比MapReduce少2-5倍
 
兼容性
可与Hadoop集成 读写HDFS/Hbase/Cassandra 与yarn集成
 
通用性
spark可以用于批处理/交互式查询(spark sql)/实时流处理(spark streaming)/机器学习(spark MLlib)和图计算(GraphX)
 
6.1.2 spark HA高可用部署
1.基于文件系统的单点恢复(主要用于开发或测试环境)
2.基于zookeeper的Standby Masters(用于生产模式)
 
6.1.3 spark的角色
Driver Program:运行main函数并且新建SparkContext的程序(初始化工作)
Application:基于spark的应用程序,包含了driver程序和集群上的executor(代码逻辑与运行资源)
Cluster Manager:指的是在集群上获取资源的外部服务(提供外部运行资源,资源分配),目前有三种类型
1)Standalone:spark原生的资源管理,有Master负责资源的分配
2)Apache Mesos:与Hadoop MR兼容性良好的一种资源调度框架
3)Hadoop yarn:主要是指yarn中的ResourceManager
Master:集群中老大,负责资源的分配和任务的调度
Worker Node:集群中任何可以运行Application代码的节点(小弟),在Standalone模式中指的是通过
slaves文件配置的worker节点,在spark on yarn 模式下就是nodemanager节点
Executor:是在一个worker node上为某应用启动的一个进程,该进程负责运行任务,并且负责将数据存在内存或者磁盘上,每个应用都有各自独立的executor(运行当前任务所需要的资源)
Task:被送到某个executor上的工作单元(线程)
cache:spark中设置的数据缓存
 
6.1.6 在IDEA中编写WordCount程序
1.创建Maven项目并配置pom.xml
2.添加src/main/scala和src/test/scala,与pom.xml中的配置保持一致
3.新建一个Scala class,类型为object,并编写spark程序
4.使用maven打包上传到spark集群中的某个节点上
5.启动hdfs和spark集群
6.使用spark-submit命令提交spark应用
 
6.2 spark streaming
6.2.1 spark streaming的特性
易用 容错 易整合
 
6.3 算子操作
6.3.1 Trasformations
 
特殊的转换算子(以下两个都需要设置checkpoint)
UpdateStateByKey(累加统计)
Window Operations(开窗函数)
窗口大小和滑动间隔 一定要是设定的数据批处理间隔的整数倍,否则会报错.
 
6.3.2 OutputOperations
Output Operations可以将DStream的数据输出到外部的数据库或文件系统,当某个Output Operations被调用时(与RDD的Action相同),spark streaming程序才会开始真正的计算过程.
 
6.3.3 spark streaming编程实战
开发流程:
1.构建sparkContext对象
2.构建StreamingContext对象
3.创建输入流InputDStream
4.对DStream执行算子操作
5.将执行结果保存或者输出
 
6.3.4 SparkStreaming 整合 flume
6.3.5 SparkStreaming 整合 Kafka
 
6.3.6 Checkpoint
Spark Streaming的检查点具有容错机制,有足够的信息能够支持故障恢复.支持两种数据类型的检查点:
元数据检查点和数据检查点
1)元数据检查点
在类似 HDFS的容错存储上,保存Streaming计算信息,这种检查点用来恢复运行Streaming应用程序失败的Driver进程.
 
2)数据检查点
在进行跨越多个批次合并数据的有状态操作时尤其重要,通过周期检查将转换RDD的中间状态进行可靠存储,借以切断无限增加的依赖.使用有状态的转换,如果updateStateByKey或者reduceByKeyAndWindow在应用程序中使用,那么需要提供检查点路径,对RDD进行周期性检查
 
当程序因为异常重启时,如果检查点路径存在,则context将从检查点数据中重建,如果检查点目录不存在,将会重建context,并设置DStream.
 
6.4 Spark SQL
6.4.1
1.Spark sql的属性
1)易整合:可通过sql开发对应的应用程序,也可以使用java/Scala/python/R编写的API来开发
2)统一的数据源访问:可以使用相同的方式来连接到不同的数据源
即sparkSession.read.文件格式(文件路径)
3)兼容hive:可以使用spark sql来操作hive sql
4)标准的数据连接:spark sql可以使用 标准的数据库连接(JDBC,ODBC)来操作关系型数据库
 
2.DataFrame与RDD的优缺点
RDD的优缺点:
优点:
1)编译时类型安全
编译时就能检查出类型错误
2)面向对象的编程风格
直接通过对象调用方法的形式来操作数据
 
缺点:
1)序列化和反序列化的性能开销
无论是集群间的通信,还是IO操作都需要对对象的结构和数据进行序列化和反序列化
2)GC(垃圾回收)的性能开销
频繁的创建和销毁对象,势必会增加GC
 
DataFrame通过引入schema(即数据的结构信息)和off-heap(不在堆里面的内存,指定是除了不在堆的内存,使用操作系统上的内存),解决了RDD的缺点,spark通过schema就能够读懂数据,因此在通信和IO时就只需要序列化和反序列化数据,而结构的部分就可以省略了;通过off-heap引入,可以快速的操作数据,避免大量的GC.但是丢了RDD的优点,DataFrame不是安全类型的.API也不是面向对象风格的.
 
 
6.4.2 以编程方式执行Spark SQL查询
1.编写Spark SQL程序实现RDD转换成DataFrame
1)通过反射推断Schema
2)通过StructType直接指定Schema
 
6.5 SparkRDD
6.5.1
1.什么是RDD
RDD叫做弹性分布式数据集,是spark中最基本的数据抽象,它代表一个不可变/可分区/里面的元素可并行计算的集合.RDD具有数据流模型的特点:自动容错/位置感知性调度和可伸缩性.
RDD允许用户在知性多个查询时显式地将数据缓存在内存中,后续的查询能够重用这些数据,这极大地提升了查询速度
 
4.RDD在spark中的地位及作用
2)spark如何解决迭代计算?
其主要思想就是RDD
 
6.5.3 RDD编写API
1.RDD的算子分类:
根据数据集创建一个新的数据集,计算后返回一个新的RDD
Action(动作):对rdd结果计算后返回一个数值value给驱动程序
 
6.5.5 RDD的依赖关系
1.RDD的依赖
RDD和它依赖的父RDD的关系有两种不同的类型,即窄依赖和宽依赖
 
2.窄依赖
一个父RDD的Partition最多被子RDD的一个Partition使用
 
2.宽依赖
多个字RDD的Partition会依赖同一个父RDD的Partition
 
6.5.6 RDD的缓存
spark的速度非常快的原因之一,就是在不同操作中可以在内存中持久化或者缓存数据集
RDD相关的持久化和缓存,是spark最重要的特征之一,可以说,缓存是spark构建迭代式算法和快速交互式查询的关键.
 
1.RDD缓存方式
RDD通过persist方法或者cache方法可以将前面的计算结果缓存,但是并不是这两个方法被调用时立即缓存,而是出发后面的action时,该RDD将会被缓存在计算节点的内存中,并供后面重用.
 
查看源码发现cache最终也是调用了persist方法,默认的存储级别都是仅在内存存储一份,spark的存储级别还有好多种,存储级别在object StorageLevel中定义的
 
6.5.7 DAG的生成
1.DAG叫做有向无环图
 
 
6.5.8 Spark任务调度
 
各个RDD之间存在着依赖关系,这些依赖关系就形成有向无环图DAG,DAGScheduler对这些依赖关系形成的DAG进行Stage划分,划分的规则很简单,从后往前回溯,遇到窄依赖加入本stage,遇见宽依赖进行
Stage划分.DAGScheduler基于Stage生成TaskSet,并将TaskSet提交给TashScheduler.
TashScheduler负责具体的task调度最后在Worker节点上启动task.
 
2.DAGScheduler
1)DAGScheduler对DAG有向无环图进行Stage划分
2)记录哪个RDD或者Stage输出被物化(缓存),通常在一个复杂的shuffle之后,通常物化一下(cache/persist),方便之后的计算.
3)重新提交shuffle输出丢失的stage(stage内部计算出错)给TaskScheduler
4)将Taskset传给底层调度器
 
3.TaskScheduler
1)为每一个TaskSet构建一个TaskSetManager实例管理这个TaskSet的生命周期
2)数据本地性决定每个Task最佳位置
3)提交taskset(一组task)到集群运行并监控
4)推测执行,碰到计算缓慢任务需要放到别的节点上重试
5)重新提交shuffle输出丢失的Stage给DAGScheduler
 
 
6.6 RDD容错机制之checkpoint
6.6.1 checkpoint是什么
1)Spark在生产环境下经常会面临transformation的RDD非常多(例如一个Job中包含1万个RDD)
或者具体transformation的RDD本身计算特别复杂或者耗时(例如计算时长超过1个小时),这个时候就要考虑对计算结果持久化保存;
2)spark是擅长多步骤迭代的,同时擅长基于Job的复用,这个时候如果能够对曾经计算的过程产生的数据进行复用,就可以极大的提升效率;
3)如果采用persist把数据放在内存中,虽然是快速的,但是也是最不可靠地;如果把数据放在磁盘上,也不是完全可靠地!例如磁盘会损坏,系统管理员可能清空磁盘.
4)Checkpoint的产生就是为了相对而言更加可靠地持久化数据,在Checkpoint的时候可以指定把数据
放在本地,并且是多副本的方式,但是在生产环境下放在HDFS上,这就天然的借助了HDFS高容错/高可靠的特征来完成了最大化的可靠地持久化数据的方式;
假如进行一个1万个算子操作,在9000个算子的时候persist,数据还是有可能丢失的,但是如果checkpoint,数据丢失的概率几乎为0.
 
6.6.2 checkpoint原理机制
1.当RDD使用cache机制从内存中读取数据,如果数据没有读到,会使用checkpoint机制读取数据.
此时如果没有checkpoint机制,那么就需要找到父RDD重新计算数据了,因此checkpoint是个很重要的容错机制.
 
checkpoint就是对于一个RDD chain(链)如果后面需要反复使用某些中间结果RDD,可能因为一些故障导致该中间数据丢失,那么久可以针对该RDD启动checkpoint机制,使用checkpoint首先需要调用sparkContext的setCheckpoint方法,设置一个容错文件系统目录,比如hdfs.
 
2.persist或者cache与checkpoint的区别在于,前者持久化只是将数据保存在BlockManager中但是其lineage是不变的,但是后者checkpoint执行完后,rdd已经没有依赖RDD.
persist或者cache持久化的数据丢失的可能性更大,因为可能磁盘或内存被清理,但是checkpoint的数据通常保存在hdfs上,放在了高容错文件系统.
 
哪些RDD需要cache?
会被重复使用的
 
问题:用户怎么设定RDD要cache?
问题:系统怎么对RDD进行cache?
问题:cached RDD怎么被读取?
 
 
6.6.3 Checkpoint常见面试问题
问题:哪些RDD需要checkpoint?
运算时间很长或者运算量太大能得到的RDD,computing chain过长或依赖其他
RDD很多的RDD,将ShuffleMapTash的输出结果存放到本地磁盘也算是checkpoint,只不过这个
checkpoint的主要目的是去partition输出数据.
问题:什么时候checkpoint?
cache机制是每计算一个cache的partition就直接将其cache到内存了,但是checkpoint没有使用
这种第一次计算得到就存储的方法,而是等到job结束后另外启动专门的job去完成checkpoint.
也就是说需要checkpoint的RDD会被计算两次.因此,在使用rdd.checkpoint()的时候,建议加入上
rdd.cache().
问题:checkpoint怎么实现?
RDD需要经过[Initialized --> marked for checkpointing --> checkpointing in progress --> checkpointed]
这几个阶段才能被checkpoint
 
6.7 Spark运行架构
6.7.1 spark运行基本流程
1)构建sparkapplication的运行环境(启动sparkcontext),
sparkcontext向资源管理器(可以是Standalone/Mesos或YARN)注册并申请运行Executor资源.
2)资源管理器分配Executor资源并启动Executor,Executor运行情况将随着心跳发送到资源管理器上;
3)SparkContext构建DAG图,将DAG图分解成Stage,并把Taskset发送到Task Scheduler.Executor向
SparkContext申请Task,Task Scheduler将Task发送给Executor运行同时
4)Task在Executor上运行,运行完毕释放所有资源.
 
 
 
 
6.8 面试题
1.请列出spark的调度器,简述调度原理
DAGScheduler TaskScheduler
DAGScheduler
a.对DAG有向无环图进行Stage划分
b.记录哪个RDD或者Stage输出被物化(缓存),通常在一个复杂的shuffle之后,通常物化一下(cache persist),方便之后的计算
c.重新提交shuffle,输出丢失的stage(stage内部计算出错)给TaskScheduler
d.将Taskset传给底层调度器
 
a.TaskSet构建一个TaskSetManager实例管理这个TaskSet的生命周期
b.数据本地性决定每个Task最佳位置
c.提交taskset(一组task)到集群运行并监控
d.推测执行,碰到计算缓慢任务需要放到别的节点上重试
e.重新提交shuffle输出丢失的Stage给DAGScheduler
 
2.rdd的特点
RDD具有数据流模型的特点:自动容错/位置感知性调度和可伸缩性.
RDD允许用户在执行多个查询时显式地将数据缓存在内存中,后续的查询能够重用这些数据,这
极大地提升了查询速度.
 
整套调优方案主要分为开发调优/资源调优/数据倾斜调优/shuffle调优几个部分
 
6.9.1 调优概述
Spark基本开发原则,包括:RDD lineage设计/算子的合理使用/特殊操作的变化等.
 
6.9.2 原则一:避免创建重复的RDD
对同一份数据,只应该创建一个RDD,不能创建多个RDD来代表同一份数据.
 
6.9.3原则二:尽可能复用同一个RDD
对于类似这种多个RDD的数据有重叠后者包含的情况,我们应该尽量复用一个RDD,
这样可以尽可能地减少RDD的数量,从而尽可能减少算子执行的次数.
 
6.9.4 原则三:对多次使用的RDD进行持久化
保证对一个RDD执行多次算子操作时,这个RDD本身仅仅被计算一次.
对多次使用的RDD进行持久化
 
如何选择一种最合适的持久化策略?
默认情况下,性能最高的当然是 MEMORY_ONLY,但前提是你的内存必须足够足够大,可
 
6.9.5 原则四:尽量避免使用shuffle类算子
如果有可能的话,尽量避免使用shuffle类算子.
spark作业运行过程中,最消耗性能的地方就是shuffle过程.shuffle过程,将分布在集群中多个节点上
的同一个key,拉取到同一个节点上,进行聚合或join等操作.比如reduceByKey/join等算子,都会触发shuffle等操作.
 
shuffle过程中,可能会发生大量的磁盘文件读写的IO操作,以及数据的网络传输操作.
批判IO和网络数据传输也是shuffle性能较差的主要原因.
 
在开发过程中,能避免则尽可能避免使用reduceByKey/join/distinct/repartition等会进行shuffle的算子,
尽量使用map类的非shuffle算子.
 
6.9.6 原则五:使用map-side预聚合的shuffle操作
尽量使用可以map-side预聚合的算子
 
 
 
6.9.7 原则六:使用高性能的算子
其他的算子也都有着相应的优化原则
 
使用reduceByKey/aggregateByKey替代groupByKey
使用mapPartitions替代普通map
使用foreachPartitions替代foreach
使用filter之后进行coalesce操作
使用reparationAndSortWithinPartitions替代repartition与sort类操作
 
6.9.8 原则七:广播大变量
在算子函数中使用到外部变量时,默认情况下,spark会将该变量复制多个副本,通过网络传输到task中,
此时每个task都有一个变量副本.
此时建议使用spark的广播功能,对该变量进行广播.
 
6.9.9 原则八:使用Kryo优化序列化性能
在spark中,主要有三个地方涉及到了序列化:
1.在算子函数中使用到外部变量时,该变量会被序列化后进行网络传输
2.将自定义的类型作为RDD的泛型类型时(比如JavaRDD,Student是自定义类型),所有
自定义类型对象,都会进行序列化,因此这种情况下,也要求自定义的类必须实现Serializale接口.
3.使用可序列化的持久化策略时(比如MEMORY_ONLY_SER),spark会将RDD中的每个partition都
序列化成一个的字节数组.
 
6.9.10 原则九:优化数据结构(并不合理)
java中 三种类型比较耗费内存
对象
字符串
集合类型
 
第91页
 
6.10 资源调优
6.10.1 调优概述
资源参数设置的不合理,可能或导致没有充分利用集群资源,作业运行会极其缓慢,
或者设置的资源过大,队列没有足够的资源来提供,进而导致各种异常.
 
6.11 数据资源倾斜
6.11.2 数据倾斜发生时的现象
1.绝大多数task执行的都非常快,但个别task执行极慢.
2.原本能够正常执行的spark作业,某天突然爆出OOM异常,业务代码造成
 
 
6.11.4 如何定位导致数据倾斜的代码
1.某个task执行特别慢的情况
首先要看 数据倾斜发生在第几个stage中
根据stage划分原理,推算出来发生倾斜的那个stage对应代码中的哪一部分,这部分代码中肯定会有一个shuffle类算子.
 
6.11.6 数据倾斜的解决方案
解决方案一:使用Hive ETL预处理数据
方案使用场景:导致数据倾斜的是Hive表,如果该Hive表中的数据本身很不均匀(比如某个key对应了100万数据,其他key才对应了10条数据)
 
解决方案二:过滤少数导致倾斜的key
计算出样本中数据量最大的几个key之后,直接在程序中将那些key给过滤掉.
 
方案三:提高shuffle操作的并行度
方案四:两阶段聚合(局部聚合 + 全局聚合)
方案五:将reduce join转为map join
 
6.12 shuffle调优
6.12.1 调优概述
大多数spark作业的性能主要是消耗在了shuffle环节,因为该环节包含了大量的磁盘IO/序列化/网络数据传输等操作.
 
 
 
 
 

posted @ 2021-03-25 13:53  facebookb  阅读(67)  评论(0)    收藏  举报