XY个人记
Apache Spark是专为大规模数据处理而设计的快速通用的计算引擎 。现在形成一个高速发展应用广泛的生态系统。
Spark,拥有Hadoop MapReduce所具有的优点;但不同于MapReduce的是——Job中间输出结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的MapReduce的算法。
Spark 是在 Scala 语言中实现的,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地操作分布式数据集。
尽管创建 Spark 是为了支持分布式数据集上的迭代作业,但是实际上它是对 Hadoop 的补充,可以在 Hadoop 文件系统中并行运行。通过名为 Mesos 的第三方集群框架可以支持此行为。Spark 由加州大学伯克利分校 AMP 实验室 (Algorithms, Machines, and People Lab) 开发,可用来构建大型的、低延迟的数据分析应用程序。
性能特点
1.Speed(快速)
内存计算下,Spark 比 Hadoop 快100倍。
2.Ease of Use(易用性)
可用多种语言:Java, Scala, Python, R, and SQL
Java开发
好处:对于大数据大型项目来说,涉及到HBase、Hive、Flume等等,有利于整合
坏处:代码量比较大,代码不优雅
scala开发:Spark本身源码就是scala,兼容性好,代码更简洁
3.Generality(通用)
整合:spark sql、spark streaming、MLlib、GraphX
4.Runs Everywhere(在任何平台运行)
Spark runs on Hadoop, Apache Mesos, Kubernetes, standalone, or in the cloud
国内:一般选择在yarn上运行
国外:一般选择Mesos运行
Spark 和 MapReduce 比较
MapReduce | Spark |
数据存储结构:磁盘hdfs文件系统的split | 使用内存构建弹性分布式数据集RDD,对数据进行 运算和cache |
编程范式:Map + Reduce | DAG(有向无环图):Transformation + action |
计算中间数据落磁盘,io及序列化、反序列化代 价大 | 计算中间数据在内存中维护,存取速度是磁盘的 多个数量级 |
Task以进程的方式维护,任务启动就有数秒 | Task以线程的方式维护,对小数据集的读取能达到 亚秒级的延迟 |
Spark的版本差别
Spark1.6
出现Dataset的概念,与DataFrame两个概念
程序的主入口SparkContext(sc)
Spark2.0+
统一了Dataset和DataFrame: type DataFrame = Dataset[Row]
程序的主入口变成SparkSession(spark),用于替换统一HiveContext、SQLContext
累加器API更简单更高性能
spark基本工作原理:分布式 基于内存 迭代式
RDD:spark基本抽象
Resilient(弹性) Distributed(分布式) Dataset(数据集)弹性分布式数据集, 是分布式内存的一个抽象概念,RDD提供了一种高度受限的共享内存模型,即RDD是只读的记录分区的集合,只能通过在其他RDD执行确定的转换操作(如map、join和group by)而创建,然而这些限制使得实现容错的开销很低。
RDD可以抽象的代表一个HDFS文件,RDD是以分区的形式存在,每个分区存在不同的节点上。分区的数据默认放在内存上,如果某个文件的大小超过了它所在节点存储的大小,它会把存放不下的数据存储在当前节点的内存中,会自动进行内存和磁盘的切换。
数据集:内部是一个数据集合
分布式:数据分区存在,并且存放在spark集群的不同的节点上
弹性:
-1. 自动进行内存和磁盘存储的切换(用户只需要关注RDD的计算处理、操作) RDD的分区的数据默认是放在内存上
-2. 基于血统(依赖)的高效容错性 RDD1 经过转换生成 RDD2
-3. DRR的最小单位Task失败,自动重试机制
RDD特点:
RDD里面的数据是不可变的并且分区存在,每次调用RDD的API,会生成新的RDD,对旧的RDD的数据不会发生变化
RDD的五大特性:
* - A list of partitions(分区列表)
* - A function for computing each split(每个分区都有一个计算函数)
* - A list of dependencies on other RDDs (依赖于其他RDD的一个列表)
* - Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
(对于key-value形式的RDD有一个分区器) key-value形式你可以理解为二元组形式的RDD[(String,Int)]
* - Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)
(每个分区都有一个分区位置列表)
RDD 的两种算子
1、Transformation(转换):Transformation 是一个RDD到另一个RDD,延迟执行
2、Ation(执行):是一个RDD到一个结果,立即执行
Transformation具体内容
1、map(func) :
返回一个新的分布式数据集,由每个原元素经过func函数转换后组成。
2、filter(func) :
返回一个新的数据集,由经过func函数后返回值为true的原元素组成 。
3、flatMap(func) :
类似于map,但是每一个输入元素,会被映射为0到多个输出元素(因此,func函数的返回值是一个Seq,而不是单一元素)。
4、sample(withReplacement, frac, seed) :
根据给定的随机种子seed,随机抽样出数量为frac的数据。
5、union(otherDataset) :
返回一个新的数据集,由原数据集和参数联合而成。
6、groupByKey([numTasks]) :
在一个由(K,V)对组成的数据集上调用,返回一个(K,Seq[V])对的数据集。注意:默认情况下,使用8个并行任务进行分组,你可以传入numTask可选参数,根据数据量设置不同数目的Task。
7、reduceByKey(func, [numTasks]) :
在一个(K,V)对的数据集上使用,返回一个(K,V)对的数据集,key相同的值,都被使用指定的reduce函数聚合到一起。和groupbykey类似,任务的个数是可以通过第二个可选参数来配置的。
8、join(otherDataset, [numTasks]) :
在类型为(K,V)和(K,W)类型的数据集上调用,返回一个(K,(V,W))对,每个key中的所有元素都在一起的数据集。
9、groupWith(otherDataset, [numTasks]) :
在类型为(K,V)和(K,W)类型的数据集上调用,返回一个数据集,组成元素为(K, Seq[V], Seq[W]) Tuples。
10、cartesian(otherDataset) :
笛卡尔积。但在数据集T和U上调用时,返回一个(T,U)对的数据集,所有元素交互进行笛卡尔积。
Actions具体内容
1、reduce(func) :
通过函数func聚集数据集中的所有元素。Func函数接受2个参数,返回一个值。这个函数必须是关联性的,确保可以被正确的并发执行。
2、collect() :
在Driver的程序中,以数组的形式,返回数据集的所有元素。这通常会在使用filter或者其它操作后,返回一个足够小的数据子集再使用,直接将整个RDD集Collect返回,很可能会让Driver程序OOM。
3、count() :
返回数据集的元素个数。
4、take(n) :
返回一个数组,由数据集的前n个元素组成。注意,这个操作目前并非在多个节点上,并行执行,而是Driver程序所在机器,单机计算所有的元素内存压力会增大,需要谨慎使用。
5、first() :
返回数据集的第一个元素(类似于take(1))。
6、saveAsTextFile(path) :
将数据集的元素,以textfile的形式,保存到本地文件系统,hdfs或者任何其它hadoop支持的文件系统。Spark将会调用每个元素的toString方法,并将它转换为文件中的一行文本。
7、saveAsSequenceFile(path) :
将数据集的元素,以sequencefile的格式,保存到指定的目录下,本地系统,hdfs或者任何其它hadoop支持的文件系统。RDD的元素必须由key-value对组成,并都实现了Hadoop的Writable接口,或隐式可以转换为Writable(Spark包括了基本类型的转换,例如Int,Double,String等等)。
8、foreach(func) :
在数据集的每一个元素上,运行函数func。这通常用于更新一个累加器变量,或者和外部存储系统做交互。
Spark应用的结构
Driver + Executors
Driver:相当于MapReduce中ApplicationMaster,运行SparkContext上下文、SparkContext进行初始化的地方(JVM)、进行RDD的初始化、Task运行的资源申请、调度的地方。 一般认为就是main运行的地方
Executors:具体的Task运行的地方,一个executor可以运行多个Task任务,一个spark应用可以有多个Executor
进程:
local模式
Driver和Executor运行在同一个进程(SparkSubmit),以线程的方式进行区分的
集群模式(standalone、yarn、mesos)
Driver:
SparkSubmit
Executor:(有几个Executor就会有几个CoarseGrainedExecutorBackend进程)
CoarseGrainedExecutorBackend
spark-shell底层运行的就是spark-submit命令,spark-submit底层运行spark-class
Application(每个应用都有Driver+Executors)一个应用包含多个job
如下图所示:RDD的action类型的API一旦触发就会产生一个job 一个Job里面包含多个Stage
stage0 有shuffle操作就会划分stage
一个Stage里面可以包含多个Task,Task就是最小的运行单位,是在executor处理对应分区数据的线程
1、Application
application(应用)其实就是用spark-submit提交的程序。比方说spark examples中的计算pi的SparkPi。一个application通常包含三部分:从数据源(比方说HDFS)取数据形成RDD,通过RDD的transformation和action进行计算,将结果输出到console或者外部存储(比方说collect收集输出到console)。
2、Driver
Spark中的driver感觉其实和yarn中Application Master的功能相类似。主要完成任务的调度以及和executor和cluster manager进行协调。有client和cluster联众模式。client模式driver在任务提交的机器上运行,而cluster模式会随机选择机器中的一台机器启动driver。从spark官网截图的一张图可以大致了解driver的功能。
3、Job
Spark中的Job和MR中Job不一样不一样。MR中Job主要是Map或者Reduce Job。而Spark的Job其实很好区别,一个action算子就算一个Job,比方说count,first等。
4、Task
Task是Spark中最新的执行单元。RDD一般是带有partitions的,每个partition的在一个executor上的执行可以任务是一个Task。
5、Stage
Stage概念是spark中独有的。一般而言一个Job会切换成一定数量的stage。各个stage之间按照顺序执行。至于stage是怎么切分的,首选得知道spark论文中提到的narrow dependency(窄依赖)和wide dependency( 宽依赖)的概念。其实很好区分,看一下父RDD中的数据是否进入不同的子RDD,如果只进入到一个子RDD则是窄依赖,否则就是宽依赖。宽依赖和窄依赖的边界就是stage的划分点
Stage的切分规则:从后往前,遇到宽依赖就切割stage。
Stage计算模式:pipeline管道计算模式,pipeline只是一种计算思想,模式。
备注:图中几个理解点:
1、Spark的pipeLine的计算模式,相当于执行了一个高阶函数f3(f2(f1(textFile))) !+!+!=3 也就是来一条数据然后计算一条数据,把所有的逻辑走完,然后落地,准确的说一个task处理遗传分区的数据 因为跨过了不同的逻辑的分区。而MapReduce是 1+1=2,2+1=3的模式,也就是计算完落地,然后在计算,然后再落地到磁盘或内存,最后数据是落在计算节点上,按reduce的hash分区落地。所以这也是比Mapreduce快的原因,完全基于内存计算。
2、管道中的数据何时落地:shuffle write的时候,对RDD进行持久化的时候。
3. Stage的task并行度是由stage的最后一个RDD的分区数来决定的 。一般来说,一个partiotion对应一个task,但最后reduce的时候可以手动改变reduce的个数,也就是分区数,即改变了并行度。例如reduceByKey(XXX,3),GroupByKey(4),union由的分区数由前面的相加。
4.、如何提高stage的并行度:reduceBykey(xxx,numpartiotion),join(xxx,numpartiotion)
Client和Cluster两种运行模式的工作流程
在Client模式下,Driver进程会在当前客户端启动,客户端进程一直存在直到应用程序运行结束
工作流程如下:
1.启动master和worker . worker负责整个集群的资源管理,worker负责监控自己的cpu,内存信息并定时向master汇报
2.在client中启动Driver进程,并向master注册
3.master通过rpc与worker进行通信,通知worker启动一个或多个executor进程
4.executor进程向Driver注册,告知Driver自身的信息,包括所在节点的host等
5.Driver对job进行划分stage,并对stage进行更进一步的划分,将一条pipeline中的所有操作封装成一个task,并发送到向自己注册的executor
进程中的task线程中执行
6.应用程序执行完成,Driver进程退出
在cluster模式下,Driver进程将会在集群中的一个worker中启动,而且客户端进程在完成自己提交任务的职责后,就可以退出,而不用等到应用程序执行完毕
工作流程如下:
1.在集群的节点中,启动master , worker进程,worker进程启动成功后,会向Master进行注册。
2.客户端提交任务后,ActorSelection(master的actor引用),然后通过ActorSelection给Master发送注册Driver请求(RequestSubmitDriver)
3.客户端提交任务后,master通知worker节点启动driver进程。(worker的选择是随意的,只要worker有足够的资源即可)
driver进程启动成功后,将向Master返回注册成功信息
4.master通知worker启动executor进程
5.启动成功后的executor进程向driver进行注册
6.Driver对job进行划分stage,并对stage进行更进一步的划分,将一条pipeline中的所有操作封装成一个task,并发送到向自己注册的executor
进程中的task线程中执行
7.所有task执行完毕后,程序结束