1.11 Spark Core & SQL

Spark是一个内存计算框架,它的核心原理是将数据存储在内存中进行计算,以实现高速的数据处理。

Spark是一个快速、通用的大数据处理框架,它使用了分布式计算模型来处理大规模数据集。下面是Spark的工作原理和Shuffle过程的简要说明:

工作原理:

Spark将数据集划分为多个分区,并在集群中的多个节点上并行处理这些分区。
Spark的核心抽象是弹性分布式数据集(Resilient Distributed Dataset,简称RDD),它是一个可并行操作的不可变分布式对象。
RDD可以从外部数据源创建,也可以通过转换操作(如map、filter、reduce等)从现有RDD派生而来。
Spark的计算过程中,会将RDD划分为多个阶段(stage),每个阶段包含一系列的任务(task),这些任务可以在不同的节点上并行执行。
Shuffle过程:
在Spark中,shuffle是指将数据重新分区并重新组织,以便进行后续的操作,如聚合、排序等。具体步骤如下:

Map阶段:将输入数据划分为若干个数据块,每个数据块由一个Map任务处理。Map任务将输入数据转换为键值对,并将键值对写入内存或磁盘。
Partition阶段:将Map任务的输出数据按照键进行分区,每个分区对应一个分区器。分区器决定了数据如何分布到不同的分区。
Sort阶段:在每个分区内,对键值对进行排序,以便后续的合并操作。
Combine阶段:将相同键的键值对进行合并,减少数据传输量。
Shuffle阶段:将每个分区的数据发送到对应的节点,以便进行后续的操作,如聚合、排序等。
spark的shufflle过程有几种
在Apache Spark中,Shuffle过程有两种常见的实现方式:Sort-based Shuffle和Hash-based Shuffle。

Sort-based Shuffle: Sort-based Shuffle是Spark早期版本中使用的一种Shuffle实现方式。在Sort-based Shuffle中,Map阶段的输出会被写入磁盘,并根据键进行排序。然后,Reduce阶段会从磁盘读取并合并相同键的数据。这种方式的优点是可以保证数据的全局排序,适用于需要全局排序的场景。然而,Sort-based Shuffle的缺点是需要大量的磁盘读写操作,对于大规模数据集和大规模集群来说,性能可能较低。

Hash-based Shuffle: Hash-based Shuffle是Spark较新版本中引入的一种Shuffle实现方式。在Hash-based Shuffle中,Map阶段的输出会根据键的哈希值进行分区,并将数据写入磁盘的不同文件中。Reduce阶段会根据键的哈希值读取相应的文件,并将相同键的数据合并。这种方式避免了Sort-based Shuffle中的全局排序和大量的磁盘读写操作,因此在性能上通常比Sort-based Shuffle更高效。

需要注意的是,Spark的Shuffle过程的具体实现方式可能会因版本和配置而有所不同。此外,Spark还提供了一些优化策略,如合并映射端输出(Map端聚合)、局部聚合(Combiner)和排序等,以减少Shuffle过程的数据量和开销,提高性能。

总结起来,Spark的Shuffle过程主要有Sort-based Shuffle和Hash-based Shuffle两种实现方式。选择合适的Shuffle方式取决于具体的场景和需求。

Spark的工作流程大致分为以下几个步骤:

应用程序的编写:用户使用Spark API(如Spark Core、Spark SQL等)编写应用程序,描述需要执行的计算逻辑。

作业划分:应用程序被划分为一系列的有向无环图(DAG)的任务。每个任务代表了一项具体的计算操作。

任务分配:Spark将任务调度到集群中的各个计算节点上执行。每个计算节点上都有一个Executor,负责执行分配给它的任务。

任务执行:每个Executor在自己的计算节点上读取数据、执行计算操作,然后将结果返回给驱动程序或下一个任务。

数据共享:Spark使用共享变量来提高计算效率。共享变量分为广播变量(Broadcast Variables)和累加器(Accumulators)。广播变量用于在计算节点之间共享可读数据,减少网络传输成本。累加器用于在计算过程中进行聚合操作,比如计数、总和等。

1.11.1 Spark有几种部署方式?请分别简要论述
1)Local:运行在一台机器上,通常是练手或者测试环境。
2)Standalone:构建一个基于Mster+Slaves的资源调度集群,Spark任务提交给Master运行。是Spark自身的一个调度系统。
3)Yarn: Spark客户端直接连接Yarn,不需要额外构建Spark集群。有yarn-client和yarn-cluster两种模式,主要区别在于:Driver程序的运行节点。
4)Mesos:国内大环境比较少用。
1.11.2 Spark任务使用什么进行提交,JavaEE界面还是脚本
Shell 脚本。
1.11.3 Spark提交作业参数(重点)
参考答案:
https://blog.csdn.net/gamer_gyt/article/details/79135118
1)在提交任务时的几个重要参数
executor-cores —— 每个executor使用的内核数,默认为1,官方建议2-5个,我们企业是4个
num-executors —— 启动executors的数量,默认为2
executor-memory —— executor内存大小,默认1G
driver-cores —— driver使用内核数,默认为1
driver-memory —— driver内存大小,默认512M
2)边给一个提交任务的样式
spark-submit
–master local[5]
–driver-cores 2
–driver-memory 8g
–executor-cores 4
–num-executors 10
–executor-memory 8g
–class PackageName.ClassName XXXX.jar
–name “Spark Job Name”
InputPath
OutputPath
1.11.4 简述Spark的架构与作业提交流程
spark架构主要由以下组件构成:

Application: 建立在 Spark上的用户程序,包括 Driver代码和运行在集群各节点 Executor中的代码
Driver program: 驱动程序, Application中的main函数并创建 SparkContext
Cluster Manager : 在集群(Standalone、Mesos、YARN)上获取资源的外部服务
Worker Node: 集群中任何可以运行 Application代码的节点
Executor : 某个 Application运行在 worker节点上的一个进程
Task: 被送到某个 Executor上的工作单元
Job : 包含多个 Task 组成的并行计算,往往由 Spark Action算子 触发生成,一个 Application中往往会产生多个 Job
Stage: 每个Job会被拆分成多组 Task,作为一个 TaskSet,其名称为 Stage

SparkContext可以连接不同类型的Cluster Manager(Standalone、YARN、Mesos),连接后,获得集群节点上的Executor
一个Worker节点默认一个Executor,可通过SPARK_WORKER_INSTANCES调整
每个应用获取自己的Executor
每个Task处理一个RDD分区

作业提交流程
1、client提交任务到RM.
2、RM启动AM.
3、AM启动Driver线程, 并向RM申请资源.
4、RM返回可用资源列表.
5、AM通过nmClient启动Container, 并且启动ExecutorBackend后台进程.
6、Executor反向注册给Driver
7、Executor启动任务

sparkSQL和hive的异同点
相同点:

1- 都是分布式计算的引擎
2- 都可以处理大规模的数据
3- 都可以简历Yarn集群之上运行

不同点

1- Spark SQL是基于内存计算, 而 HIVE SQL是基于磁盘进行计算的
2- Spark SQL没有元数据管理服务(自己维护), 而HIVE SQL是有metastore的元数据管理服务的
3- Spark SQL底层执行Spark RDD程序, 而 HIVE SQL底层执行是MR
4- Spark SQL可以编写SQL 也可以编写代码, 但是HIVE SQL 仅能编写SQL语句
![在这里插入图片描述](https://img-blog.csdnimg.cn/130a3ed7e4034e26abe310bdc134e43d.png

Spark算⼦有两类,分别是transformation算⼦和action算⼦。
Transformation算⼦有:map,mapPartitions,groupBy,filter,distinct,repartition,union,
reduceByKey,groupByKey,Join,aggregateByKey等。
Action算⼦有:reduce,collect,count,save,countByKey,aggregate,take

1.11.11 Spark常用算子reduceByKey与groupByKey的区别,哪一种更具优势?(重点)
reduceByKey:按照key进行聚合,在shuffle之前有combine(预聚合)操作,返回结果是RDD[k,v]。
groupByKey:按照key进行分组,直接进行shuffle。
开发指导:reduceByKey比groupByKey,建议使用。但是需要注意是否会影响业务逻辑。
1.11.12 Repartition和Coalesce关系与区别
1)关系:
两者都是用来改变RDD的partition数量的,repartition底层调用的就是coalesce方法:coalesce(numPartitions, shuffle = true)
2)区别:
repartition一定会发生shuffle,coalesce根据传入的参数来判断是否发生shuffle
一般情况下增大rdd的partition数量使用repartition,减少partition数量时使用coalesce
1.11.13 分别简述Spark中的缓存机制(cache和persist)与checkpoint机制,并指出两者的区别与联系
都是做RDD持久化的
cache:内存,不会截断血缘关系,使用计算过程中的数据缓存。
checkpoint:磁盘,截断血缘关系,在ck之前必须没有任何任务提交才会生效,ck过程会额外提交一次任务。
1.11.14 简述Spark中共享变量(广播变量和累加器)的基本原理与用途。(重点)
累加器(accumulator)是Spark中提供的一种分布式的变量机制,其原理类似于mapreduce,即分布式的改变,然后聚合这些改变。累加器的一个常见用途是在调试时对作业执行过程中的事件进行计数。而广播变量用来高效分发较大的对象。
共享变量出现的原因:
通常在向 Spark 传递函数时,比如使用 map() 函数或者用 filter() 传条件时,可以使用驱动器程序中定义的变量,但是集群中运行的每个任务都会得到这些变量的一份新的副本,更新这些副本的值也不会影响驱动器中的对应变量。
Spark的两个共享变量,累加器与广播变量,分别为结果聚合与广播这两种常见的通信模式突破了这一限制。
1.11.15 当Spark涉及到数据库的操作时,如何减少Spark运行中的数据库连接数?
使用foreachPartition代替foreach,在foreachPartition内获取数据库的连接。
1.11.16 如何使用Spark实现TopN的获取(描述思路或使用伪代码)(重点)
方法1:
(1)按照key对数据进行聚合(groupByKey)
(2)将value转换为数组,利用scala的sortBy或者sortWith进行排序(mapValues)数据量太大,会OOM。
方法2:
(1)取出所有的key
(2)对key进行迭代,每次取出一个key利用spark的排序算子进行排序
方法3:
(1)自定义分区器,按照key进行分区,使不同的key进到不同的分区
(2)对每个分区运用spark的排序算子进行排序
1.11.17 京东:调优之前与调优之后性能的详细对比(例如调整map个数,map个数之前多少、之后多少,有什么提升)
这里举个例子。比如我们有几百个文件,会有几百个map出现,读取之后进行join操作,会非常的慢。这个时候我们可以进行coalesce操作,比如240个map,我们合成60个map,也就是窄依赖。这样再shuffle,过程产生的文件数会大大减少。提高join的时间性能。
1.11.18 简述SparkSQL中RDD、DataFrame、DataSet三者的区别与联系? (笔试重点)
1)RDD
优点:
编译时类型安全
编译时就能检查出类型错误
面向对象的编程风格
直接通过类名点的方式来操作数据
缺点:
序列化和反序列化的性能开销
无论是集群间的通信, 还是IO操作都需要对对象的结构和数据进行序列化和反序列化。
GC的性能开销,频繁的创建和销毁对象, 势必会增加GC
2)DataFrame
DataFrame引入了schema和off-heap
schema : RDD每一行的数据, 结构都是一样的,这个结构就存储在schema中。 Spark通过schema就能够读懂数据, 因此在通信和IO时就只需要序列化和反序列化数据, 而结构的部分就可以省略了。
3)DataSet
DataSet结合了RDD和DataFrame的优点,并带来的一个新的概念Encoder。
当序列化数据时,Encoder产生字节码与off-heap进行交互,能够达到按需访问数据的效果,而不用反序列化整个对象。Spark还没有提供自定义Encoder的API,但是未来会加入。
三者之间的转换:
在这里插入图片描述
DataFrame 和 DataSet 的区别:前者是 row 类型
RDD 和 DataSet 及 DataSet 的区别:前者没有字段和表信息

1.11.19 append和overwrite的区别
append在原有分区上进行追加,overwrite在原有分区上进行全量刷新
1.11.20 coalesce和repartition的区别
coalesce和repartition都用于改变分区,coalesce用于缩小分区且不会进行shuffle,repartition用于增大分区(提供并行度)会进行shuffle,在spark中减少文件个数会使用coalesce来减少分区来到这个目的。但是如果数据量过大,分区数过少会出现OOM所以coalesce缩小分区个数也需合理
1.11.21 cache缓存级别
DataFrame的cache默认采用 MEMORY_AND_DISK 这和RDD 的默认方式不一样RDD cache 默认采用MEMORY_ONLY
1.11.22 释放缓存和缓存
缓存:(1)dataFrame.cache (2)sparkSession.catalog.cacheTable(“tableName”)
释放缓存:(1)dataFrame.unpersist (2)sparkSession.catalog.uncacheTable(“tableName”)
1.11.23 Spark Shuffle默认并行度
参数spark.sql.shuffle.partitions 决定 默认并行度200
1.11.24 kryo序列化
kryo序列化比java序列化更快更紧凑,但spark默认的序列化是java序列化并不是spark序列化,因为spark并不支持所有序列化类型,而且每次使用都必须进行注册。注册只针对于RDD。在DataFrames和DataSet当中自动实现了kryo序列化。
1.11.25 创建临时表和全局临时表
DataFrame.createTempView() 创建普通临时表
DataFrame.createGlobalTempView() DataFrame.createOrReplaceTempView() 创建全局临时表
1.11.26 BroadCast join 广播join
原理:先将小表数据查询出来聚合到driver端,再广播到各个executor端,使表与表join时
进行本地join,避免进行网络传输产生shuffle。
使用场景:大表join小表 只能广播小表
1.11.27 控制Spark reduce缓存 调优shuffle
spark.reducer.maxSizeInFilght 此参数为reduce task能够拉取多少数据量的一个参数默认48MB,当集群资源足够时,增大此参数可减少reduce拉取数据量的次数,从而达到优化shuffle的效果,一般调大为96MB,资源够大可继续往上跳。

spark.shuffle.file.buffer 此参数为每个shuffle文件输出流的内存缓冲区大小,调大此参数可以减少在创建shuffle文件时进行磁盘搜索和系统调用的次数,默认参数为32k 一般调大为64k。
1.11.28 注册UDF函数
SparkSession.udf.register 方法进行注册
1.11.29 SparkSQL中join操作与left join操作的区别?
join和sql中的inner join操作很相似,返回结果是前面一个集合和后面一个集合中匹配成功的,过滤掉关联不上的。
leftJoin类似于SQL中的左外关联left outer join,返回结果以第一个RDD为主,关联不上的记录为空。
部分场景下可以使用left semi join替代left join:
因为 left semi join 是 in(keySet) 的关系,遇到右表重复记录,左表会跳过,性能更高,而 left join 则会一直遍历。但是left semi join 中最后 select 的结果中只许出现左表中的列名,因为右表只有 join key 参与关联计算了

1.13 数据倾斜
公司一:总用户量1000万,5台64G内存的服务器。
公司二:总用户量10亿,1000台64G内存的服务器。
1.公司一的数据分析师在做join的时候发生了数据倾斜,会导致有几百万用户的相关数据集中到了一台服务器上,几百万的用户数据,说大也不大,正常字段量的数据的话64G还是能轻松处理掉的。
2.公司二的数据分析师在做join的时候也发生了数据倾斜,可能会有1个亿的用户相关数据集中到了一台机器上了(相信我,这很常见)。这时候一台机器就很难搞定了,最后会很难算出结果。
1.13.1 数据倾斜表现
1)hadoop中的数据倾斜表现:
有一个多几个Reduce卡住,卡在99.99%,一直不能结束。
各种container报错OOM
异常的Reducer读写的数据量极大,至少远远超过其它正常的Reducer
伴随着数据倾斜,会出现任务被kill等各种诡异的表现。
2)hive中数据倾斜
一般都发生在Sql中group by和join on上,而且和数据逻辑绑定比较深。
3)Spark中的数据倾斜
Spark中的数据倾斜,包括Spark Streaming和Spark Sql,表现主要有下面几种:
Executor lost,OOM,Shuffle过程出错;
Driver OOM;
单个Executor执行时间特别久,整体任务卡在某个阶段不能结束;
正常运行的任务突然失败;
1.13.2 数据倾斜产生原因
我们以Spark和Hive的使用场景为例。
他们在做数据运算的时候会涉及到,count distinct、group by、join on等操作,这些都会触发Shuffle动作。一旦触发Shuffle,所有相同key的值就会被拉到一个或几个Reducer节点上,容易发生单点计算问题,导致数据倾斜。
一般来说,数据倾斜原因有以下几方面:
1)key分布不均匀;

2)建表时考虑不周
我们举一个例子,就说数据默认值的设计吧,假设我们有两张表:
user(用户信息表):userid,register_ip
ip(IP表):ip,register_user_cnt
这可能是两个不同的人开发的数据表。如果我们的数据规范不太完善的话,会出现一种情况:
user表中的register_ip字段,如果获取不到这个信息,我们默认为null;
但是在ip表中,我们在统计这个值的时候,为了方便,我们把获取不到ip的用户,统一认为他们的ip为0。
两边其实都没有错的,但是一旦我们做关联了,这个任务会在做关联的阶段,也就是sql的on的阶段卡死。
3)业务数据激增
比如订单场景,我们在某一天在北京和上海两个城市多了强力的推广,结果可能是这两个城市的订单量增长了10000%,其余城市的数据量不变。
然后我们要统计不同城市的订单情况,这样,一做group操作,可能直接就数据倾斜了。
1.13.3 解决数据倾斜思路
很多数据倾斜的问题,都可以用和平台无关的方式解决,比如更好的数据预处理,异常值的过滤等。因此,解决数据倾斜的重点在于对数据设计和业务的理解,这两个搞清楚了,数据倾斜就解决了大部分了。
1)业务逻辑
我们从业务逻辑的层面上来优化数据倾斜,比如上面的两个城市做推广活动导致那两个城市数据量激增的例子,我们可以单独对这两个城市来做count,单独做时可用两次MR,第一次打散计算,第二次再最终聚合计算。完成后和其它城市做整合。
2)程序层面
比如说在Hive中,经常遇到count(distinct)操作,这样会导致最终只有一个Reduce任务。
我们可以先group by,再在外面包一层count,就可以了。比如计算按用户名去重后的总用户量:
(1)优化前 只有一个reduce,先去重再count负担比较大:
select name,count(distinct name)from user;
(2)优化后
// 设置该任务的每个job的reducer个数为3个。Hive默认-1,自动推断。
set mapred.reduce.tasks=3;
// 启动两个job,一个负责子查询(可以有多个reduce),另一个负责count(1):
select count(1) from (select name from user group by name) tmp;
3)调参方面
Hadoop和Spark都自带了很多的参数和机制来调节数据倾斜,合理利用它们就能解决大部分问题。
4)从业务和数据上解决数据倾斜
很多数据倾斜都是在数据的使用上造成的。我们举几个场景,并分别给出它们的解决方案。
有损的方法:找到异常数据,比如ip为0的数据,过滤掉
无损的方法:对分布不均匀的数据,单独计算
先对key做一层hash,先将数据随机打散让它的并行度变大,再汇集
数据预处理
1.13.4 定位导致数据倾斜代码
Spark数据倾斜只会发生在shuffle过程中。
这里给大家罗列一些常用的并且可能会触发shuffle操作的算子:distinct、groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartition等。
出现数据倾斜时,可能就是你的代码中使用了这些算子中的某一个所导致的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一凡888

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值