一、Spark运行时的架构
1.基本概念
- 在分布式环境下,Spark集群采用的是主/从结构。在一个Spark集群中,有一个节点负责中央协调,调度各分布式工作节点。
- 中央协调节点被称为驱动器(Driver)节点,与之对应的工作节点被称为执行器(executor)。
- 驱动器节点可以和大量的执行器节点进行通信,它们也都作为独立的Java进程运行。
- 驱动器节点和所有的执行器节点一起被称为一个Spark应用。
- Spark应用通过一个叫作集群管理器(Cluster Manager)的外部服务在集群中的机器上启动。
- Spark自带的集群管理器被称为独立集群管理器。Spark也能运行在Hadoop YARN和Apache Mesos这两大开源集群管理器上。
2.驱动器节点
- spark驱动器是执行你的程序中main()方法的进程。
- 驱动器程序在Spark应用中的职责:
- 把用户程序转为任务
- spark程序其实隐式的创建除了一个由操作组成的逻辑上的有向无环图(Direct Acylic Graph,简称DAG)。当驱动器程序运行时,它会把这个逻辑图转为物理执行计划。
- Spark会对逻辑执行计划作一些优化,比如将连续映射转为流水线化执行,将多个操作合并到一个步骤中等。这样Spark就把逻辑计划转为一系列步骤(stage)
- 每个stage又由多个任务组成。这些任务会被打包发送到集群中。
- 任务是spark中最小的工作单元,用户程序通常要启动成百上千的独立任务。
- 为执行器节点调度任务
- 有了物理执行计划之后,Spark驱动器程序必须在各执行器进程间协调任务的调度。
- 每个执行器节点代表一个能够处理任务和存储RDD数据的进程。
- spark会根据当前执行器节点集合,尝试把所有任务基于数据所在位置分配给合适的执行器进程。
- 把用户程序转为任务
3.执行器节点
- 执行器节点是一种工作进程,负责在spark作业中运行任务,任务间相互独立。
- RDD是直接缓存在执行器进程内的,因此任务可以在运行时充分利用缓存数据加速运算。
二、集群管理器
- 驱动器节点和执行器节点时如何启动的?
- Spark依赖与集群管理器来启动执行器节点,而在某些特殊情况下,也依赖集群管理器来启动驱动器节点。集群管理器是Spark中的可插拔式组件。
- spark文档中始终使用驱动器节点和执行器节点的概念来描述执行spark应用的进程。而主节点(master)和工作节点(worker)的概念则被用来分别表述集群管理器中的中心化的部分和分布式的部分。
三、启动一个程序
- 不论使用的是哪种集群管理器,都可以使用Spark提供的统一脚本spark-submit将你的应用提交到那种集群管理器上。
- 通过不同的配置项,spark-submit可以连接到相应的集群管理器上,并控制应用所使用的资源数。
- 在使用某些特定集群管理器时,spark-submit也可以将驱动器节点运行在集群内部(比如一个YARN的工作节点)。但对于其他的集群管理器,驱动器节点只能被运行在本地机器上。
四、使用spark-submit部署应用
- spark-submit --master可接受的值参考105页
- 其他选项:
- 调度信息,比如你希望为作业申请的资源
- 应用运行时的依赖,比如需要部署到所有工作节点上的库和文件
- 例子
#!/bin/sh
root=/search/odin/liubin/eta-spark
nohup spark-submit \
--conf spark.master=yarn \
--conf spark.submit.deployMode=client \
--num-executors 30 \
--conf spark.executor.cores=3 \
--conf spark.executor.memory=12G \
--conf spark.driver.memory=6G \
--conf spark.driver.cores=2 \
--conf spark.default.parallelism=100 \
--conf spark.shuffle.spill=true \
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer \
--conf spark.dynamicAllocation.enabled=false \
--conf spark.ui.port=9532 \
--conf spark.network.timeout=10000000 \
--class com.robinliew.learn.BaofusiDataApp \
--name BaofusiDataApp \
--jars $root/scalaj-http_2.11-2.3.0.jar,$root/predict-eta-api-0.0.1-SNAPSHOT.jar,$root/evaluate-eta-api-0.0.1-SNAPSHOT.jar,$root/link-api-2.4.3.jar,$root/commons-math-2.2.jar,$root/navi-eta-2.1.jar,$root/kubbo-all-0.12.0.jar,$root/sogou-commons-datatype-1.2.jar,$root/navi-commons-datatype-1.1.1.jar $root/BaofusiDataApp-1.0-SNAPSHOT.jar
- 解释:
--deploy-mode:选择在本地(客户端"client")启动驱动器程序,还是在集群中的一台工作节点机器(集群"cluster")启动。
默认是本地模式。
--class:运行Java或Scala程序时应用的主类
--jars:需要上传并放到应用的CLASSPATH中的JAR包的列表。如果应用依赖少量的第三方的jar包,可以把它们放在这个参数里。
--files:需要放到应用工作目录中的文件列表。这个参数一般用来放需要分发到各节点的数据文件。
- spark-submit容许通过–conf prop=value标记设置任意的SparkConf配置选项,也可以使用–properties-File指定一个包含键值对的属性文件。
五、打包代码与依赖
- Java和scala用户也可以通过spark-submit的–jars标记提交独立的JAR包依赖。
- 常规的做法是使用构建工具,生成单个大JAR包,包含应用的所有的传递依赖。这通常被称为超级(uber)JAR或者组合(assembly)JAR,大多数Java或Scala的构建工具都支持生成这样的工件。
- Maven和Sbt构建工具的使用(Sbt单独一章写)
1.一个典型的Maven配置
<?xml version="1.0" encoding="UTF-8"?>
<!--
Generated from archetype; please customize.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.robinliew.learn</groupId>
<artifactId>BaofusiDataApp</artifactId>
<name>LearnScala project</name>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<encoding>UTF-8</encoding>
<scala.version>2.11.8</scala.version>
<spark.version>2.2.0</spark.version>
<hadoop.version>2.6.0</hadoop.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>
<!-- 为了方便看源码 -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
<scope>provided</scope>
</dependency>
<!-- spark依赖 -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
</dependency>
<!-- 第三方库 -->
<!-- link-api相关服务 -->
<dependency>
<groupId>com.sogou.map</groupId>
<artifactId>link-api</artifactId>
<version>2.4.3</version>
</dependency>
<!-- kubbo -->
<dependency>
<groupId>com.sogou.map</groupId>
<artifactId>kubbo-all</artifactId>
<version>0.12.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaVersion>${scala.version}</scalaVersion>
<args>
<arg>-target:jvm-1.5</arg>
</args>
</configuration>
</plugin>
<!-- 指定多个源代码目录、多个资源文件目录 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
- 2.使用maven-shade-plugin插件来创建出包含所有依赖的超级JAR包。把spark相关依赖标记为provided来确保Spark不与应用依赖的其他工件打包在一起。
<?xml version="1.0" encoding="UTF-8"?>
<!--
Generated from archetype; please customize.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.robinliew.learn</groupId>
<artifactId>BaofusiDataApp</artifactId>
<name>LearnScala project</name>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<encoding>UTF-8</encoding>
<scala.version>2.11.8</scala.version>
<spark.version>2.2.0</spark.version>
<hadoop.version>2.6.0</hadoop.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>
<!-- 为了方便看源码 -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>${spark.version}</version>
<scope>provided</scope>
</dependency>
<!-- link-api相关服务 -->
<dependency>
<groupId>com.sogou.map</groupId>
<artifactId>link-api</artifactId>
<version>2.4.3</version>
</dependency>
<!-- kubbo -->
<dependency>
<groupId>com.sogou.map</groupId>
<artifactId>kubbo-all</artifactId>
<version>0.12.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<!-- 用来创建超级JAR包的Maven shade插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<scalaVersion>${scala.version}</scalaVersion>
<args>
<arg>-target:jvm-1.5</arg>
</args>
</configuration>
</plugin>
<!-- 指定多个源代码目录、多个资源文件目录 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
3.SBT 配置
- VM Parameters
-XX:MaxPermSize=512M
-Dsbt.log.format=true
-Dfile.encoding=UTF-8
-Dsbt.ivy.home=D:/softwaredevelopkit/sbt/location/.ivy2
-Dsbt.global.base=D:/softwaredevelopkit/sbt/location/.sbt
-Dsbt.repository.config=D:/softwaredevelopkit/sbt/location/.sbt/repositories
六、Spark应用内与应用间调度
-
在调度多用户集群时,Spark主要依赖集群管理器来在Spark应用间共享资源。
-
当Spark应用向集群管理器申请执行器节点时,应用收到的执行器节点个数可能比它申请更多或者更少,这取决于集群的可用性与争用。
-
许多集群管理器支持队列,可以为队列定义不同优先级或容量限制,这样Spark就可以把作业提交到相应的队列中。
-
spark应用有一种特殊情况,就是那些长期运行的应用。这意味着这些应用从不主动退出。
-
spark内部的公平调度器会让长期运行的应用定义调度任务的优先级队列。
集群的配置启动(单独一章来写)
扫码关注公众号
- 后台回复“Spark学习资料”免费获取更多Spark学习教材及实战资料