SparkCore2

本文详细介绍了SparkCore2的关键概念,包括Application、Driver、Executor、Cluster Manager等,以及它们之间的关系。文章阐述了Spark运行架构,强调了Executor的持久性和多线程特性。同时,讨论了缓存策略,包括cache和persist的区别,以及如何根据需求选择合适的存储级别。此外,还提到了Spark的Lineage和Dependcy,解释了其容错机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Glossary

(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

2.为什么这里是2?

在SparkContext中的textFile方法里的有如下代码,

def wholeTextFiles(
    path: String,
    minPartitions: Int = defaultMinPartitions): RDD[(String, String)] = withScope {
  assertNotStopped()  //而这里的最小值设置的就2

3.梳理术语之关系

(1)Application——> n个 job——>n个 stage——>n个 tasks

(2)partition数目=task数目

4.Spark运行架构图解

(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(一个机架无所谓,多个机架就要注意)

5.Monitor

(1)每一个driver program都有一个web ui的默认端口是4040.,它能展示你的task、stage和executor的一些信息,具体的可以看看官网的http://spark.apache.org/docs/latest/monitoring.html

6.executor中的Cache用处体现在哪呢?

(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 = 7

面试题:cache和persist有什么区别呢?

def 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.

7.缓存的选取策略

Storage LevelMeaning
MEMORY_ONLYStore RDD as deserialized Java objects in the JVM. If the RDD does not fit in memory, some partitions will not be cached and will be recomputed on the fly each time they're needed. This is the default level.
MEMORY_AND_DISKStore RDD as deserialized Java objects in the JVM. If the RDD does not fit in memory, store the partitions that don't fit on disk, and read them from there when they're needed.
MEMORY_ONLY_SER 
(Java and Scala)
Store RDD as serialized Java objects (one byte array per partition). This is generally more space-efficient than deserialized objects, especially when using a fast serializer, but more CPU-intensive to read.
MEMORY_AND_DISK_SER 
(Java and Scala)
Similar to MEMORY_ONLY_SER, but spill partitions that don't fit in memory to disk instead of recomputing them on the fly each time they're needed.
DISK_ONLYStore the RDD partitions only on disk.
MEMORY_ONLY_2, MEMORY_AND_DISK_2, etc.Same as the levels above, but replicate each partition on two cluster nodes.
OFF_HEAP (experimental)Similar to MEMORY_ONLY_SER, but store the data in off-heap memory. This requires off-heap memory to be enabled.

缓存的选取就是不同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.

8.Lineage和Dependcy

(1)Lineage:这个就是体现五大特性的弹性和容错性,他具有血缘关系,就是一个经过一系列的变化,RDD转换之后,当中间 的RDD的parturition丢时,他自动能重新计算,找回。

(2)Dependcy(面试必问)

1)上面左图就是窄依赖:一个父RDD的partition最多被RDD的某个partition使用一次。

2)join是个特殊的,如果它是co-partitioned(这是个啥呢?)的就是窄依赖,如果不是那他就是宽依赖。

3)上面的右图就是宽依赖:一个父RDD的partition会被子类使用多次。

4)从上面可以看出在宽依赖的计算中,数据丢失,恢复是很慢的,所以尽量避免使用宽依赖来计算。但是在解决数据倾斜的时候,很多时候要加一层宽以来,使得数据 更为打散。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值