大数据(10):Spark

一、什么是 Spark

spark

用 Spark 官网 的话说,Spark 用于大规模数据分析的统一引擎;是一个多语言引擎,用于在单节点机器或集群上执行数据工程、数据科学和机器学习。

它是由加州大学伯克利分校 AMP 实验室开发的通用内存并行计算框架,用来构建大型的、低延迟的数据分析应用程序。它扩展了广泛使用的 MapReduce 计算模型。高效的支撑更多计算模式,包括交互式查询和流处理。

Spark 的一个主要特点是能够在内存中进行计算,及时依赖磁盘进行复杂的运算,Spark 依然比 MapReduce 更加高效。

二、Spark 与 MR

Hadoop 的 MR 框架和 Spark 框架都是数据处理框架。

那么我们在使用时如何选择呢?

Hadoop 的 MR 框架设计的初衷是一次性数据计算,所谓的一次性数据计算,就是框架在处理的时候,会从存储设备中读取数据,进行逻辑操作,然后将处理的结果重新存储到介质中。

而Spark框架把数据处理的中间结果放入内存中,为下一次的计算提供了便利。

Spark 与 MR

Hadoop MapReduce 其设计初衷并不是为了满足循环迭代式数据流处理,因此在多并行运行的数据可复用场景(如:机器学习、图挖掘算法、交互式数据挖掘算法)中存在诸多计算效率等问题。

Spark 应运而生,Spark 就是在 MapReduce 基础上,利用其计算过程的优化,从而大大加快了数据分析、挖掘的运行和读写速度,并将计算单元缩小到更适合并行计算和重复使用的 RDD 计算模型。

它的核心技术是 弹性分布式数据集(Resilient Distributed Datasets,RDD),提供了比 MapReduce 丰富的模型,可以快速在内存中对数据集进行多次迭代,来支持复杂的数据挖掘算法和图形计算算法。

根本差异是多个作业之间的数据通信问题 : Spark 多个作业之间数据通信是基于内存,而 Hadoop 是基于磁盘。

可以看出在绝大多数的数据计算场景中,Spark 确实会比 MapReduce更有优势。但是 Spark 是基于内存的,所以在实际的生产环境中,由于内存的限制,可能会由于内存资源不够导致 Job 执行失败。此时, MapReduce 其实是一个更好的选择,所以 Spark并不能完全替代 MR。

三、Spark 核心模块

Spark 核心模块
  • Spark Core
    提供了 Spark 最基础与最核心的功能,Spark 其他的功能如:Spark SQL,Spark Streaming,GraphX,MLlib 都是在 Spark Core 的基础上进行扩展的

  • Spark SQL
    是 Spark 用来操作结构化数据的组件。通过 Spark SQL,用户可以使用 SQL 或者 Apache Hive 版本的 SQL 方言(HQL)来查询数据。

一个新的产品,它为了让开发人员他们更方便去使用,往往都会把它集成到一些通用的这个技术上面去,比如说像 Flink 也有 SQL,目的就是为了让大家不需要去学习额外的语法规则,尽量让你可以无缝地去衔接。

  • Spark Streaming
    是 Spark 平台上针对实时数据进行流式计算的组件,提供了丰富的处理数据流的 API。

  • Spark MLlib
    是 Spark 提供的一个机器学习算法库。MLlib 不仅提供了模型评估、数据导入等额外的功能,还提供了一些更底层的机器学习原语。

  • Spark GraphX
    GraphX 是 Spark 面向图计算提供的框架与算法库。图计算的数据集跟我们常见的不一样,像我们现在处理的数据都是基于二维表的,是这种structure的,就是说它的结构是非常明确的吧,像图形数据级呢,它往往是网状数据集,它的结构是环形的这种网状的数据集。

四、下载与安装

1、在 Spark 官网 找到对应版本下载

如果是用 Mac 电脑体验一下,也可以直接用 brew 安装

$ brew install apache-spark

2、配置环境变量
[~/.bash_profile]

export SPARK_HOME=/opt/homebrew/Cellar/apache-spark/3.3.0/libexec
export PATH=$SPARK_HOME/bin:$SPARK_HOME/sbin:$PATH

3、使环境变量生效

$ source ~/.bash_profile

4、进入 spark 命令行

$ ./spark-shell

5、启动成功

6、编写一个 person.txt 文件并上传到 HDFS 上的 spark 目录下

$ hadoop fs -mkdir -p /spark
$ hadoop fs -put person.txt /spark

文件内容如下

hello world tom
tom hello world

在spark shell中用scala语言编写spark程序

scala> sc.textFile("hdfs://localhost/spark/person.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
res: Array[(String, Int)] = Array((tom,2), (hello,2), (world,2)) 

其中:

  • sc 是 SparkContext 对象,该对象是提交 spark 程序的入口
  • textFile() 是读取数据文件
  • flatMap(_.split(" ")) 先把每行按空格分割,再map再压平
  • map((_,1)) 将单词和1构成元组
  • reduceByKey(+) 按照key进行reduce,并将value累加

四、RDD

RDD(Resilient Distributed Dataset)弹性分布式数据集,是 Spark 中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。

弹性分布式数据集,虽然每个字都认识,但放到一起就不知道是什么意思了。

首先看 Distributed Dataset 分布式数据集,这个好理解:
就是把一份数据是放在不同的节点,比如我们有一份 100G 的数据,我们把这个数据分散在各个节点保存,这个叫分布式数据集。

但是第一个单词 Resilient ,这个弹性的怎么来理解,什么叫弹性的?

一个分布式的数据集,在物理上是多个数据块,但在逻辑上是一个整体,这个整体我们给他一个名字,就把他叫 RDD1,RDD1 就等于这个 100G 的数据,当然,如果内存放不下会把数据放磁盘中,程序进行自动的存储切换。

我们可以对 RDD1 进行许多操作,比如做 map 操作,形成 RDD2,然后再做 filter 操作,形成 RDD3 等等,会做很多操作,后面可能一直到 RDD50,在 RDD50 的时候呢,我们要去做下一步的业务逻辑的处理,例如 join RDD2,那么这个时候问题来了。

spark 是基于内存的,它生成的一些结果在内存中是会慢慢被丢掉,因为内存肯定要释放出来,不能把两个小时前的数据还保留在内存中,肯定把它丢弃掉,被释放。

如果后面的数据集,需要用到前面的数据集,而前面的数据集已经在内存中被丢弃了怎么办?

这个时候呢,spark 会通过 DAG 重新计算出来,不需要人为的干预,自动化的,这就是 Resilient。

这个就表示就是对第一个单词的解释,就是 Resilient,他是这种弹性的分布式数据集,当数据在内存中被被解除内存了,而之后又需要用到的时候,spark 会自动重新计算出来。

但是重新计算是很消耗资源到,因此 RDD 还提供了 persistcache 方法。通这两个方法可以将前面的计算结果缓存,但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 时,该 RDD 将会被缓存在计算节点的内存中,并供后面重用。

五、DAG

DAG 是 Directed Acyclic Graph(有向无环图)的简称,反映RDD之间的依赖关系;

Node节点:rdd的分区
Edge边:基于数据进行变换
Acyclic:变换后到数据无法回到变换之前
Direct:数据变化会改变数据分区状态

spark 架构

1、我们提交一个任务,任务就叫Application
2、初始化程序的入口 SparkContext,
  2.1 初始化 DAG Scheduler
  2.2 初始化 Task Scheduler
3、Task Scheduler 向 master去进行注册并申请资源
4、Master 根据 SparkContext 的资源申请要求和 Worker 心跳周期内报告的信息决定在哪个 Worker 上分配资源,然后在该 Worker 上获取资源,
5、Worker 向 Driver(SparkContext) 注册,这样 Driver 就知道哪些 Executor 为他进行服务了。到这个时候其实我们的初始化过程基本完成了,我们开始执行 transformation 的代码,但是代码并不会真正的运行,直到我们遇到一个 action 操作
6、SparkContext将Applicaiton代码发送给Worker;并且SparkContext解析Applicaiton代码,构建DAG图。

SparkContext

Transformation

主要做的是就是将一个已有的 RDD 转化另外一个 RDD。Transformation 具有延迟加载的特性。Transformation 算子的代码不会真正被执行,即使代码有误,也不会报错。只有当我们的程序里面遇到一个 action 算子的时候,代码才会真正的被执行。

常见的 Transformation 有 map()filter()flatMap()mapPartitions()groupByKey()reduceByKey()

Action

触发代码的运行,我们一段 spark 代码里面至少需要有一个 action 操作。
常见的 action 操作有:reduce()collect()count()take() 等。

六、Spark SQL

Spark SQL 是 Spark 用于处理结构化数据的一个模块,那么这里我们首先要知道它处理的数据都是结构化的,那么结构化的数据有哪些呢,最典型的就是这种基于二维表存储的数据吧,还有 CSV。

它不同于 RDD,Spark SQL 提供了更多关于什么数据和执行计算计算的结构信息,Spark SQL 内部使用这些额外的信息呢,来提供一些优化操作,也就是说用 Spark SQL 的时候,比用 Spark RDD 的性能要更好,速度快了很多倍。

有几种方式可以与 Spark SQL进行交互,其中我们可以用使用 SQL 语句,再一个可以使用 data set API 来写程序。无论你使用 API 操作,还是使用 SQL 语句操作,它底层的执行模式是一样的,在性能上是没有任何区别的。

七、Spark SQL 基本使用

1、读取 json 数据

增加 maven 依赖


    org.apache.spark
    spark-core_2.13
    3.3.0



    org.apache.spark
    spark-sql_2.13
    3.3.0

读取 hdfs 上 person.json 文件

private static void sparkSQL() {
    SparkSession spark = SparkSession.builder().appName(SparkTest.class.getSimpleName()).master("local").getOrCreate();
    Dataset json = spark.read().json("hdfs://localhost/spark/person.json");

    json.show();
    json.select("name").show();
    json.filter("age > 1").show();
    // 创建视图
    json.createOrReplaceTempView("person");
    spark.sql("select * from person where age > 1").show();
}

输出结果

+---+----+
|age|name|
+---+----+
|  1| tom|
|  2|toms|
+---+----+

+----+
|name|
+----+
| tom|
|toms|
+----+

+---+----+
|age|name|
+---+----+
|  2|toms|
+---+----+

+---+----+
|age|name|
+---+----+
|  2|toms|
+---+----+

2、通过 jdbc 协议读取 mysql 数据

增加 maven 依赖


    mysql
    mysql-connector-java
    8.0.28

连接数据库,读取数据

private static void jdbdTest() {
    SparkSession spark = SparkSession.builder().appName(SparkTest.class.getSimpleName()).master("local").getOrCreate();
    String url = "jdbc:mysql://localhost:4000/test";
    Properties properties = new Properties();
    properties.put("url", url);
    properties.put("user", "root");
    properties.put("password", "12345678");
    Dataset jdbc = spark.read().jdbc(url, "test", properties);
    jdbc.createOrReplaceTempView("test");
    spark.sql("select * from test").show();
}

3、读取 hive 数据

增加 maven 依赖


    org.apache.spark
    spark-hive_2.13
    3.3.0

hive 数据读取需增加 enableHiveSupport()

private static void hiveTest() {
    SparkSession spark = SparkSession.builder().appName(SparkTest.class.getSimpleName()).master("local").enableHiveSupport().getOrCreate();

    spark.sql("show databases").show();
    spark.sql("use myhive").show();
    spark.sql("select t.word, count(*) from ((select explode(split(line, ' ')) as word from doc) as t) group by t.word;").show();
}

你可能感兴趣的:(大数据(10):Spark)