纵观 spark 的诞生和发展, spark 有一点做得非常明智:对同类产品的兼容。从大的方面来说,就像 spark 官网的这段话一样: Runs Everywhere: Spark runs on Hadoop, Mesos, standalone, or in the cloud. It can access diverse data sources including HDFS, Cassandra, HBase, and S3.,spark 对 hadoop 系产品的兼容,让 hadoop 系的开发人员可以轻松的从 hadoop 转到 spark;从小的方面来说,spark 对一些细分工具也照顾 [兼容] 得很好,比如说 spark 推出了 dataframe,人家就可以支持 spark dataframe 和 pandas dataframe 的转换。
- 阿里巴巴的三个job任务最大可达到1PB的规模
- 一个集群计算的框架,Spark集群目前最大可以达到8000个节点(tx)
Master与Worker
- master和worker是物理节点;
- 一个集群有多个master节点和多个worker节点
Master(资源调度算法)
- Master在standalone的模式下兼顾Cluster Manger的功能
- TaskScheduler 会通过后台的一个进程,连接 Master,向 Master 注册 Application
Worker
Worker 是指每个工作节点,启动的一个进程,负责管理本节点,jps 可以看到 Worker 进程在运行,对应的概念是 Master 节点
Driver与Executor
driver和executor是进程
Driver
使用Driver这一概念的分布式框架有很多,比如hive,Spark中的Driver即运行Application的main()函数,并且创建SparkContext,创建SparkContext的目的是为了准备Spark应用程序的运行环境,
在Spark中由SparkContext负责与ClusterManager通讯,进行资源的申请,任务的分配和监控等。
Executor
- 每个executor持有一个线程池,每个线程可以执行一个task
- 此外executor还有一个功能就是为应用程序中要求缓存的 RDD 提供内存式存储,RDD 是直接缓存在executor进程内的,因此任务可以在运行时充分利用缓存数据加速运算
当Executor部分运行完毕后,Driver同时负责将SaprkContext关闭,通常SparkContext代表Driver。
Executor 每个 Spark 程序在每个节点上启动的一个进程,专属于一个 Spark 程序,与 Spark 程序有相同的生命周期,负责 Spark 在节点上启动的 Task,管理内存和磁盘。如果一个节点上有多个 Spark 程序,那么相应就会启动多个执行器。所以说一个 Worker 节点可以有多个 Executor 进程。
在Executor端,则不需要借助Py4j,因为Executor端运行的Task逻辑是由Driver发过来的,那是序列化后的字节码,虽然里面可能包含有用户定义的Python函数或Lambda表达式,Py4j并不能实现在Java里调用Python的方法,为了能在Executor端运行用户定义的Python函数或Lambda表达式,则需要为每个Task单独启一个Python进程,通过socket通信方式将Python函数或Lambda表达式发给Python进程执行。语言层面的交互总体流程如下图所示,实线表示方法调用,虚线表示结果返回。
SparkContext-Scheduler
DAGScheduler
TaskScheduler
Application与Job与Stage与Task
以下引用一张很棒的示意图:
Job
通过Action函数划分(应用程序中的每个acion操作(如collect、count、saves、reduce)都会创建成一个job)
Stage
上图是一个job分成了三个stage
通过Shuffle划分(每个job又会根据是否需要数据混排生成一个或多个stage)
stage切割规则:从后往前,遇到宽依赖(shuffle或洗牌,算子如:groupByKey、countByKey、reduceByKey、join、groupBy)就切割stage
Task
通过Partition划分(stage会根据RDD分区的数量生成相对应数量的task)
task的内容和stage完全相同,当分区数量为n时,会有n个相同效果的task被分发到执行程序中执行
taskNum=jobNumstageNumblockNum
Task 指具体的执行任务,一个 Job 在每个 Stage 内都会按照 RDD 的 Partition 数量,创建多个 Task,Task 分为 ShuffleMapTask 和 ResultTask 两种。
ShuffleMapStage 中的 Task 为 ShuffleMapTask,而 ResultStage 中的 Task 为 ResultTask。
ShuffleMapTask 和 ResultTask 类似于 Hadoop 中的 Map 任务和 Reduce 任务
driver进程会将我们编写的spark应用代码拆分成多个stage,每个stage执行一部分代码片段,并为每个stage创建一批tasks,然后将这些tasks分配到各个executor中执行。
- 每执行到一个 Action(动作函数),就会创建一个 Job。Job 会提交给 DAGScheduler。
- DAGScheduler 会将 Job 划分为多个 Stage,然后每个 Stage 创建一个 TaskSet。
- TaskScheduler 会把每一个 TaskSet 里的 Task,提交到 Executor 上执行。
- Executor 上有线程池,每接收到一个 Task,就用 TaskRunner 封装,然后从线程池里取出一个线程执行这个 task。(TaskRunner 将我们编写的代码,拷贝,反序列化,执行 Task,每个 Task 执行 RDD 里的一个 partition)
窄依赖与宽依赖
Transformation 和 Action
问题
- 一个worker上只有一个partition吗?