Spark架构
-
MapReduceOnYarn(回顾)
工作步骤
- 第一步:在ClientNode上,初始化JVM容器(RunJar),运行MapReduce应用,然后实例化Job对象
- 第二步:将Job对象,注册到Yarn集群的ResourceManager之上,返回一个ApplicationId
- 第三步:将Job对象的资源(任务的jar、配置文件、计算的数据切片信息等)提交到一个共享的文件系统(通常指的HDFS,大数据计算原则:移动计算而不移动数据)
- 第四步:正式的将MapReduce的Job提交到Yarn计算中运行(注意:此步骤后所有的操作都发生在Yarn集群)
- 第五、六步:Yarn集群的ResourceManager会在某空闲的NodeManager会加载一个JVM容器MRAppMaster(负责Job的监控和管理),并且对Job进行进一步的初始化
- 第七步: MRAppMaster会从共享的文件系统(HDFS)获取数据切片信息,(一个Splits —》 MapTask, ReduceTask【默认为1,或者手动设定】)
- 第八步:MRAppMaster会请求Yarn集群的ResourceManager分配相应单位的计算资源(JVM进程)
- 第九步:MRAppMaster会在ResourceManager分配的空闲的NodeManager上启动相应单位的计算进程(YarnChild)
- 第十、十一步:接下来YarnChild(Task JVM)会从共享的文件系统(HDFS)获取资源(任务jar包,计算数据),运行MapTask/ReduceTask
- 第十二步: 当任务运行结束后,释放资源
分析问题
- MapReduce任务分为粗粒度的MapTask和ReduceTask,并且计算针对于进程(JVM)的,并不能发挥多核CPU的优势
- MapReduce慢,MapTask映射的结果需要溢写在磁盘中存储,Reduce任务计算时需要通过网络从磁盘拉取负责计算分区数据,造成的大量资源开销
- MapReduce完成复杂的科学计算,可能需要将多个任务串联起来,多个任务的数据通过HDFS这样的共享文件系统进行共享(MR—> R1 —> MR2 —> R2 —>MR3 —>R3 …), 计算延迟较高。本来就很慢,串联更慢。
- MapReduce只能够进行Batch(大数据的批处理计算),不支持(Streaming,SQL【借助于Hive】、ML【借助于Mahout】等)
- MapReduce计算中间结果不支持缓存(Cache)
-
SparkOnStandalone架构
将基于Spark开发的应用打包,提交到Standalone集群中运行
工作步骤
- 第一步:在提交Spark应用时会初始化Driver(JVM进程),并且创建SparkContext
- 第二步:Driver会根据任务需要的资源信息,请求资源管理器(ClusterManager)分配计算计算
- 第三步:ClusterManager会根据将分配的计算资源反向注册给Driver
- 第四步:Driver端的DAGScheduler划分Stage,将一个复杂的计算任务肢解为若个小的任务,每一个Stage阶段都包含一个TaskSet
- 第五步:Driver端的TaskScheduler会根据阶段的划分,逐一提交Stage的TaskSet,运行在预支的计算节点。Spark计算节点在运行任务时,TaskSet中的每一个Task运行在Thread线程中,进行分布式并行计算。
- 第六步:当所有阶段的任务运行结束后,通过SparkContext释放占用的计算资源,通知ClusterManager回收
总结特点
- Spark可以将任务进行细粒度的拆分,每一个切分后的任务子集,都支持分布式并行计算。不同于MapReduce粗粒度的阶段划分
- Spark任务在运行时针对线程的,不同于MapReduce进程,能够充分发挥多核CPU计算优势
- Spark的Executor中有Cache缓冲区,可以将计算产生的中间结果进行缓存,便于重复计算和故障恢复。
Spark应用开发
依赖
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<!--_scala的版本-->
<artifactId>spark-core_2.11</artifactId>
<version>2.4.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!--scala项目的打包插件 spark application jar包 运行standalone集群-->
<!--spark应用类似mr程序 运行集群环境中-->
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.0.1</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
开发WordCount应用
import org.apache.spark.{SparkConf, SparkContext}
/**
* spark版本的单词统计
*/
object WordCountApplication {
def main(args: Array[String]): Unit = {
//1. 创建SparkContext,上下文对象提供spark应用运行环境信息
val conf = new SparkConf()
.setAppName("WordCount Apps")
.setMaster("spark://SparkOnStandalone:7077")
val sc = new SparkContext(conf)
//2. 编写DAG计算任务 有向无环图(某逻辑开发 --》 多重计算 --》最终输出)
val rdd = sc.textFile("hdfs://SparkOnStandalone:9000/text.txt")
val result = rdd
.flatMap(line => line.split(" "))
.map(word => (word, 1L)) // (Hello,1L)
.groupByKey()
.map(t2 => (t2._1, t2._2.size))
result.saveAsTextFile("hdfs://SparkOnStandalone:9000/result")
//3. 释放资源
sc.stop()
}
}
在Windows操作系统配置主机名映射
C:\Windows\System32\drivers\etc\HOSTS
192.168.126.100(主机IP) SparkOnStandalone
将Spark应用打包集群运行(远程)
//1. 通过Maven Package插件将Spark应用 打成Jar包
//2. 将Jar包上传到虚拟机中
//3. 提交任务
[root@SparkOnStandalone spark-2.4.4]# bin/spark-submit --help
--master MASTER_URL # 使用spark集群环境
--class CLASS_NAME # spark应用入口类的全限定名
--total-executor-cores NUM # spark应用的计算进程占用核心数量Cores
如:
[root@SparkOnStandalone spark-2.4.4]# bin/spark-submit --master spark://SparkOnStandalone:7077 --class com.baizhi.WordCountApplication --total-executor-cores 2 /root/spark-day1-1.0-SNAPSHOT.jar
在Local本地模拟运行(本地)
import org.apache.spark.{SparkConf, SparkContext}
/**
* spark版本的单词统计
*/
object WordCountApplicationOnLocal {
def main(args: Array[String]): Unit = {
//1. 创建SparkContext,上下文对象提供spark应用运行环境信息
val conf = new SparkConf()
.setAppName("WordCount Apps")
.setMaster("local[*]") // local 本地模式 模拟Spark应用运行 [*] 当前计算机的所有核心 cores 6
val sc = new SparkContext(conf)
//2. 编写DAG计算任务 有向无环图(某逻辑开发 --》 多重计算 --》最终输出)
val rdd = sc.textFile("hdfs://SparkOnStandalone:9000/text.txt")
val result = rdd
.flatMap(line => line.split(" "))
.map(word => (word, 1L)) // (Hello,1L)
.groupByKey()
.map(t2 => (t2._1, t2._2.size))
result.saveAsTextFile("hdfs://SparkOnStandalone:9000/result")
//3. 释放资源
sc.stop()
}
}
org.apache.hadoop.security.AccessControlException
解决方案
:
- 在运行Spark应用时,添加虚拟机参数-DHADOOP_USER_NAME=root