Spark源码分析笔记(二)Spark设计理念与基本架构

一. hadoop1.0 hadoop2.0 Spark对比

hadoop1.0贡献了三个部分:

  1. 运行时环境:任务管理者jobTracker ,任务的执行者taskTracker
  2. 编程模型:MapReduce,开发者完成Map函数和Reduce函数
  3. 数据处理引擎:Map任务,数据的过滤分类;Reduce任务,数据的汇聚

但是也有很多不足

  1. 可扩展性差:jobTracker既负责资源管理又负责任务调度,负责太多工作,容易出问题。在spark中,job向资源管理器申请到资源后,就负责对任务状态的监控及调度。资源管理器更好的负责集群资源的管理与分配。
  2. 可用性差:表现为master节点故障后集群的不可用。Spark中可以配置辅master,当主master故障时,可以维持工作;
  3. 资源利用率低:表现为两方面,一方面是task对已分配资源的利用率低,且占用;另一方面,一次分配资源给map任务和reduce任务,map任务先执行,此时reduce任务占有资源且不使用
  4. 组件的扩展性差:不支持spark,storm。

hadoop2.0的瓶颈:频繁对HDFS的操作引起的I/O瓶颈

spark在解决上述问题后,相比性能提升的最大地方是,支持了数据在内存里计算,减少了I/O操作,但不是完全内存,内存不够的时候还是需要磁盘IO的。

二. Spark设计思想

spark从功能上提供了核心功能sparkcore和spark的扩展功能(源码上也可以体现)

先看一下一个rdd任务如何执行的(个人理解):我向spark提交任务,会配置好相关参数,然后spark将参数广播,并向集群管理器申请资源,在每一个分配得到的work上跑任务。一个任务,一般获取数据,然后进行数据裁剪(map),此时一个work存储一个partition数据,会有一个task任务去处理这个分区的数据,这样就会避免各个work的数据的传输,并且在内存在计算,如果溢出可以写入磁盘。map之后,执行reduce任务,将各个分区(各个work节点)的数据进行混洗(shuffle:比如聚合,关联),得出最后的结果写入hdfs上,shuffle是影响任务性能的瓶颈。

那么sparkcore是如何处理的?

  • SparkContext:负责初始化,即将配置参数作为SparkContext的入参,然后Spark会知道任务会用多大的内存等参数。SparkContext还会将RDD进行拆分,先将RDD拆分成多个stage,再将stage拆分job,一个job拆成多个task(分区相关),且这些任务的提交和调度都有SparkContext完成
  • 存储体系:Spark会优先使用内存进行计算,提高计算效率。另外有个广播变量(broadcast)机制,基于内存共享,提高执行效率。
  • 计算引擎:如何将RDD的mapreduce划分成最终的task粒度。
  • 部署模式:管理平台的资源分配。比如如何解决平台每小时能够调度1W级的任务的资源分配。

另外对于spark的扩展功能:Spark SQL,Spark Streaming,GraphX(图计算),MLlib(机器学习),或是工具,或是API。

Spark SQL:提供熟悉SQL的操作工具,可以实现对HDFS数据的查询,内部机制也是RDD的执行。

Spark Streaming: 流式计算。比如利用kafka推送对集群进行数据入库时,某份数据并不是一个整体直接过来,而是在不同时间段划分成不同份,将原始数据放到hdfs过程中,kafka可以对文件进行解析,初步整理,添加分区字段等操作。

三. Spark基本架构

Spark源码分析笔记(二)Spark设计理念与基本架构

Cluster Manager(集群管理器):负责集群资源的分配与管理。Driver App需要执行任务时,向集群管理器申请资源,集群管理器将spark的worker节点的内存,cpu分配给任务,但是不负责executor的资源分配。

Master与worker:都是spark的节点,master管理worker,暂不清楚master和集群管理器的关系,worker会创建executor,将自己的资源进一步分配给executor,并通知master?集群管理器自己资源信息。

driver:Driver负责整个应用任务的job的划分和stage的切割以及task的切割和优化,并负责把task分发到worker对应的节点的executor进程中的task线程中执行, 并获取task的执行结果,Driver通过SparkContext对象与spark集群获取联系,得到master主机host,就可以通过rpc向master注册自己。driver是要获取结果,所以driver的内存分配也很关键,比如使用collect();

executor:执行driver分配的任务,并将执行结果,状态等信息与driver,worker同步。注意executor内存的分配。