Spark 知识点

spark是什么?有什么?

spark是一种基于内存的快速、通用、可扩展的大数据分析引擎。
sparkcore :实现了spark基本功能,包括任务调度、内存管理、错误恢复、与存储系统交互。还包括rdd的api定义。
sparkSQL:用来处理结构化数据的程序包。通过它,我们可以用SQL或HQL查询数据。支持的数据源;hive表、JSON Parquet
sparkstreaming:对于实时数据进行流式计算的组件。与sparkcore中的rdd API高度对应。

RDD:弹性分布式数据集

以我的理解来讲RDD可以看成一个分布式对象集合。它本质上是一个只读的分区记录集合。每个RDD可以分成多个分区,每个分区就是一个数据集片段。一个RDD的不同分区可以保存到集群中的不同节点上,从而可以在集群中的不同节点上进行并行计算。
只读:不能修改,只能通过转换操作生成新的 RDD。
分布式:可以分布在多台机器上进行并行处理。
弹性:计算过程中内存不够时它会和磁盘进行数据交换。
基于内存:可以全部或部分缓存在内存中,在多次计算间重用。

spark运行原理:

1、spark通过sparkcontext向Clustermanager(资源管理器)申请所需执行的资源(cpu、内存等)
2、Clustermanager分配应用程序执行所需的资源,在worker节点上创建Executor
(sparkcontext构建成DAG图,DAG scheduler将DAG图分解成stage,stage发送给Taskscheduler,executor向sparkcontext申请Task,taskScheduler将应用程序代码发给executor运行)
3、SparkContext 将程序代码(jar包或者python文件)和task任务发送给Executor执行,并收集结果给Driver。

spark任务划分:

每个 worker 节点可以起一个或多个 Executor。
一个executor可以并行执行多个task
一个executor的核心数由 spark-submit的executor-cores参数指定。
每个 Executor 的每个 core 一次只能执行一个 Task。( 这里的 core 是虚拟的 core 而不是机器的物理 CPU 核,可以理解为就是 Executor 的一个工作线程。)
每个 Task 执行的结果就是生成了目标 RDD 的一个 partiton
同时并行执行的task最大数值=executor数目*(每个executor核数/每个task占用核心数)

Spark中RDD的高效与DAG图有着莫大的关系,在DAG调度中需要对计算过程划分stage,而划分依据就是RDD之间的依赖关系。
一个动作算子就产生一个job。Job由一个或多个stage(调度阶段)组成的一次计算作业 包含多个Task组成的并行计算
一个宽依赖就划分一个stage。一个stage创建一个TaskSet
一个TaskSet由多个task组成 每个task都是由每个Rdd分区创建

spark宽依赖和窄依赖:

stage划分的依据就是宽依赖
窄依赖是指1个父RDD分区对应1个子RDD的分区。(map,filter,union)
宽依赖是指1个父RDD分区对应多个子RDD分区。(groupByKey,reduceByKey,sortByKey,未经协同划分的join)

spark转换算子和行动算子:

转换算子:map flatMap mapPartitions union filter reduceByKey aggregateByKey
行动算子:1)reduce 2)collect: 3)first 4)take 5)aggregate 6)countByKey 7)foreach 8)saveAsTextFile

reduceByKey(func)和groupByKey()的区别:

reduceByKey()对于每个key对应的多个value进行了merge操作,最重要的是它能够先在本地进行merge操作。merge可以通过func自定义。
groupByKey()也是对每个key对应的多个value进行操作,但是只是汇总生成一个sequence,本身不能自定义函数,只能通过额外通过map(func)来实现。

spark数据倾斜:

出现数据倾斜的原因:

基本只可能是因为发生了shuffle操作,在shuffle的过程中,出现了数据倾斜的问题。因为某个,或者某些key对应的数据,远远的高于其他的key。

工作时我的应对:

1、在自己的程序里面找找,哪些地方用了会产生shuffle的算子,groupByKey、countByKey、reduceByKey、join
2、看log
log一般会报你的哪一行代码,导致了OOM异常;或者呢,看log,看看是执行到了第几个stage。
哪一个stage,task特别慢,就能够自己用肉眼去对你的spark代码进行stage的划分,就能够通过stage定位到你的代码,哪里发生了数据倾斜。

解决方案:

一、如果我们判断那少数几个数据量特别多的key,对作业的执行和计算结果不是特别重要的话,那么干脆就直接过滤掉那少数几个key。
二、提高shuffle操作的并行度 ----对于有shuffle的算子,通过设置一些参数增加shuffle read task的数量
比如reduceByKey(1000),该参数就设置了这个shuffle算子执行时shuffle read task的数量。对于Spark SQL中的shuffle类语句,比如group by、join等,需要设置一个参数,即spark.sql.shuffle.partitions,该参数代表了shuffle read task的并行度,该值默认是200,对于很多场景来说都有点过小。
三、对于数据量特别多的key,我们将原本相同的key通过附加随机前缀的方式,变成多个不同的key,就可以让原本被一个task处理的数据分散到多个task上去做局部聚合,进而解决单个task处理数据量过多的问题。接着去除掉随机前缀,再次进行全局聚合,就可以得到最终的结果。

spark优化:

尽可能复用同一个RDD 对多次使用的RDD进行持久化
尽量避免使用shuffle类算子
先filter在join 减少shuffle的数据量
使用map-side预聚合的shuffle操作
使用高性能的算子(使用reduceByKey/aggregateByKey替代groupByKey)(使用mapPartitions替代普通map)(broadcast join和普通join)

spark shuffle调优

参数调优
spark.shuffle.file.buffer 如果作业可用的内存资源较为充足的话,可以适当增加这个参数的大小(比如64k),从而减少shuffle write过程中溢写磁盘文件的次数,也就可以减少磁盘IO次数,进而提升性能。在实践中发现,合理调节该参数,性能会有1%~5%的提升。
spark.reducer.maxSizeInFlight ,可以适当增加这个参数的大小(比如96m),从而减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能
spark.shuffle.io.retryWait 建议加大每次重试拉取数据的等待间隔时长(比如60s),以增加shuffle操作的稳定性

updateStateByKey: 有状态的转化操作

在流式计算中通常会有状态计算的需求,即当前计算结果不仅依赖于目前收到数据还需要之前结果进行合并计算的场景,由于sparkstreaming的mini-batch机制,必须将之前的状态结果存储在RDD中并在下一次batch计算时将其取出进行合并。这就是updateStateByKey方法的用处。

spark几种部署模式

local:常用于本地开发测试
standalone:一个有Master和Slave构成的集群
on yarn:运行在yarn资源管理器框架之上,由yarn负责资源管理,spark负责任务调度和计算。有yarn-client模式和yarn-cluster模式。 yarn-cluster driver运行在集群子节点,具有容错功能,适用于生产环境。yarn-client Driver运行在客户端,适用于交互、调式,希望立即看到app的输出。
mesos:运行在mesos资源管理器框架上,由mesos负责资源管理,spark负责任务调度和计算。

spark-submit 提交作业参数和过程

作业参数

–master spark:指定要连接的集群master
–executor-memory
–driver-memory —— driver内存大小,默认512M
–total-executor-cores 每个executor使用的内核数,默认为1,官方建议2-5个,我们企业是4个
–num-executors —— 启动executors的数量,默认为2

过程:

使用spark-submit 提交一个spark作业之后,这个作业就会启动一个对应的Driver进程。Driver进程就是开始执行spark程序的那个Main函数。然后向clustermanager申请资源,Clustermanager分配应用程序执行所需的资源,在worker节点上创建Executor。Driver进程会将我们编写的spark作业代码分拆为多个stage,每个stage执行一部分代码片段,并为每个stage创建一批task,然后将这些task分配到各个excutor进程中执行。一个stage中的task都执行完毕之后,会在各个节点本地的磁盘文件中写入中间结果,然后driver就会调度运行下一个stage。下一个stage的task的输入数据就是上一个stage输出的中间结果,如此循环往复,直到将我们编写的代码逻辑全部执行完,并且计算完所有的数据。

spark wordcount:

sc.textFile(“input”).flatMap(.split(" ")).map((,1)).reduceByKey(+).collect()

sparkstreaming wordcount

val sparkconf = new SparkConf().setMaster(“local[*]”).setAppName(“WC”)
val ssc = new StreamingContext(sparkconf,Seconds(3))
val linesword = new socketTextStream(“hadoop101”,9999)
val wc = linesword.flatMap(.split(" ")).map((,1)).reduceByKey(+).print()
ssc.start()
ssc.awaitTermination()
nc -lk 9999

简述repartition与coalesce的区别

coalesce重新分区,可以选择是否进行shuffle过程。由参数shuffle: Boolean = false/true决定
repartition实际上是调用的coalesce,默认是进行shuffle的

map、mappartition与flatmap差异

map是对rdd中的每一个元素进行操作;
mapPartitions则是对rdd中的每个分区的迭代器进行操作,可能会导致内存溢出
flatmap 每一个输入的元素可以被映射为0或多个输出元素(所以func应该返回一个序列,而不是单一元素)
foreach 没有返回值。

cache、pesist和checkpoint的区别

1)cache和persist都是用于将一个RDD进行缓存的,这样在之后使用的过程中就不需要重新计算了,可以大大节省程序运行时间;也都是懒执行 需要action算子触发
2) cache只有一个默认的缓存级别MEMORY_ONLY ,cache调用了persist,而persist可以根据情况设置其它的缓存级别;
3)rdd 支持checkpoint将数据保存到持久化的存储中,从而切断了之前的血缘关系,checkpoint后的rdd不需要知道它的父rdds了,它可以从checkpoint处拿到数据。在 ck 之前必须没有任何任务提交才会生效,ck 过程会额外提交一次任务。

spark streaming接收Kafka数据两种方式:基于Receiver的接收方式和直接接收的方式。

区别:

Receiver是使用Kafka的高层次Consumer API来实现的。receiver从Kafka中获取的数据都是存储在Spark Executor的内存中的,然后Spark Streaming启动的job会去处理那些数据。
direct 这种方式会周期性地查询Kafka,来获得每个topic+partition的最新的offset,从而定义每个batch的offset的范围。当处理数据的job启动时,就会使用Kafka的简单consumer api来获取Kafka指定offset范围的数据。

使用direct:

1、简化并行读取:如果要读取多个partition,不需要创建多个输入DStream然后对它们进行union操作。Spark会创建跟Kafka partition一样多的RDD partition,并且会并行从Kafka中读取数据。所以在Kafka partition和RDD partition之间,有一个一对一的映射关系。
2、高性能:如果要保证零数据丢失,在基于receiver的方式中,需要开启WAL机制。这种方式其实效率低下,因为数据实际上被复制了两份,Kafka自己本身就有高可靠的机制,会对数据复制一份,而这里又会复制一份到WAL中。而基于direct的方式,不依赖Receiver,不需要开启WAL机制,只要Kafka中作了数据的复制,那么就可以通过Kafka的副本进行恢复。

spark中的共享变量

累加器---->计数器 sc.accumulator(0)

在spark应用程序中,我们经常会有这样的需求,如异常监控,调试,记录符合某特性的数据的数目,这种需求都需要用到计数器,当这个变量被声明为累加器后,该变量就会有分布式计数的功能。其原理类似于mapreduce,即分布式的改变,然后聚合这些改变。

广播变量 broadcast

如果executor端用到了Driver的变量,如果不使用广播变量在Executor有多少task就有多少Driver端的变量副本。
如果Executor端用到了Driver的变量,如果使用广播变量在每个Executor中只有一份Driver端的变量副本。这个executor启动的task会共享这个变量,节省了通信的成本和服务器的资源。

共享变量出现的原因:

通常在向 Spark 传递函数时,比如使用 map() 函数或者用 filter() 传条件时,可以使用驱动器程序中定义的变量,但是集群中运行的每个任务都会得到这些变量的一份新的副本,更新这些副本的值也不会影响驱动器中的对应变量。

RDD中 df 和 ds 的区别

DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格。DataFrame与RDD的主要区别在于,前者带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。
DataSet是分布式数据集合。是DataFrame的一个扩展。DataSet是强类型的。

df->ds

case class Person(name: String, age: Long) 样例类
df.as[Person]

ds->df

case class Person(name: String, age: Long)
val ds = Seq(Person(“Andy”, 32)).toDS()
val df = ds.toDF

spark并行度设置

增加任务的并行度,充分利用集群机器的计算能力,一般并行度设置为集群CPU总和的2-3倍。
对于reduceByKey等会发生shuffle的操作,就使用并行度最大的父RDD的并行度即可。
可以手动使用textFile()、parallelize()等方法的第二个参数来设置并行度;也可以使用spark.default.parallelism参数,来设置统一的并行度。Spark官方的推荐是,给集群中的每个cpu core设置2~3个task。

join操作优化经验?

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

Spark与Hadoop区别与联系

(1)Spark对标于Hadoop中的计算模块MR,但是速度和效率比MR要快得多;
(2)Spark没有提供文件管理系统,所以,它必须和其他的分布式文件系统进行集成才能运作,它只是一个计算分析框架,专门用来对分布式存储的数据进行计算处理,它本身并不能存储数据;
(3)Spark可以使用Hadoop的HDFS或者其他云数据平台进行数据存储,但是一般使用HDFS;
(4)Spark可以使用基于HDFS的HBase数据库,也可以使用HDFS的数据文件,还可以通过jdbc连接使用Mysql数据库数据;Spark可以对数据库数据进行修改删除,而HDFS只能对数据进行追加和全表删除;
(5)Spark数据处理速度秒杀Hadoop中MR;
(6)Spark处理数据的设计模式与MR不一样,Hadoop是从HDFS读取数据,通过MR将中间结果写入HDFS;然后再重新从HDFS读取数据进行MR,再刷写到HDFS,这个过程涉及多次落盘操作,多次磁盘IO,效率并不高;而Spark的设计模式是读取集群中的数据后,在内存中存储和运算,直到全部运算完毕后,再存储到集群中;
(7)Spark是由于Hadoop中MR效率低下而产生的高效率快速计算引擎,批处理速度比MR快近10倍,内存中的数据分析速度比Hadoop快近100倍(源自官网描述);
(8)Spark中RDD一般存放在内存中,如果内存不够存放数据,会同时使用磁盘存储数据;通过RDD之间的血缘连接、数据存入内存中切断血缘关系等机制,可以实现灾难恢复,当数据丢失时可以恢复数据;这一点与Hadoop类似,Hadoop基于磁盘读写,天生数据具备可恢复性;
(9)Spark引进了内存集群计算的概念,可在内存集群计算中将数据集缓存在内存中,以缩短访问延迟,对7的补充;
(10)Spark中通过DAG图可以实现良好的容错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值