Spark快速入门系列(一)了解Spark 与Spark的简单使用

1.Spark概述

目标

Spark 是什么 ?
Spark 的特点 ?
Spark 生态圈的组成  ?

1.1. Spark是什么

目标

了解 Spark 的历史和产生原因, 从而浅显的理解 Spark 的作用

Spark的历史

  • 2009 年由加州大学伯克利分校 AMPLab 开创
  • 2010 年通过BSD许可协议开源发布
  • 2013 年捐赠给Apache软件基金会并切换开源协议到切换许可协议至 Apache2.0
  • 2014 年 2 月,Spark 成为 Apache 的顶级项目
  • 2014 年 11 月, Spark的母公司Databricks团队使用Spark刷新数据排序世界记录

Spark是什么
Apache Spark 是一个快速的, 多用途的集群计算系统, 相对于 Hadoop MapReduce 将中间结果保存在磁盘中, Spark 使用了内存保存中间结果, 能在数据尚未写入硬盘时在内存中进行运算.

Spark 只是一个计算框架, 不像 Hadoop 一样包含了分布式文件系统和完备的调度系统, 如果要使用 Spark, 需要搭载其它的文件系统和更成熟的调度系统

为什么会有Spark
在这里插入图片描述
Spark 产生之前, 已经有非常成熟的计算系统存在了, 例如 MapReduce, 这些计算系统提供了高层次的API, 把计算运行在集群中并提供容错能力, 从而实现分布式计算.

虽然这些框架提供了大量的对访问利用计算资源的抽象, 但是它们缺少了对利用分布式内存的抽象, 这些框架多个计算之间的数据复用就是将中间数据写到一个稳定的文件系统中(例如HDFS), 所以会产生数据的复制备份, 磁盘的I/O以及数据的序列化, 所以这些框架在遇到需要在多个计算之间复用中间结果的操作时会非常的不高效.

而这类操作是非常常见的, 例如迭代式计算, 交互式数据挖掘, 图计算等.

认识到这个问题后, 学术界的 AMPLab 提出了一个新的模型, 叫做 RDDs.

RDDs 是一个可以容错且并行的数据结构, 它可以让用户显式的将中间结果数据集保存在内中, 并且通过控制数据集的分区来达到数据存放处理最优化.

同时 RDDs 也提供了丰富的 API 来操作数据集.

后来 RDDs 被 AMPLab 在一个叫做 Spark 的框架中提供并开源.

总结

Spark 是Apache的开源框架
Spark 的母公司叫做 Databricks
Spark 是为了解决 MapReduce 等过去的计算系统无法在内存中保存中间结果的问题
Spark 的核心是 RDDs, RDDs 不仅是一种计算框架, 也是一种数据结构

1.2. Spark的特点(优点)

目标

理解 Spark 的特点, 从而理解为什么要使用 Spark

速度快

  • Spark 的在内存时的运行速度是 Hadoop MapReduce 的100倍
  • 基于硬盘的运算速度大概是 Hadoop MapReduce 的10倍
  • Spark 实现了一种叫做 RDDs 的 DAG 执行引擎, 其数据缓存在内存中可以进行迭代处理

易用

df = spark.read.json("logs.json")
df.where("age > 21") \
  .select("name.first") \
  .show()
  • Spark 支持 Java, Scala, Python, R, SQL 等多种语言的API.
  • Spark 支持超过80个高级运算符使得用户非常轻易的构建并行计算程
  • Spark 可以使用基于 Scala, Python, R, SQL的 Shell 交互式查询.

通用

  • Spark 提供一个完整的技术栈, 包括 SQL执行, Dataset命令式API, 机器学习库MLlib, 图计算框架GraphX, 流计算SparkStreaming
  • 用户可以在同一个应用中同时使用这些工具, 这一点是划时代的

兼容

  • Spark 可以运行在 Hadoop Yarn, Apache Mesos, Kubernets, Spark Standalone等集群中
  • Spark 可以访问 HBase, HDFS, Hive, Cassandra 在内的多种数据库

总结

支持 Java, Scala, Python 和 R 的 API
可扩展至超过 8K 个节点
能够在内存中缓存数据集, 以实现交互式数据分析
提供命令行窗口, 减少探索式的数据分析的反应时间

1.3. Spark组件

目标

理解 Spark 能做什么
理解 Spark 的学习路线

Spark 最核心的功能是 RDDs, RDDs 存在于 spark-core 这个包内, 这个包也是 Spark 最核心的包.

同时 Spark 在 spark-core 的上层提供了很多工具, 以便于适应不用类型的计算.

Spark-Core 和 弹性分布式数据集(RDDs)

  • Spark-Core 是整个 Spark 的基础, 提供了分布式任务调度和基本的 I/O 功能

  • Spark 的基础的程序抽象是弹性分布式数据集(RDDs), 是一个可以并行操作, 有容错的数据集合

    • RDDs 可以通过引用外部存储系统的数据集创建(如HDFS, HBase), 或者通过现有的 RDDs 转换得到
    • RDDs 抽象提供了 Java, Scala, Python 等语言的API
    • RDDs 简化了编程复杂性, 操作 RDDs 类似通过 Scala 或者 Java8 的 Streaming 操作本地数据集合

Spark SQL

  • Spark SQL 在 spark-core 基础之上带出了一个名为 DataSet 和 DataFrame 的数据抽象化的概念
  • Spark SQL 提供了在 Dataset 和 DataFrame 之上执行 SQL 的能力
  • Spark SQL 提供了 DSL, 可以通过 Scala, Java, Python 等语言操作 DataSet 和 DataFrame
  • 它还支持使用 JDBC/ODBC 服务器操作 SQL 语言

Spark Streaming

  • Spark Streaming 充分利用 spark-core 的快速调度能力来运行流分析
  • 它截取小批量的数据并可以对之运行 RDD Transformation
  • 它提供了在同一个程序中同时使用流分析和批量分析的能力

MLlib

  • MLlib 是 Spark 上分布式机器学习的框架. Spark分布式内存的架构 比 Hadoop磁盘式 的 Apache Mahout 快上 10 倍, 扩展性也非常优良
  • MLlib 可以使用许多常见的机器学习和统计算法, 简化大规模机器学习
  • 汇总统计, 相关性, 分层抽样, 假设检定, 随即数据生成
  • 支持向量机, 回归, 线性回归, 逻辑回归, 决策树, 朴素贝叶斯
  • 协同过滤, ALS
  • K-means
  • SVD奇异值分解, PCA主成分分析
  • TF-IDF, Word2Vec, StandardScaler
  • SGD随机梯度下降, L-BFGS

GraphX

GraphX 是分布式图计算框架, 提供了一组可以表达图计算的 API, GraphX 还对这种抽象化提供了优化运行

总结

Spark 提供了 批处理(RDDs), 结构化查询(DataFrame), 流计算(SparkStreaming), 机器学习(MLlib), 图计算(GraphX) 等组件
这些组件均是依托于通用的计算引擎 RDDs 而构建出的, 所以 spark-core 的 RDDs 是整个 Spark 的基础

1.4. Spark和Hadoop的异同

HadoopSpark
类型基础平台, 包含计算, 存储, 调度分布式计算工具
场景大规模数据集上的批处理迭代计算, 交互式计算, 流计算
延迟
易用性API 较为底层, 算法适应性差API 较为顶层, 方便使用
价格对机器要求低, 便宜对内存有要求, 相对较贵

2.Spark集群的搭建

目标

从 Spark 的集群架构开始, 理解分布式环境, 以及 Spark 的运行原理
理解 Spark 的集群搭建, 包括高可用的搭建方式

2.1. Spark 集群结构

目标

通过应用运行流程, 理解分布式调度的基础概念

Spark 自身是没有集群管理工具的, 但是如果想要管理数以千计台机器的集群, 没有一个集群管理工具还不太现实, 所以 Spark 可以借助外部的集群工具来进行管理

整个流程就是使用 Spark 的 Client 提交任务, 找到集群管理工具申请资源, 后将计算任务分发到集群中运行

在这里插入图片描述名词解释
Driver

  • 该进程调用 Spark 程序的 main 方法, 并且启动 SparkContext

Cluster Manager

  • 该进程负责和外部集群工具打交道, 申请或释放集群资源

Worker

  • 该进程是一个守护进程, 负责启动和管理 Executor

Executor

  • 该进程是一个JVM虚拟机, 负责运行 Spark Task

运行一个 Spark 程序大致经历如下几个步骤

  • 启动 Drive, 创建 SparkContext
  • Client 提交程序给 Drive, Drive 向 Cluster Manager 申请集群资源
  • 资源申请完毕, 在 Worker 中启动 Executor
  • Driver 将程序转化为 Tasks, 分发给 Executor 执行

问题一: Spark 程序可以运行在什么地方?

  • 集群: 一组协同工作的计算机, 通常表现的好像是一台计算机一样, 所运行的任务由软件来控制和调度
  • 集群管理工具: 调度任务到集群的软件
  • 常见的集群管理工具: Hadoop Yarn, Apache Mesos, Kubernetes

Spark 可以将任务运行在两种模式下:

  • 单机, 使用线程模拟并行来运行程序
  • 集群, 使用集群管理器来和不同类型的集群交互, 将任务运行在集群中

Spark 可以使用的集群管理工具有:

  • Spark Standalone
  • Hadoop Yarn
  • Apache Mesos
  • Kubernetes

问题二: Driver 和 Worker 什么时候被启动?

在这里插入图片描述

  • Standalone 集群中, 分为两个角色: Master 和 Slave, 而 Slave 就是 Worker, 所以在 Standalone 集群中, 启动之初就会创建固定数量的 Worker
  • Driver 的启动分为两种模式: Client 和 Cluster. 在 Client 模式下, Driver 运行在 Client 端, 在 Client 启动的时候被启动. 在 Cluster 模式下, Driver 运行在某个 Worker 中, 随着应用的提交而启动

在这里插入图片描述

  • 在 Yarn 集群模式下, 也依然分为 Client 模式和 Cluster 模式, 较新的版本中已经逐渐在废弃 Client 模式了, 所以上图所示为 Cluster 模式
  • 如果要在 Yarn 中运行 Spark 程序, 首先会和 RM 交互, 开启 ApplicationMaster, 其中运行了 Driver, Driver创建基础环境后, 会由 RM 提供对应的容器, 运行 Executor, Executor会反向向 Driver 反向注册自己, 并申请 Tasks 执行
  • 在后续的 Spark 任务调度部分, 会更详细介绍

总结

Master 负责总控, 调度, 管理和协调 Worker, 保留资源状况等
Slave 对应 Worker 节点, 用于启动 Executor 执行 Tasks, 定期向 Master汇报
Driver 运行在 Client 或者 Slave(Worker), 默认运行在 Slave(Worker)

2.2. Spark 集群搭建

目标

大致了解 Spark Standalone 集群搭建的过程
这个部分的目的是搭建一套用于测试和学习的集群, 实际的工作中可能集群环境会更复杂一些

Table 1. 集群组件

Bigdata01Bigdata02Bigdata03
MasterSlaveSlave
History Server

Step 1 下载和解压

此步骤假设大家的 Hadoop 集群已经能够无碍的运行, 并且 Linux 的防火墙和 SELinux 已经关闭, 时钟也已经同步, 如果还没有, 请参考 Hadoop 集群搭建部分, 完成以上三件事
下载 Spark 安装包, 下载时候选择对应的 Hadoop 版本

1 下载 Spark
Spark下载地址

解压并拷贝到opt/softwore

2 解压 Spark 安装包

tar -zxvf spark-2.4.6-bin-hadoop2.7.tgz -C /opt/module

3 重命名spark

mv spark-2.4.6-bin-hadoop2.7 spark

4 修改配置文件spark-env.sh, 以指定运行参数

进入配置目录, 并复制一份新的配置文件, 以供在此基础之上进行修改

cd /opt/module/spark/conf
cp spark-env.sh.template spark-env.sh
vim spark-env.sh

#将以下内容复制进配置文件末尾

# 指定 Java Home
export JAVA_HOME=/opt/module/jdk1.8.0

# 指定 Spark Master 地址
export SPARK_MASTER_HOST=Bigdata01
export SPARK_MASTER_PORT=7077

Step 2 配置

1 修改配置文件 slaves, 以指定从节点为止, 从在使用 sbin/start-all.sh 启动集群的时候, 可以一键启动整个集群所有的 Worker

进入配置目录, 并复制一份新的配置文件, 以供在此基础之上进行修改

cd /opt/module/spark/conf
cp slaves.template slaves
vi slaves

# 配置所有从节点的地址

Bigdata02
Bigdata03

2 配置 HistoryServer

默认情况下, Spark 程序运行完毕后, 就无法再查看运行记录的 Web UI 了, 通过 HistoryServer 可以提供一个服务, 通过读取日志文件, 使得我们可以在程序运行结束后, 依然能够查看运行过程

复制 spark-defaults.conf, 以供修改

cd /opt/module/spark/conf
cp spark-defaults.conf.template spark-defaults.conf
vi spark-defaults.conf
#将以下内容复制到`spark-defaults.conf`末尾处, 通过这段配置, 可以指定 Spark 将日志输入到 HDFS 中

spark.eventLog.enabled  true
spark.eventLog.dir      hdfs://Bigdata:9000/spark_log
spark.eventLog.compress true

将以下内容复制到spark-env.sh的末尾, 配置 HistoryServer 启动参数, 使得 HistoryServer 在启动的时候读取 HDFS 中写入的 Spark 日志

#指定 Spark History 运行参数
export SPARK_HISTORY_OPTS="-Dspark.history.ui.port=4000 -Dspark.history.retainedApplications=3 -Dspark.history.fs.logDirectory=hdfs://Bigdata01:9000/spark_log"

为 Spark 创建 HDFS 中的日志目录

hdfs dfs -mkdir -p /spark_log

Step 3 分发和运行

将 Spark 安装包分发给集群中其它机器

cd /opt/module
scp -r spark root@Bigdata02:$PWD
scp -r spark root@Bigdata03:$PWD

启动 Spark Master 和 Slaves, 以及 HistoryServer

cd /opt/module/spark
sbin/start-all.sh
sbin/start-history-server.sh

目标
Spark 的集群搭建大致有如下几个步骤

  • 下载和解压 Spark
  • 配置 Spark 的所有从节点位置
  • 配置 Spark History server 以便于随时查看 Spark 应用的运行历史
  • 分发和运行 Spark 集群

2.3. Spark 集群高可用搭建

目标

简要了解如何使用 Zookeeper 帮助 Spark Standalone 高可用

对于 Spark Standalone 集群来说, 当 Worker 调度出现问题的时候, 会自动的弹性容错, 将出错的 Task 调度到其它 Worker 执行

但是对于 Master 来说, 是会出现单点失败的, 为了避免可能出现的单点失败问题, Spark 提供了两种方式满足高可用

  • 使用 Zookeeper 实现 Masters 的主备切换
  • 使用文件系统做主备切换

Step 1 停止 Spark 集群

cd /opt/module/spark
sbin/stop-all.sh

Step 2 修改配置文件, 增加 Spark 运行时参数, 从而指定 Zookeeper 的位置

1 进入 spark-env.sh 所在目录, 打开 vim 编辑

cd /opt/module/spark/conf
vim spark-env.sh

2 编辑 spark-env.sh, 添加 Spark 启动参数, 并去掉 SPARK_MASTER_HOST 地址

# 指定 Java Home
export JAVA_HOME=/opt/module/jdk1.8.0_141

# 指定 Spark Master 地址
# export SPARK_MASTER_HOST=Bigdata01
export SPARK_MASTER_PORT=7077

# 指定 Spark History 运行参数
export SPARK_HISTORY_OPTS="-Dspark.history.ui.port=4000 -Dspark.history.retainedApplications=3 -Dspark.history.fs.logDirectory=hdfs://Bigdata01:9000/spark_log"

# 指定 Spark 运行时参数
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER -Dspark.deploy.zookeeper.url=Bigdata01:2181,Bigdata02:2181,Bigdata03:2181 -Dspark.deploy.zookeeper.dir=/spark"

Step 3 分发配置文件到整个集群

cd /opt/module/spark/conf
scp -r spark-env.sh Bigdata02:$PWD
scp -r spark-env.sh Bigdata03:$PWD

Step 4 启动

在 Bigdata01上启动整个集群

cd /opt/module/spark
sbin/start-all.sh
sbin/start-history-server.sh

在 node02 上单独再启动一个 Master

cd /opt/module/spark
sbin/start-master.sh

如果关闭一个, 则另外一个成为ALIVE, 但是这个过程可能要持续两分钟左右, 需要耐心等待

在 Bigdata01中执行如下指令

cd /opt/module/spark
sbin/stop-master.sh

Spark HA 选举
Spark HA 的 Leader 选举使用了一个叫做 Curator 的 Zookeeper 客户端来进行
Zookeeper 是一个分布式强一致性的协调服务, Zookeeper 最基本的一个保证是: 如果多个节点同时创建一个 ZNode, 只有一个能够成功创建. 这个做法的本质使用的是 Zookeeper 的 ZAB 协议, 能够在分布式环境下达成一致.

附录:Spark各服务端口

Serviceport
Master WebUIBigdata01:8080
Worker WebUIBigdata01:8081
History ServerBigdata01:4000

2.4. 第一个应用的运行

目标

从示例应用运行中理解 Spark 应用的运行流程

流程
Step 1 进入 Spark 安装目录中

cd /opt/module/spark

Step 2 运行 Spark 示例任务 (普通)

bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://Bigdata01:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
./examples/jars/spark-examples_2.11-2.4.6.jar \
100

运行 Spark 示例任务 (高可用)

bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://Bigdata01:7077,Bigdata02:7077,Bigdata03:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
./examples/jars/spark-examples_2.11-2.4.6.jar \
100

3.Spark入门

目标

通过理解 Spark 小案例, 来理解 Spark 应用
理解编写 Spark 程序的两种常见方式
1,spark-shell
2,spark-submit

Spark 官方提供了两种方式编写代码, 都比较重要, 分别如下

  • spark-shell

    Spark shell 是 Spark 提供的一个基于 Scala 语言的交互式解释器, 类似于 Scala 提供的交互式解释器, Spark shell 也可以直接在 Shell 中编写代码执行
    这种方式也比较重要, 因为一般的数据分析任务可能需要探索着进行, 不是一蹴而就的, 使用 Spark shell 先进行探索, 当代码稳定以后, 使用独立应用的方式来提交任务, 这样是一个比较常见的流程

  • spark-submit
    Spark submit 是一个命令, 用于提交 Scala 编写的基于 Spark 框架, 这种提交方式常用作于在集群中运行任务

3.1. Spark shell 的方式编写 WordCount

概要

在初始阶段工作可以全部使用 Spark shell 完成, 它可以加快原型开发, 使得迭代更快, 很快就能看到想法的结果. 但是随着项目规模越来越大, 这种方式不利于代码维护, 所以可以编写独立应用. 一般情况下, 在探索阶段使用 Spark shell, 在最终使用独立应用的方式编写代码并使用 Maven 打包上线运行

接下来使用 Spark shell 的方式编写一个 WordCount

Spark shell 简介
启动 Spark shell
进入 Spark 安装目录后执行 spark-shell --master master 就可以提交Spark 任务

Spark shell 的原理是把每一行 Scala 代码编译成类, 最终交由 Spark 执行

Master地址的设置
Master 的地址可以有如下几种设置方式

3 master

地址解释
local[N]使用 N 条 Worker 线程在本地运行
spark://host:port在 Spark standalone 中运行, 指定 Spark 集群的 Master 地址, 端口默认为 7077
mesos://host:port在 Apache Mesos 中运行, 指定 Mesos 的地址
yarn在 Yarn 中运行, Yarn 的地址由环境变量 HADOOP_CONF_DIR 来指定

Step 1 准备文件
在 Bigdata01 中创建文件 /opt/module/spark/wordcount.txt

hadoop	spark	flink
java	python	R
hbase	kafka	hive

Step 2 启动 Spark shell

cd /opt/module/spark
bin/spark-shell --master local[2]

Step 3 执行如下代码

scala> val sourceRdd = sc.textFile("file:///opt/module/spark/wordcount.txt")
sourceRdd: org.apache.spark.rdd.RDD[String] =file:///opt/module/spark/wordcount.txt MapPartitionsRDD[1] at textFile at <console>:24

scala> val flattenCountRdd = sourceRdd.flatMap(_.split(" ")).map((_, 1))
flattenCountRdd: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[3] at map at <console>:26

scala> val aggCountRdd = flattenCountRdd.reduceByKey(_ + _)
aggCountRdd: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[4] at reduceByKey at <console>:28

scala> val result = aggCountRdd.collect
result: Array[(String, Int)] = Array((hadoop,1), (spark,1), (flink,1),(hive,1),(kafka,1),(hbase,1),(python,1),(R,1),(java,1))

上述代码中 sc 变量指的是 SparkContext, 是 Spark 程序的上下文和入口

正常情况下我们需要自己创建, 但是如果使用 Spark shell 的话, Spark shell 会帮助我们创建, 并且以变量 sc 的形式提供给我们调用

运行流程
在这里插入图片描述

  1. flatMap(_.split(" ")) 将数据转为数组的形式, 并展平为多个数据
  2. map(_, 1) 将数据转换为元组的形式
  3. reduceByKey(_ + _) 计算每个 Key 出现的次数

总结

使用 Spark shell 可以快速验证想法
Spark 框架下的代码非常类似 Scala 的函数式调用

3.2. 读取 HDFS 上的文件

目标

理解 Spark 访问 HDFS 的两种方式

Step 1 上传文件到 HDFS 中

在这里插入代码片
cd /opt/module/spark
hdfs dfs -mkdir /input
hdfs dfs -put wordcount.txt /input/

Step 2 在 Spark shell 中访问 HDFS

val sourceRdd = sc.textFile("hdfs://Bigdata01:9000/input/wordcount.txt")
val flattenCountRdd = sourceRdd.flatMap(_.split(" ")).map((_, 1))
val aggCountRdd = flattenCountRdd.reduceByKey(_ + _)
val result = aggCountRdd.collect

3.3. 编写独立应用提交 Spark 任务

目标

理解如何编写 Spark 独立应用
理解 WordCount 的代码流程

Step 1 创建工程

Step 2 编写 Maven 配置文件 pom.xml
工程根目录下增加文件 pom.xml

添加以下内容

   <properties>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <encoding>UTF-8</encoding>
        <scala.version>2.11.8</scala.version>
        <spark.version>2.4.6</spark.version>
        <hadoop.version>2.7.2</hadoop.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>${scala.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-hive_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-streaming-flume_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>0.11.0.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/log4j/apache-log4j-extras -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>apache-log4j-extras</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.1.41</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.spark/spark-mllib -->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-mllib_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>


    </dependencies>

    <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.2.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <args>
                                <!--<arg>-make:transitive</arg>-->
                                <arg>-dependencyfile</arg>
                                <arg>${project.build.directory}/.scala_dependencies</arg>
                            </args>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.spark.wordcount.WorkCount</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Step 3 编写代码

object WordCounts {

  def main(args: Array[String]): Unit = {
    // 1. 创建 Spark Context
    val conf = new SparkConf().setMaster("local[2]")
    val sc: SparkContext = new SparkContext(conf)

    // 2. 读取文件并计算词频
    val source: RDD[String] = sc.textFile("hdfs://Bigdata01:9000/input/wordcount.txt", 2)
    val words: RDD[String] = source.flatMap { line => line.split(" ") }
    val wordsTuple: RDD[(String, Int)] = words.map { word => (word, 1) }
    val wordsCount: RDD[(String, Int)] = wordsTuple.reduceByKey { (x, y) => x + y }

    // 3. 查看执行结果
    println(wordsCount.collect)
  }
}

Step 4 运行

运行 Spark 独立应用大致有两种方式, 一种是直接在 IDEA 中调试, 另一种是可以在提交至 Spark 集群中运行, 而 Spark 又支持多种集群, 不同的集群有不同的运行方式

直接在 IDEA 中运行 Spark 程序

spark-submit 命令

spark-submit [options] <app jar> <app options>
  • app jar 程序 Jar 包
  • app options 程序 Main 方法传入的参数
  • options 提交应用的参数, 可以有如下选项

options 可选参数

参数解释
–master < url>同 Spark shell 的 Master, 可以是spark, yarn, mesos, kubernetes等 URL
–deploy-mode < client or cluster>Driver 运行位置, 可选 Client 和 Cluster, 分别对应运行在本地和集群(Worker)中
–class < class full name>Jar 中的 Class, 程序入口
–jars < dependencies path>依赖 Jar 包的位置
–driver-memory < memory size>Driver 程序运行所需要的内存, 默认 512M
–executor-memory < memory size>Executor 的内存大小, 默认 1G

提交到 Spark Standalone 集群中运行

bin/spark-submit --master spark://Bigdata01:7077 \
--class com.spark.wordcount.WorkCount \
original-spark-0.1.0.jar

结果 (original-spark-0.1.0.jar 让我重命名了print.jar)

[root@Bigdata01 spark]# bin/spark-submit --master spark://Bigdata01:7077 \
> --class com.spark.wordcount.WorkCount \
> ./print.jar
20/08/23 01:10:43 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
hadoop	spark	flink
java	python	R
hbase	kafka	hive

如何在任意目录执行 spark-submit 命令?
在 /etc/profile 中写入如下

export SPARK_HOME=/opt/module/spark/bin
export PATH=$PATH:$SPARK_HOM

执行 /etc/profile 使得配置生效

source /etc/profile

总结: 三种不同的运行方式

Spark shell

  • 作用

    • 一般用作于探索阶段, 通过 Spark shell 快速的探索数据规律
    • 当探索阶段结束后, 代码确定以后, 通过独立应用的形式上线运行
  • 功能

    • Spark shell 可以选择在集群模式下运行, 还是在线程模式下运行
    • Spark shell 是一个交互式的运行环境, 已经内置好了 SparkContext 和 SparkSession 对象, 可以直接使用
    • Spark shell 一般运行在集群中安装有 Spark client 的服务器中, 所以可以自有的访问 HDFS

本地运行

  • 作用
    • 在编写独立应用的时候, 每次都要提交到集群中还是不方便, 另外很多时候需要调试程序, 所以在 IDEA 中直接运行会比较方便, 无需打包上传了
  • 功能
    • 因为本地运行一般是在开发者的机器中运行, 而不是集群中, 所以很难直接使用 HDFS 等集群服务, 需要做一些本地配置, 用的比较少
    • 需要手动创建 SparkContext

集群运行

  • 作用

    • 正式环境下比较多见, 独立应用编写好以后, 打包上传到集群中, 使用spark-submit来运行, 可以完整的使用集群资源
  • 功能

    • 同时在集群中通过spark-submit来运行程序也可以选择是用线程模式还是集群模式
    • 集群中运行是全功能的, HDFS 的访问, Hive 的访问都比较方便
    • 需要手动创建 SparkContext
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值