(1)Application(应用,创建了一个SparkContext就是一个Application)=1个Driver program + n 个executors
(2)Application jar:表示就是Application的主类。
(3)Driver progrem:就是你的main方法并且创建了SparkContext。这是一个进程
(4)Cluster manager:一个Spark应用程序他是可以跑在不同的集群上的,他就是来指定你的运行模式的。
(5)Deploy mode:区分驱动程序进程在何处运行。在“集群”模式下,框架在集群内部启动驱动程序。在“客户机”模式下,提交者在集群之外启动驱动程序,只要有get way权限,可以在集群外面提交。
(6)Worker node:在standlone(这个就是Spark 集群,HA)模式中的,类似于yarn模式中的nodemanager。
(7)Execuor:一个进程运行一个应用程序在work node,这个进程他能够运行task和保存数据到内存里面或者磁盘,一个appliction有多个executors,不同application之间executor是没关系的,极少有共享的。
(8)task:他是一个工作单元,他会被发送到executor上去,并行执行的。
(9)job:只有出发了Action才有产生jon。
(10)Stage:与shuffer有关系,一个job被切分成很多个tasks的集合,没有遇到shuffer的都是一个stage
在SparkContext中的textFile方法里的有如下代码,
def wholeTextFiles( path: String, minPartitions: Int = defaultMinPartitions): RDD[(String, String)] = withScope { assertNotStopped() //而这里的最小值设置的就2(1)Application——> n个 job——>n个 stage——>n个 tasks
(2)partition数目=task数目
(1)概述:Spark应用程序作为集群上独立的进程集运行,由主程序(main program)(称为驱动程序driver program)中的SparkContext对象协调。 具体来说,为了在集群上运行,SparkContext可以连接到几种类型的集群管理器(cluster manager)(Spark自己的独立集群管理器、Mesos或YARN),这些管理器(manager)可以跨应用程序分配资源。连接之后,Spark在集群中的节点上获取执行器,这些节点是运行计算并为应用程序存储数据的进程。接下来,它将发送您的应用程序代码(由传递给Spa的JAR或Python文件定义)。
(2)There are several useful things to note about this architecture:
1)每个application有他自己的executor进程,它一直保留在哪你的程序中(所以需要spark context.stop释放资源 ),并且是多线程运行tasks,每个applicetion相互隔离这样带来的好处有俩方面,一是scheduling side(每个driver只需要调度自己的task就可以了),二是在executor side(执行方面,task运行在不同的jvm里面的,体现在集群上)。但是,这也意味着你的数据在不同的application上不能共享,除非将他写到外部数据源去(例如:Auxxio)。
2)Spark是不感知底层集群管理器的(cluster manager),就是你在--master这指定就好了。只要它在获得executor进程之后,executor就能直接和集群通信。
3)driver他需要监听executor(俩者是有通信机制的)过来的信息,因为executor可能会挂掉,挂掉之后你需要感知到自动重启。driver要和你的woker node之间网络是要通的
4)因为你的driver要调度task在你的集群之上,因此driver要靠近你的woker node(一个机架无所谓,多个机架就要注意)
(1)每一个driver program都有一个web ui的默认端口是4040.,它能展示你的task、stage和executor的一些信息,具体的可以看看官网的http://spark.apache.org/docs/latest/monitoring.html
(1)概述:park最重要的功能之一是跨操作在内存中持久化(或缓存)数据集。当您持久化(persist)一个RDD时,每个节点将它在内存中计算的任何分区存储起来,并在该数据集(或从该数据集派生的数据集)上的其他操作中重用它们。这使得未来的动作更快(通常超过10倍)。缓存是迭代算法和快速交互使用的关键工具。
(2)例如:cache是一个lazy的和transformation一样, 不触发action不执行。
(3)优化点:缓存的存储策略默认是Memory不是磁盘
job storage
从上面的size大小明显可知,数据缓存之后变大了,如何优化呢?
scala> import org.apache.spark.storage.StorageLevel import org.apache.spark.storage.StorageLevel scala> a.persist(StorageLevel.MEMORY_ONLY_SER) //仅仅只是这一个参数的改变,大小就能变换很大,就是是否反序列化,它也是个lazy的,明显能够看出来以序列化的方式更加省空间,但更耗cpu res7: a.type = file:///root/ruozeinput.txt MapPartitionsRDD[1] at textFile at <console>:24 scala> a.count res8: Long = 7def cache()= persist() :cache调用的就是persist,快捷方式不需要传参
def persist()= persist(StorageLevel.MEMORY_ONLY)//persist空的话就是memory存储级别
StorageLevel:这是一个标识,
class StorageLevel private( private var _useDisk: Boolean, private var _useMemory: Boolean, private var _useOffHeap: Boolean, private var _deserialized: Boolean, private var _replication: Int = 1) val MEMORY_ONLY = new StorageLevel(false, true, false, true) //对应上去,就是下图这个(4)删除缓存的
括号里面表示:是否阻塞在所有的块删除之前。
Whether to block until all blocks are deleted.缓存的选取就是不同menory和cpu之间的权衡(trade-offs),推荐你做如下的选择:
(1)如果你的RDD能够使用默认的缓存级别(MEMORY_ONLY),那就最好用它,他是更高效的cpu使用,RDD操作速度更快。
(2)如果第一种不行,存储级别就用(MEMORY_ONLY_SER),就序列化一http://spark.apache.org/docs/latest/tuning.html,减小存储,并且访问速度一样快。
(3)不要分到磁盘上去,除非计算数据集的函数很昂贵,或者它们过滤了大量数据。否则,重新计算分区可能与从磁盘读取分区一样快。
(4)Use the replicated storage levels if you want fast fault recovery (e.g. if using Spark to serve requests from a web application). All the storage levels provide full fault tolerance by recomputing lost data, but the replicated ones let you continue running tasks on the RDD without waiting to recompute a lost partition.
(1)Lineage:这个就是体现五大特性的弹性和容错性,他具有血缘关系,就是一个经过一系列的变化,RDD转换之后,当中间 的RDD的parturition丢时,他自动能重新计算,找回。
(2)Dependcy(面试必问)
1)上面左图就是窄依赖:一个父RDD的partition最多被RDD的某个partition使用一次。
2)join是个特殊的,如果它是co-partitioned(这是个啥呢?)的就是窄依赖,如果不是那他就是宽依赖。
3)上面的右图就是宽依赖:一个父RDD的partition会被子类使用多次。
4)从上面可以看出在宽依赖的计算中,数据丢失,恢复是很慢的,所以尽量避免使用宽依赖来计算。但是在解决数据倾斜的时候,很多时候要加一层宽以来,使得数据 更为打散。
