一 Spark 简介
1 什么是 Spark
1.1 Spark 是一种快速 / 通用 / 可扩展的大数据分析 / 计算引擎 ,大数据处理框架 .
1.2 Spark,拥有Hadoop MapReduce所具有的优点;但不同于MapReduce的是——Job中间输出结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的MapReduce的算法。
1.3 Spark 是一种与 Hadoop 相似的开源集群计算环境,但是两者之间还存在一些不同之处,这些有用的不同之处使 Spark 在某些工作负载方面表现得更加优越,换句话说,Spark 启用了内存分布数据集,除了能够提供交互式查询外,它还可以优化迭代工作负载。
1.4 Spark 是在 Scala 语言中实现的,它将 Scala 用作其应用程序框架。与 Hadoop 不同,Spark 和 Scala 能够紧密集成,其中的 Scala 可以像操作本地集合对象一样轻松地操作分布式数据集。
1.5 尽管创建 Spark 是为了支持分布式数据集上的迭代作业,但是实际上它是对 Hadoop 的补充,可以在 Hadoop 文件系统中并行运行。通过名为 Mesos 的第三方集群框架可以支持此行为。Spark 由加州大学伯克利分校 AMP 实验室 (Algorithms, Machines, and People Lab) 开发,可用来构建大型的、低延迟的数据分析应用程序。
2 Spark 的特点
2.1 快速 . 执行相同任务时速度比MapReduce 快几倍甚至几十上百倍 ;开发效率快
2.1 使用简单 .高度封装的 API ,算子丰富 ;支持多种编程语言
2.1 通用 .支持 SQL ;支持实时计算(Spark Streaming 和 Structed Streaming) ;可以应用在机器学习(Spark MLlib) ;图计算(Spark GraphX)
2. 运行灵活 .
1) 多种运行模式 . StandAlone 模式(自带的集群调度) ;Yarn(通用调度框架) ;Local模式(方便开发调试) ;Mesos;Kubemetes..
2) 访问多种数据源 .读取 HDFS ; 读取关系型数据库 ;读取 HBase ;读取 ES 和 Mongo 等 ;读取亚马逊分布式文件系统 S3(简单存储服务)
3 Spark 和 MapReduce 的对比
3.1 MapReduce
- 只能做离线计算
- 编程API不够灵活 ,只能在 map 方法和 reduce 方法中自己实现逻辑
- 对于复杂的运算逻辑 ,一个 MR 无法完成 ,需要多个 MR 按先后顺序串联(一个MR计算完成会将结果写到 hdfs 中,下一个MR 将上一个MR的输出作为输入,这样就要频繁的读写hdfs)
- Shuffle 时数据落地本地磁盘
- 多个 MR就要频繁读写 hdfs ,效率低
3.2 Spark
- 既可以做离线运算 ,也可以做实时运算
- 提供了分布式/高容错(可复原)/有弹性的抽象数据集RDD(不保存要计算的数据,保存的是数据的描述信息和运算逻辑,比如数据要从哪里读取,怎么运算等) / Dataset(数据集) / DataFrame(数据框架) / DStream
- 有高度封装的 API ,算子丰富
- 使用了更先进的DAG有向无环图调度思想 (有向无环图 : 是对多个RDD转换过程和依赖关系的描述 ,触发Action就会形成一个完整的DAG,一个DAG就是一个Job, 一个Job中有一到多个Stage,一个Stage对应一个TaskSet,一个TaskSet中有一到多个Task) ,切分Stage(任务执行阶段) ,优化 pipeline(传递路径/管道)
- Shuffle 时数据落地本地磁盘
- 数据可以 cache(电脑高速缓存/缓存) 到内存中进行复用 ,可以不需要频繁读取hdfs
- 数据可 checkpoint 保证安全
4 Spark 3.0 新特性
2020年6月18日,开发了近两年(自2018年10月份至今)的Apache Spark 3.0.0 正式发布,Apache Spark 3.0.0版本解决并修复了包含3400多个补丁,是开源社区做出巨大贡献的结晶,在Python和SQL功能方面带来了重大进展并且将重点聚焦在了开发和生产的易用性上。
spark3.0新特性介绍连接:https://spark.apache.org/releases/spark-release-3-0-0.html
重点 : 改进的Spark SQL 引擎
自适应查询执行(Adaptive Execution)通过在运行时对查询执行计划进行优化 ,允许Spark Planner 在运行时执行可选的执行计划 ,这些计划将基于运行时统计数据进行优化 ,从而提升性能 .
- 动态合并shuffle partitions
- 动态调整join策略
- 动态优化倾斜的join
- 动态分区裁剪
- ANSI SQL 兼容性
- Join hints
二 Spark 架构体系
框架 | 优点 | 缺点 |
MapReduce | 历史悠久、稳定 | 编程API不灵活、速度慢、只能做离线计算 |
Spark | 通用、编程API简洁、快 | 跟MapReduce比暂无缺点 |
Spark 区别于 MapReduce 最主要的一点是 : 中间输出结果可以保存在内存中 ,不再需要重复读写HDFS ,因此处理数据速度非常快 ,因为启用了内存分布数据集 ,在工作负载方面表现得更加优越.
1 Spark 架构
1.1 standalone client 模式和其执行流程
调度资源的有 Master 和 Driver :
Master : 负责调度资源 ,调度 Worker 在哪些节点上运行 .
Driver : 负责调度 Task ,调度 Task 在哪个 Executor 上运行 .
standalone client 模式执行流程 :
1 类加载 ,通过反射调用指定类的main方法
2 创建SparkContext(简称 sc) ,跟Master通信申请资源
3 Master 跟 Worker 进行通信 ,启动 Worker 端的Executor
4 Worker 端启动Executor ,并创建线程池
5 Executor 跟 Driver 反向注册
6 创建原始的RDD(分布式、弹性、可容错的抽象数据集)
7 调用RDD的Transformation 算子
8 调用RDD的Action 算子,在 Action 中会调用 sc.runJob(触发Action ,就会形成一个完整的DAG)
9 构建DAG(有向无环图 :是对多个RDD转换过程和依赖关系的描述) ,根据shuffle切分Stage(任务执行阶段) ,生成TaskSet(保存同一种计算逻辑多个Task的集合)
10 Taskscheduler 将Task序列化 , 然后通过网络将序列化的Task传送给 Executor
11 Executor 接收到序列化的Task 后,将其进行反序列化 ,然后用实现 Runnable 的包装类包装一层 ,最后提交到线程池 .
1.2 Spark 执行流程简介
- Job : RDD 每一个行动操作都会生成一个或多个调度阶段 (Stage) ,调度阶段是每个 Job 都会根据依赖关系 ,以Shuffle 过程作为划分 ,分为 Shuffle Map Stage 和 Result Stage .触发一次Acition形成一个完整的DAG , 一个DAG对应一个Job , 一个Job中有一到多个Stage,一个Stage对应一个TaskSet,一个TaskSet中有一到多个相同逻辑的Task, Task 的数量与该阶段最后一个 RDD 的分区数相同.
- Task : 分发到 Executor 上的工作任务 ,是 Spark 的最小执行单位
- DAGScheduler : 是将 DAG 根据宽依赖将切分Stage ,负责划分调度阶段并 Stage 转成 TaskSet 提交给 TaskScheduler .
- TaskScheduler : 是将 Task 调度到 Worker 下的 Executor 进程 ,然后丢入到 Executor 的线程池中进行执行
2 Spark 中重要的角色
2.1 Master 是一个 Java 进程 ,接收 Worker 的注册信息和心跳 ,移除异常超时的 Worker ,接收客户端提交的任务 ,负责资源调度 ,命令 Worker 启动 Executor .
2.2 Worker 是一个 Java 进程 ,负责管理当前节点的资源关联 ,向 Master 注册并定期发送心跳 ,负责启动 Executor ,并监控 Executor 的状态 .
2.3 SparkSubmit 是一个 Java 进程 ,负责向 Master 提交任务 .
2.4 Driver 是很多类的统称 ,可以认为 SparkContext 就是 Driver ,client 模式 Driver 运行在 SparkContext 进程中 ,cluster 模式单独运行在一个进程中 ,负责将用户编写的代码转成 Tasks ,然后调度到 Executor 中执行 ,并监控 Task 的状态和执行进度 .
2.5 Executor 是一个 Java 进程 ,负责执行 Driver 端生成的 Task ,将 Task 放入线程中运行 .
3 Spark 和 Yarn 角色对比
Spark StandAlone的Client模式 | YARN |
Master | ResourceManager |
Worker | NodeManager |
Executor | YarnChild |
SparkSubmit(Driver) | ApplicationMaster |
三 Spark 在Linux上安装 , 搭建集群
1 安装 spark ,搭建集群步骤
1.1 下载 spark 安装包 ,下载地址 : https://spark.apache.org/downloads.html
1.2 将下载的 spark 安装包上传到 Linux 服务器上 (rz 方法 ) ,路径为 /opt/apps/ 目录下保存
1.3 在 /opt/apps/ 目录下 ,将 spark 安装包解压
[root@doit04 apps]# tar -zxvf spark-3.0.1-bin-hadoop3.2.tgz
1.4 进入 spark 安装包里面 ,将 conf 目录下的 spark-env.sh.template 重命名为 spark-env.sh , 并进入该文件 ,对该文件进行编辑修改 ,将以下信息添加到文件的最下方.
export JAVA_HOME=/opt/apps/jdk1.8.0_251 -----这个是 jdk 的绝对路径
export SPARK_MASTER_HOST=linux04 -----这个是 Master 安装的节点名字
1.5 将 conf 目录下的 slaves.template 重命名为 slaves ,进入到该文件里面 ,对该文件进行修改 ,指定集群中的 Worker 所在的节点 ,将文件最下方的 localhost 删除掉 ,添加以下节点名称 .
linux04
linux05
linux06
1.6 将配置好的 spark 安装包拷贝给集群中的其他两个节点
第一种方式 :
scp -r spark-3.0.1-bin-hadoop3.2 linux05:$PWD
scp -r spark-3.0.1-bin-hadoop3.2 linux06:$PWD
第二种方式(写一个脚本 ,一次性将配置好的 spark 安装包发送给集群中的其他节点)
for i in {5,6}; do scp -r spark-3.0.1-bin-hadoop3.2 linux0$i:$PWD; done
2 启动 Spark 集群
2.1 在 spark 的安装目录下执行启动脚本
sbin/start-all.sh
2.2 执行 jps 命令查看进程 ,在集群中的 linux04 节点上可以看见 Master 进程和 Worker 进程 ,其他节点上可以看见 Worker 进程 .
2.3 访问 Master 的 web 管理界面 ,端口是 : 8080
四 启动 Spark Shell 编程
1 什么是 Spark Shell
spark shell 是 spark 中的交互式命令行客户端 ,可以在 spark shell 中使用 scala 编写 spark 程序 ,启动后默认已经创建了 SparkContext , 别名是 sc.
2 启动 Spark Shell
/opt/apps/spark-2.3.3-bin-hadoop2.7/bin/spark-shell --master spark://linux04:7077 --executor-memory 1g --total-executor-cores 3 -----执行任务内存为 1g , 总内核为 3
参数说明:
--master 指定masterd地址和端口,协议为spark://,端口是RPC的通信端口
--executor-memory 指定每一个executor的使用的内存大小
--total-executor-cores指定整个application总共使用了cores
3 在 shell 中编写第一个 spark 程序(Wordcount)
sc.textFile("hdfs://linux03:8020/wc/").flatMap(_.split(" ")).map((_, 1)).reduceByKey(_+_).sortBy(_._2,false).saveAsTextFile("hdfs://linux03:8020/out")
解读 :
1) 读取 hdfs 上的文件 ,获得一行一行的数据 ,每一行数据为一个数组
2) 对数组数据进行遍历 ,展平/压平到一个数组中转 ,对一行一行的数据进行切割(根据结构化的数据的规则) ,得到一个数组 ,数组中装的是一个一个的单词 .
3) 对数组中的每个单词进行遍历 ,然后组装成元组模式 (单词 ,1)
4) 根据元组的 key ,对元组进行分组 ,相同的 key 分为一组 , 同一组的数据 ,其 value 进行相加 ,即得到一个新的元组(单词 ,出现的总次数) .
5) 对这个新的元组(单词,总次数) 进行降序排序(这个是全局的排序) ,根据元组中第二个元素 ,即根据元组的总次数 进行降序排序 ,即得到最终结果数据 .
6) 将获得的最终的结果保存到 master 的 hdfs 上 ,可以通过"hdfs dfs -cat 文件的绝对路径" 命令查看结果数据内容 .