Spark系列文章目录
第一章 初识Spark
第二章 Spark-Core核心模型(一)
第二章 Spark-Core核心模型(二)
第三章 Spark-Core编程进阶(一)
第三章 Spark-Core编程进阶(二)
第四章 Spark-SQL基础(一)
第四章 Spark-SQL基础(二)
第五章 Spark-SQL进阶(一)
第五章 Spark-SQL进阶(二)
第五章 Spark-SQL进阶(三)
第一章 初识Spark
1.认识Spark
Spark是加州大学伯克利分校AMP实验室开发基于内存的通用并行计算框架。
思考:已经学习了MapReduce,为什么要学习Spark?
1.1并行计算
并行计算(Parallel Computing)是指同时使用多种计算资源解决计算问题的过程,是提高计算机系统计算速度和处理能力的一种有效手段。
它的基本思想是:用多个处理器来协同求解同一问题。
注意,其实就是将被求解的问题分解成若干个部分,各部分均由一个独立的处理机来并行计算
并行计算系统:
- 既可以是专门设计的、含有多个处理器的超级计算
- 也可以是以某种方式互连的若干台的独立计算机构成的集群
通过并行计算集群完成数据的处理,再将处理的结果返回给用
1.2 MapReduce
MapReduce是面向大数据并行处理的计算模型、框架和平台,它隐含了以下三层含义:
-
MapReduce是一个基于集群的高性能并行计算平台(Cluster Infrastructure)
它允许用市场上普通的商用服务器构成一个包含数十、数百至数千个节点的分布和并行计算集群。
-
MapReduce是一个并行计算与运行软件框架(Software Framework)
- 能自动完成计算任务的并行化处理
- 能自动划分计算数据和计算任务
- 能自动分配和执行任务
- 能收集计算结果
- 能将数据分布存储、数据通信、容错处理等并行计算涉的很多系统底层的复杂细节处理
- 能大大减少了软件开发人员的负担
-
MapReduce是一个并行程序设计模型与方法(Programming Model & Methodology)
它借助于函数式程序设计语言Lisp的设计思想。
- 提供了一种简便的并行程序设计方法,用Map和Reduce两个函数编程实现基本的并行计算任务
- 提供了抽象的操作和并行编程接口,以简单方便地完成大规模数据的编程和计算处理
1.2.1 优点
-
Mapreduce易于编程
- 简单的实现一些接口,就可以完成一个分布式程序
-
良好的扩展性
- 当项目计算资源得不到满足的时候,可以简单的通过增加机器来扩展它的计算能力
-
高容错性
- 当一个机器挂了,可以把上面的计算任务转移到另一个节点上运行,此过程由框架自行完成
-
适合PB级以上海量数据的离线处理
1.2.2 缺点
-
实时计算
- MapReduce无法像Oracle或MySQL那样在毫米或秒级内返回结果,如果需要大数据量的毫秒级响应,可以考虑使用HBase。
-
流式计算
- 流计算的输入数据是动态的,而MapReduce的输入数据是静态的,不能动态变化,这是因为MapReduce自身的设计特点决定了数据源必须是静态的。如果需要处理流式数据可以用Storm、Spark Steaming、Flink。
-
数据挖掘、 DAG(有向图)、机器学习等迭代计算
- 多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入磁盘,会造成大量的磁盘IO导致性能非常低下,此时可以考虑用Spark等迭代计算框架。
1.3 Spark由来
发展历程
-
2009年由 Berkeley’s AMPLab 开始编写最初的源代码;
-
2010年开放源代码;
-
2013年6月进入Apache孵化器项目;
-
2014年2月成为Apache的顶级项目(8 个月时间);
-
2014年5月底Spark1.0.0发布;
……………………
-
2016年3月Spark1.6.1发布;
-
2016年7月Spark2.0发布;
……………………
-
2020年2月Spark2.4.5发布;
-
2020年6月Spark3.0.0发布;
1.4 Spark特点
在Spark官网上介绍,它具有运行速度快、易用性好、通用性强和随处运行等特点。
- 运行速度快
Spark拥有DAG执行引擎,支持在内存中对数据进行迭代计算。官方提供的数据表明,如果数据由磁盘读取,速度是Hadoop MapReduce的10倍以上,如果数据从内存中读取,速度可以高达100多倍。
- 易用性好
支持4种语⾔言的API:Scala、Java、Python、R。特别是Scala是一种高效、可拓展的语言,能够用简洁的代码处理较为复杂的处理工作。
//Sprark-Core RDD
//词频统计 SparkContext
val text_file:RDD[String]=sc.textFile("hdfs://...")
text_file.flatMap(_.split(" ")).map(word => (word,1)).reduceByKey(_+_)
//Sprark-Sql Dataset SparkSession
//从Spark2.2.0之后,推荐使用 Dataset API
val textFile:Dataset[String] = spark.read.textFile("README.md")
val wordCounts = textFile.flatMap(line => line.split(" ")).groupByKey(identity).count()
- 通用性强
Spark技术栈是由以下五个组件组成,分别为:
这些组件分别提供以下功能:
- Spark Core提供内存计算
- SparkStreaming提供实时计算
- Spark SQL提供即时查询
- MLlib提供机器学习
- GraphX提供图处理
它们都是由AMP实验室提供,能够无缝的集成并提供一站式解决平台。
注意,Spark其他项目都会依赖于核心项目 Spark-Core的中的组件模块。
- 随处运行
- Spark可以读取HDFS、HBase、Cassandra S3中的数据
- 可以运行在Mesos、YARN和Standalone等资源管理调度器
Spark生态圈:也称为BDAS(伯克利数据分析栈),是伯克利APMLab实验室打造的,力图在算法(Algorithms)、机器(Machines)、人(People)之间通过大规模集成来展现大数据应用的一个平台。
运用大数据、云计算、通信等各种资源以及各种灵活的技术方案,对海量不透明的数据进行甄别并转化为有用的信息,以供人们更好的理解世界。
该生态圈已经涉及到机器学习、数据挖掘、数据库、信息检索、自然语言处理和语音识别等多个领域。
2.Spark安装
2.1 Spark模式
Spark的部署/运行模式默认为local[*]。
2.1.1 本地模式
Local模式是在一台计算机上的运行模式,适合于学习与测试。
设置本地模式的三种方式:
-
local 用单线程来运行
-
local[Number] 用Number个线程模式并行
-
local[*] *代表该计算机的CPU核数
2.1.2 Yarn模式
Spark-On-Yarn模式是在Yarn集群中运行,适合于生产环境。
yarn
2.1.3 Standalone模式
Spark-Standalone模式是在Spark独立集群中运行,适合于生产环境。需要提前搭建好Spark集群,国内使用较少。
spark://host:port
2.1.4 Mesos模式
Mesos是Apache下的开源分布式资源管理框架,它被称为是分布式系统的内核。Mesos最初是由加州大学伯克利分校的AMPLab开发的,后在Twitter得到广泛使用。
mesos://host:port
2.1.5 K8S模式
kubernetes,简称K8s,是用8代替8个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用。
k8s://https://host:port
2.2 Spark安装
2.2.1 单机配置
- 解压
tar -xvf spark.2.2.1-bin-hadoop2.7.tar
- 移动到opt/software目录中
mv spark.2.4.5-bin-hadoop2.7 /opt/software/
- 创建软连接
sudo ln -s software/spark.2.4.5-bin-hadoop2.7 spark
- 修改环境变量:
vi ~/.bashrc
export SPARK_HOME=/opt/spark
export PATH=$PATH:$SPARK_HOME/bin:$PATH:$SPARK_HOME/sbin
source ~/.bashrc
-
可选-修改 $SPARK_HOME/conf/log4j.properties下的log4j的级别
-
可选-拷贝一份hive-site.xml到spark安装目录的conf目录下
-
测试spark是否安装成功
在终端输入:
spark-shell --version
-
成功效果
2.2.2 Spark-on-Yarn环境搭建
- 事先准备:Hadoop集群上的三个配置文件
core-site.xml
yarn-site.xml
hdfs-site.xml
将三个文件存储到一个空目录中。
例如:/opt/spark/spark-yarn/目录下。
- 在$SPARK_HOME/conf/spark-env.sh环境配置文件中添加如下配置
export HADOOP_CONF_DIR =/opt/spark/spark-yarn/
export SPARK_LOCAL_IP=机器IP地址或者是主机名
- 优化配置
在spark-defaults.conf
配置文件里添加如下配置:
spark.yarn.jars hdfs://HDFS集群的主节点IP:9000/spark_lib/jars/*
或者
spark.yarn.archive hdfs://HDFS集群的主节点IP:9000/spark_lib/jars
注意,此配置需先将Spark的家目录的jars文件夹上传到hdfs上。
上传操作具体如下:
hdfs dfs -mkdir /spark_lib
hdfs dfs -put /opt/spark/jars /spark_lib/
2.2.3 Spark-Standalone环境搭建
-
修改Spark配置文件 (路径为$SPARK_HOME/conf/下)
复制slaves.template和 spark-env.sh.template各一份cp spark-env.sh.template spark-env.sh
cp slaves.template slaves
-
vi slaves,此文件是指定子节点的主机,直接添加从节点主机名即可(前提是在/etc/hosts里面配置了).例如:
briup0
briup1
briup2
-
在spark-env.sh末端添加如下几行:
必须配置
#主节点的IP地址
export SPARK_MASTER_IP=192.168.1.200
可选配置
#主节点的端口号
export SPARK_MASTER_PORT=7077
#指定Spark用来混洗数据的本地存储路径
export SPARK_LOCAL_DIRS=/data/spark/dirs,/home/briup/spark/dirs
#(一定要注意这个混洗数据的路径的权限)
#Worker的WebUI端口号
export SPARK_WORKER_WEBUI_PORT=8081
#主节点的WEBUI端口号
export SPARK_MASTER_WEBUI_PORT=8099
#每个Worker使用的CPU核数,默认1个
export SPARK_WORKER_CORES=2
#每个Slave中启动几个Worker实例,默认1个
export SPARK_WORKER_INSTANCES=2
#每个Worker使用多大的内存,默认1g
export SPARK_WORKER_MEMORY=2g
#驱动器节点Driver使用的内存
export SPARK_DRIVER_MEMORY=2g
-
启动start-all.sh命令或者是
start-master.sh/start-slave.sh spark://host:7077
-
测试是否成功,在集群的所有机器上输入
jps
-
打开浏览器输入http://localhost:8080查看集群资源页面
测试spark-submit命令
$Spark_home/spark-submit --master spark://localhost:7077 --class org.apache.spark.examples.SparkPi examples/jars/spark-examples_2.11-2.2.1.jar 10
2.2.4 Spark-on-Hive环境搭建
- 将hive-site.xml添加到$SPARK_HOME/conf/目录下
hive-site.xml文件内容如下:
<configuration>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://127.0.0.1:3306/hive_spark?createDatabaseIfNotExist=true</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>spark</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>spark</value>
</property>
<property>
<name>hive.metastore.schema.verification</name>
<value>false</value>
</property>
<property>
<name>hive.server2.thrift.port</name>
<value>10000</value>
</property>
<property>
<name>hive.server2.thrift.bind.host</name>
<value>0.0.0.0</value>
</property>
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
</property>
</configuration>
- 修改
spark-defaults.conf
文件
#集群运行模式下,需要将Hive的元数据的连接jar包配置到执行器节点
spark.executor.extraClassPath $HIVE_HOME/lib/mysql-connector-java-5.1.22.jar
#设置warehouse
spark.sql.warehouse.dir hdfs://computer1.cloud.briup.com:9000/user/hive/warehouse/
-
添加Mysql连接jar包
将mysql的依赖mysql-connector-java-5.1.22.jar添加到spark的安装目录,并上传到HDFS的/spark_lib/jars目录下
-
命令行测试
spark-sql --driver-class-path $HIVE_HOME/lib/mysql-connector-java-5.1.22.jar
-
编码测试
//构建支持Spark-On-Hive的SparkSession对象
object FirstSpark{
def main(args:Array[String])={
val spark=SparkSession.builder()
.appName("应用名称")
.master("运行模式")
.config("spark.sql.warehouse.dir","Hive数据仓库地址")
//需要先在hive服务器中启动该命令hive --service metastore
.config("hive.metastore.uris","thrift://Hive所在服务器的IP地址:9083")
.enableHiveSupport()
.getOrCreate();
import spark.implicits._
}
}
注意 ,如果在代码中没有指定支持Hive的配置,需要在resources目录下添加hive-site.xml配置文件
配置文件内容如下:
<configuration>
<!--第一种方式:指定hive的地址,用户名,密码等信息 -->
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://127.0.0.1:3306/hive_spark?createDatabaseIfNotExist=true</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>spark</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>spark</value>
</property>
<!--第二种方式:借助于thriftserver协议 -->
<!--先在hive服务器中启动该命令hive 两个-service metastore &-->
<property>
<name>hive.metastore.uris</name>
<value>thrift://172.16.0.4:9083</value>
</property>
</configuration>
3.Spark架构
3.1 通用运行架构
说明 :
-
ClusterManager
集群管理者,负责集群整体资源管理和调度
在Spark Standalone模式中为Master,控制整个集群,监控Worker。
在Spark on Yarn模式中为资源管理器RecourceManager。
-
Worker
从节点,负责控制计算的节点
启动Executor或Driver。在Spark on Yarn模式中为NodeManager。 -
Driver
驱动器,运行Application的main()函数并且创建SparkContext的进程。
当全部的Executor运行完毕后,Driver负责将SparkContext关闭。
-
SparkContext
是整个 Spark 应用程序的上下文,控制应用的生命周期,通常用SparkContext代表Driver。
- 负责与ClusterManager通信
- 负责资源的申请
- 负责任务的分配
- 负责任务的监控
- 负责创建RDD、累加器、广播变量
注意,每个JVM里只能存在一个处于激活状态的SparkContext。
-
Executor
执行器,Application运行在worker节点上的一个进程。
- 负责将Task包装成线程池(TaskRunner)
- 负责启动线程池
- 负责从线程池中抽取出一个空闲线程运行任务(Task)
- 负责将数据存在内存或磁盘上
注意,每个执行器能(Executor)并行运行 Task 的数量就取决于分配给它的 CPU 个数。
3.2 Spark On Yarn运行架构
在YARN中,每个Application实例都有一个ApplicationMaster进程,它是Application启动的第一个容器。
- 它负责和ResourceManager打交道并请求资源
- 获取资源之后告诉NodeManager为其启动Container
从深层次的含义讲YARN-Cluster和YARN-Client模式的区别其实就是ApplicationMaster进程的区别。
-
YARN-Cluster模式下
- Driver运行在AM(Application Master)中,负责向YARN申请资源,并监督作业的运行状况
- 当用户提交了作业之后,就可以关掉Client,作业会继续在YARN上运行
- 因而YARN-Cluster模式不适合运行交互类型的作业
-
YARN-Client模式下
- Application Master仅仅向YARN请求Executor
- Client会和请求的Container通信来调度他们工作
- 也就是说Client不能离开
3.3 Spark Standalone运行架构
4.Spark命令
4.1 spark-shell
Spark提供的终端命令,允许在终端中使用Scala、Java编程语言编写Spark程序。适用于学习测试环境。
语法:
Usage: ./bin/spark-shell [options]
帮助命令:
spark-shell —help
4.2 spark-sql
Spark提供的终端命令,允许在终端使用Sql语言操作数据。适用于学习测试环境。
语法:
Usage: ./bin/spark-sql [options] [cli option]
帮助命令:
spark-sql —help
4.3 spark-submit
Spark提供的作业提交命令,允许将打包好的程序提交到集群中运行。适用于生产环境。
语法:
Usage: spark-submit [options] <app jar | python file | R file> [app arguments]
Usage: spark-submit --kill [submission ID] --master [spark://...]
Usage: spark-submit --status [submission ID] --master [spark://...]
Usage: spark-submit run-example [options] example-class [example args]
帮助命令:
spark-submit —help
含义解释:
- app jar 表示应用入口的jar包,必须传递
- app arguments 表示传递给主方法的参数,可以省略
- options 表示可选配置,可以省略
- submission ID 表示提交作业的ID,可以省略
- run-example 表示运行官方自带案例
- example-class 表示官方自带案例所在类的全类名
可选配置(options):
--master 运行模式,默认为local[*]
--class 主方法所在类名
--name 应用名称
--deploy-mode Yarn的客户端还是集群模式,默认为client,可以修改为cluster
--executor-memory 执行器内存大小,默认为1g
--driver-memory 驱动器内存大小,默认为1g
--num-executors 执行器的个数,默认为2
--executor-cores 每个执行器的CPU个数,默认为1
--driver-cores 驱动器的CPU个数,默认为1,只支持cluster模式下修改
--jars 额外依赖的第三方jar包
--files 需要分发到各节点的数据文件
--total-executor-cores 执行器的CPU个数,默认为集群中全部可用CPU个数,只支持Standalone,Mesos,K8s运行模式下生效
5.编程流程
6.Spark案例
6.1 构建Spark-maven项目
-
直接构建一个Maven-Project项目
-
将以下内容添加到pom.xml文件标签内之后,在src目录下依次构建main/scala目录,更新maven项目
<properties>
<scala.version>2.12.8</scala.version>
<spark.scala.version>2.12</spark.scala.version>
<spark.version>3.0.1</spark.version>
</properties>
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
<!--引入Spark-core核心依赖-->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_${spark.scala.version}</artifactId>
<version>${spark.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<useFile>false</useFile>
<disableXmlReport>true</disableXmlReport>
<includes>
<include>**/*Test.*</include>
<include>**/*Suite.*</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
6.2 WordCount案例
- 新建一个package
base
- 在该包下创建一个scala object
WordCount
- 在该对象的中构建main方法
package com.briup.base
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object WordCount {
def main(args: Array[String]): Unit = {
if(args.length<2){
println("请输入需要进行词频统计的文件路径以及结果存储路径!!")
System.exit(0)
}
//目的:获取Spark上下文对象
//1.获取SparkConf对象
val conf=new SparkConf();
conf.setMaster("local[*]")
conf.setAppName("词频统计案例")
//2.获取SparkContext对象
val sc=new SparkContext(conf);
sc.setLogLevel("warn")
println(sc)
//3.借助于sc的方法获取RDD对象
val fileRDD: RDD[String] = sc.textFile(args(0))
//4.根据业务逻辑调用RDD中一系列方法(转化方法和行动方法)
//统计words.txt中每个单词出现的频次
//将字符串分割成一个个单词
val mapRDD: RDD[String] = fileRDD.flatMap( (x:String)=> x.split(" ") )
//转化,将每个单词转化为二元元组
val wordAndNumRDD=mapRDD.map( (word:String) => (word,1) )
//按照key相同,value进行相加
val wordCountRDD=wordAndNumRDD.reduceByKey(_+_)
//将词频统计结果输出到控制台
wordCountRDD.foreach(println)
//将计算结果存储到文本文件中
wordCountRDD.saveAsTextFile(args(1))
//5.关闭SparkContext对象
sc.stop()
}
}
7.作业流程
说明 :
-
Application
应用,用户编写的 Spark 应用程序
- 包含了运行在Driver上的代码
- 包含了运行在 Executor上的代码
- 将应用提交后集群之后,集群管理者为该Application分配资源并将程序转换并执行
-
RDD
弹性分布式数据集(Resillient Distributed Dataset),Spark 的基本计算单元 -
DAG
有向无环图( DirectedSched Acycle graph),反应 RDD 之间的依赖关系 -
Job
作业,由RDD Action算子触发,在SparkContext通过runJob方法向Spark提交Job
- 一个Application中可以包含多个Job
- 一个Job转化为一个DAG
-
DAG
有向无环图(DirectedSched Acycle graph),反应 RDD 之间的依赖关系- 一个DAG交给一个DAG Scheduler
-
DAG Scheduler
有向无环图调度器,负责将DAG根据宽依赖关系划分为Stage,并提交 Stage给 TaskScheduler
- 一个DAG默认为一个Stage
- 一个宽依赖关系Stage加一
- 一个Stage交给一个TaskScheduler
-
Stage
阶段
- 一个Stage包含一组相同的Task,这一组Task也叫做TaskSet
- 一个Stage包含的Task个数取决于分区个数
- 一个分区对应一个Task
-
Task Scheduler
任务调度器,将Task分发给Executor执行 -
Task
任务,执行RDD中对应Stage中所包含的算子
-
SparkEnv
线程级别的上下文,存储运行时的重要组件的引用,可以进行shuffle管理或广播变量等的管理
文字描述:
- 用户在Client端通过spark-submit命令将Application提交到ClusterManager;
- ClusterManager接收到App之后,会找一个Worker启动Driver;
- Driver程序创建SparkContext,将其作为调度的总入口;
- SparkContext在初始化过程中分别创建DAGScheduler(进行Stage调度)和TaskScheduler(进行Task调度)两个模块。同时SparkContext会将App拆分成多个RDD DAG;
- 每一个DAG会提交给一个DAGScheduler,DAGScheduler会根据它们的依赖关系拆分成不同的Stage(TaskSets),每一个Stage提交给一个TaskScheduler;
- TaskScheduler会将这些Task任务不断的分发到Worker节点的中的Executor中执行;
- Executor会启动多线程,将每一个任务交给一个线程执行;
- SparkEnv会启动一些控制组件,进行shuffle管理或广播变量等的管理;
- Driver管理Task状态,Task完成,Stage完成,作业完成。