Spark之基础知识

一、概述

1、定义

        Spark 是一种基于内存的快速、通用、可扩展的大数据分析计算引擎。

2、Spark和Hadoop的联系和区别

(1)联系:

        Hadoop MapReduce 由于其设计初衷并不是为了满足循环迭代式数据流处理,因此在多
并行运行的数据可复用场景(如:机器学习、图挖掘算法、交互式数据挖掘算法)中存
在诸多计算效率等问题。所以 Spark 应运而生, Spark 就是在传统的 MapReduce 计算框
架的基础上,利用其计算过程的优化,从而大大加快了数据分析、挖掘的运行和读写速
度,并将计算单元缩小到更适合并行计算和重复使用的 RDD 计算模型。

(2)区别:

        Spark 和 Hadoop 的根本差异是多个作业之间的数据通信问题 : Spark 多个作业之间数据
通信是基于内存(Memory),而 Hadoop 是基于磁盘(File)。
        一次性数据计算时,框架在处理数据的时候,会从存储设备中读取数据进行逻辑操作,然后将处理的结果重新存储到介质中,那么MapReduce(图1)和Spark(图2)两者是如何做的呢?

图1 MapReduce框架处理流程

 

图2 Spark框架处理流程 

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

3、核心模块

  • Spark Core :Spark Core 中提供了 Spark 最基础与最核心的功能,Spark 其他的功能如:Spark SQL,Spark Streaming,GraphX, MLlib 都是在 Spark Core 的基础上进行扩展的
  • Spark SQL :Spark SQL 是 Spark 用来操作结构化数据的组件。通过 Spark SQL,用户可以使用 SQL或者 Apache Hive 版本的 SQL 方言(HQL)来查询数据。
  • Spark Streaming:Spark Streaming 是 Spark 平台上针对实时数据进行流式计算的组件,提供了丰富的处理数据流的 API。
  • Spark MLlib:MLlib 是 Spark 提供的一个机器学习算法库。MLlib 不仅提供了模型评估、数据导入等额外的功能,还提供了一些更底层的机器学习原语。
  • Spark GraphX:GraphX Spark 面向图计算提供的框架与算法库。

二、运行环境

        Spark 作为一个数据处理框架和计算引擎,被设计在所有常见的集群环境中运行 , 在国
内工作中主流的环境为 Yarn。

1、Yarn模式(重点)

        Spark 主 要是计算框架,而不是资源调度框架,所以本身提供的资源调度并不是它的强项,所以还是和其他专业的资源调度框架集成会更靠谱一些。分为五个阶段:解压缩文件、修改配置文件、启动HDFS及YARN集群、提交应用、配置历史服务器。
(1)解压缩文件:
         spark-3.0.0-bin-hadoop3.2.tgz 文件上传到 linux 并解压缩,放置在指定位置。
        
tar -zxvf spark-3.0.0-bin-hadoop3.2.tgz -C /opt/module
cd /opt/module 
mv spark-3.0.0-bin-hadoop3.2 spark-yarn

(2)修改配置文件:

        1) 修改 hadoop 配置文件 /opt/module/hadoop/etc/hadoop/yarn-site.xml, 并分发
   
<!--是否启动一个线程检查每个任务正使用的物理内存量,如果任务超出分配值,则直接将其杀掉,默认
是 true -->
<property>
 <name>yarn.nodemanager.pmem-check-enabled</name>
 <value>false</value>
</property>
<!--是否启动一个线程检查每个任务正使用的虚拟内存量,如果任务超出分配值,则直接将其杀掉,默认
是 true -->
<property>
 <name>yarn.nodemanager.vmem-check-enabled</name>
 <value>false</value>
</property>
        2) 修改 conf/spark-env.sh ,添加 JAVA_HOME YARN_CONF_DIR 配置
mv spark-env.sh.template spark-env.sh
。。。
export JAVA_HOME=/opt/module/jdk1.8.0_144
YARN_CONF_DIR=/opt/module/hadoop/etc/hadoop
(3)启动HDFS及YARN集群
(4)提交应用:
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode cluster \
./examples/jars/spark-examples_2.12-3.0.0.jar \
10

         查看 http://linux2:8088 页面,点击 History,查看历史页面

 (5)配置历史服务器:

        1) 修改 spark-defaults.conf.template 文件名为 spark-defaults.conf

mv spark-defaults.conf.template spark-defaults.conf
        2) 修改 spark-default.conf 文件,配置日志存储路径
spark.eventLog.enabled true
spark.eventLog.dir hdfs://linux1:8020/directory
注意:需要启动 hadoop 集群, HDFS 上的目录需要提前存在。
[root@linux1 hadoop]# sbin/start-dfs.sh
[root@linux1 hadoop]# hadoop fs -mkdir /directory

      3) 修改 spark-env.sh 文件, 添加日志配置

export SPARK_HISTORY_OPTS="
-Dspark.history.ui.port=18080 
-Dspark.history.fs.logDirectory=hdfs://linux1:8020/directory 
-Dspark.history.retainedApplications=30"

其中,参数 1 含义:WEB UI 访问的端口号为 18080。参数 2 含义:指定历史服务器日志存储路径。 参数 3 含义:指定保存 Application 历史记录的个数,如果超过这个值,旧的应用程序信息将被删除,这个是内存中的应用数,而不是页面上显示的应用数。

        4) 修改 spark-defaults.conf

spark.yarn.historyServer.address=linux1:18080
spark.history.ui.port=18080

        5) 启动历史服务

sbin/start-history-server.sh
        6) 重新提交应用
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
--deploy-mode client \
./examples/jars/spark-examples_2.12-3.0.0.jar \
10

        7) Web 页面查看日志:http://linux2:8088  

2、local本地模式

所谓的 Local 模式,就是不需 要其他任何节点资源就可以在本地执行 Spark 代码的环境,一般用于教学,调试,演示等之前在 IDEA 中运行代码的环境我们称之为开发环境,不太一样。分为五个阶段:解压缩文件、启动 Local 环境、命令行工具、退出本地模式、提交应用
(1)解压缩文件:
        将 spark-3.0.0-bin-hadoop3.2.tgz 文件上传到 Linux 并解压缩,放置在指定位置,路径中
不要包含中文或空格
tar -zxvf spark-3.0.0-bin-hadoop3.2.tgz -C /opt/module
cd /opt/module 
mv spark-3.0.0-bin-hadoop3.2 spark-local

(2)启动Local环境:

             1) 进入解压缩后的路径,执行如下指令
bin/spark-shell

         2) 启动成功后,可以输入网址进行 Web UI 监控页面访问

http://虚拟机地址:4040

 (3)命令行工具:

        在解压缩文件夹下的 data 目录中,添加 word.txt 文件。在命令行工具中执行如下代码指
令(和 IDEA 中代码简化版一致)
sc.textFile("data/word.txt").flatMap(_.split("")).map((_,1)).reduceByKey(_+_).collect

 (4)退出本地模式:

         按键 Ctrl+C 或输入 Scala 指令
:quit

(5)提交应用:

bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master local[2] \
./examples/jars/spark-examples_2.12-3.0.0.jar \
10
1) --class 表示要执行程序的主类, 此处可以更换为咱们自己写的应用程序
2) --master local[2] 部署模式,默认为本地模式,数字表示分配的虚拟 CPU 核数量
3) spark-examples_2.12-3.0.0.jar 运行的应用类所在的 jar 包, 实际使用时,可以设定为咱
们自己打的 jar
4) 数字 10 表示程序的入口参数,用于设定当前应用的任务数量

3、standalone模式

        只使用 Spark 自身节点运行的集群模式,也就是我们所谓的 独立部署(Standalone)模式。Spark Standalone 模式体现了经典的 master-slave 模式。

集群规划 :

分为七个阶段:解压缩文件、修改配置文件、启动集群、提交应用、提交参数说明、配置历史服务、配置高可用 

三、运行架构(重点)

1、核心组件

(1)Driver

        Spark 驱动器节点,用于执行 Spark 任务中的 main 方法,负责实际代码的执行工作。
实际上,我们无法准确地描述 Driver 的定义,因为在整个的编程过程中没有看到任何有关
Driver 的字眼。所以简单理解,所谓的 Driver 就是驱使整个应用运行起来的程序,也称之为Driver 类。
        Driver 在 Spark 作业执行时主要负责:
  • 将用户程序转化为作业( job
  • 通过 UI 展示查询运行情况
  • 跟踪 Executor 的执行情况
  • Executor 之间调度任务 (task)

(2)Executor

        Spark Executor 是集群中工作节点(Worker)中的一个 JVM 进程,负责在 Spark 作业 中运行具体任务(Task),任务彼此之间相互独立。Spark 应用启动时,Executor 节点被同时启动,并且始终伴随着整个 Spark 应用的生命周期而存在。如果有 Executor节点发生了 故障或崩溃,Spark 应用也可以继续执行,会将出错节点上的任务调度到其他 Executor 节点上继续运行。

        Executor 有两个核心功能:

  • 负责运行组成 Spark 应用的任务,并将结果返回给驱动器进程
  • 它们通过自身的块管理器( Block Manager )为用户程序中要求缓存的 RDD 提供内存
    式存储。 RDD 是直接缓存在 Executor 进程内的,因此任务可以在运行时充分利用缓存
    数据加速运算。

(3)Master&Worker

        Spark 集群的独立部署环境中,不需要依赖其他的资源调度框架,自身就实现了资源调度的功能,所以环境中还有其他两个核心组件:Master Worker,这里的 Master 是一个进程,主要负责资源的调度和分配,并进行集群的监控等职责,类似于 Yarn 环境中的 RM, 而 Worker呢,也是进程,一个 Worker 运行在集群中的一台服务器上,由 Master分配资源对数据进行并行的处理和计算,类似于Yarn 环境中 NM

(4)ApplicationMaster

        Hadoop 用户向 YARN 集群提交应用程序时 , 提交程序中应该包含 ApplicationMaster ,用
于向资源调度器申请执行任务的资源容器 Container ,运行用户自己的程序任务 job ,监控整
个任务的执行,跟踪整个任务的状态,处理任务失败等异常情况。
        说的简单点就是,ResourceManager (资源)和 Driver (计算)之间的解耦合靠的就是
ApplicationMaster

2、核心概念

(1)Executor与Core

        Spark Executor 是集群中运行在工作节点(Worker )中的一个 JVM 进程,是整个集群中
的专门用于计算的节点。在提交应用中,可以提供参数指定计算节点的个数,以及对应的资
源。这里的资源一般指的是工作节点 Executor 的内存大小和使用的虚拟 CPU 核( Core )数量。
应用程序相关启动参数如下:

 (2)并行度

        在分布式计算框架中一般都是多个任务同时执行,由于任务分布在不同的计算节点进行 计算,所以能够真正地实现多任务并行执行,记住,这里是并行,而不是并发。这里我们将 整个集群并行执行任务的数量称之为并行度。那么一个作业到底并行度是多少呢?这个取决于框架的默认配置。应用程序也可以在运行过程中动态修改。

(3)有向无环图

        这里所谓的有向无环图,并不是真正意义的图形,而是由 Spark 程序直接映射成的数据
流的高级抽象模型。简单理解就是将整个程序计算的执行过程用图形表示出来 , 这样更直观,
更便于理解,可以用于表示程序的拓扑结构。
        DAG( Directed Acyclic Graph )有向无环图是由点和线组成的拓扑图形,该图形具有方
向,不会闭环。

3、提交流程

        所谓的提交流程,其实就是我们开发人员根据需求写的应用程序通过 Spark 客户端提交
Spark 运行环境执行计算的流程。本文介绍的提交流程是基于 Yarn 环境的,总体的提交流程为下图,其中该图大体分为两个分支流程:向下的计算过程和向右的资源过程。

        Spark 应用程序提交到 Yarn 环境中执行的时候,一般会有两种部署执行的方式: Client
Cluster 两种模式主要区别在于: Driver 程序的运行节点位置。 工作中一般采用的是Cluster:
Cluster 模式将用于监控和调度的 Driver 模块启动在 Yarn 集群资源中执行。一般应用于实际生产环境。
提交的具体流程如图3:

     图3 提交具体细节 

  • YARN Cluster 模式下,任务提交后会和 ResourceManager 通讯申请启动 ApplicationMaster
  • 随后 ResourceManager 分配 container,在合适的 NodeManager 上启动ApplicationMaster 此时的 ApplicationMaster 就是 Driver
  • Driver 启动后向 ResourceManager 申请 Executor 内存,ResourceManager 接到 ApplicationMaster 的资源申请后会分配 container,然后在合适的 NodeManager 上启动 Executor 进程
  • Executor 进程启动后会向 Driver 反向注册,Executor 全部注册完成后 Driver 开始执行 main 函数,
  • 之后执行到 Action 算子时,触发一个 Job,并根据宽依赖开始划分 stage,每个 stage 成对应的 TaskSet,之后将 task 分发到各个 Executor 上执行。

四、核心编程

Spark 计算框架为了能够进行高并发和高吞吐的数据处理,封装了三大数据结构,用于
处理不同的应用场景。三大数据结构分别是:
  • RDD : 弹性分布式数据集
  • 累加器:分布式共享只写变量
  • 广播变量:分布式共享只读变量

1、RDD(重点)

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

(1)IO操作和shuffle

        介绍RDD前先介绍一下IO操作(图4)和shuffle(图5)。图4中的IO操作体现了装饰者的设计模式:

图4 IO操作 

        另一个是shuffle,首先shuffle的含义是:将数据根据指定的规则进行分组, 分区默认不变,但是数据会被 打乱重新组合,我们将这样的操作称之为 shuffle一个组的数据在一个分区中,但是并不是说一个分区中只有一个组 。在spark中,shuffle必须落盘,不能在内存中等待,会导致内存溢出,shuffle操作的性能非常低。
图5 shuffle

 (2)RDD数据处理方式

        RDD的数据处理方式如图6所示,可以看出,类似于IO流,也有装饰着设计模式。RDD的数据只有在调用collect方法时,才会真正执行业务逻辑操作。之前的封装全部都是功能的扩展。RDD是不保存数据的,但IO流会临时保存一部分数据。

 图6 RDD数据处理方式

RDD的特点包括:

  • 弹性:存储的弹性:内存与磁盘的自动切换; 容错的弹性:数据丢失可以自动恢复;计算的弹性:计算出错重试机制;分片的弹性:可根据需要重新分片
  • 分布式:数据存储在大数据集群不同节点上
  • 数据抽象: RDD 是一个抽象类,需要子类具体实现
  • 可分区、并行计算
  • 不可变: RDD 封装了计算逻辑,是不可以改变的,想要改变,只能产生新的 RDD ,在
    新的 RDD 里面封装计算逻辑
  • 数据集: RDD 封装了计算逻辑,并不保存数据​​​​​​​

    (3)RDD核心属性(5个)

    • 分区列表:RDD 数据结构中存在分区列表,用于执行任务时并行计算,是实现分布式计算的重要属性。数据之间无关联
    • 分区计算函数:Spark 在计算时,是使用分区函数对每一个分区进行计算。计算逻辑相同
    • RDD之间的依赖关系:RDD 是计算模型的封装,当需求中需要将多个计算模型进行组合时,就需要将多个 RDD 建立依赖关系
    • 分区器(可选):当数据为 KV 类型数据时,可以通过设定分区器自定义数据的分区
    • 首选位置(可选):计算数据时,可以根据计算节点的状态选择不同的节点位置进行计算。判断计算发送到哪个节点效率最优,移动数据不如移动计算

​​​​​​​

 (4)执行原理

        从计算的角度来讲,数据处理过程中需要计算资源(内存 & CPU )和计算模型(逻辑)。 执行时,需要将计算资源和计算模型进行协调和整合。
        Spark 框架在执行时,先申请资源,然后将应用程序的数据处理逻辑分解成一个一个的计算任务。然后将任务发到已经分配资源的计算节点上, 按照指定的计算模型进行数据计算。最后得到计算结果。
        RDD 是 Spark 框架中用于数据处理的核心模型,接下来我们看看,在 Yarn 环境中, RDD的工作原理:
        1) 启动 Yarn 集群环境

         2) Spark 通过申请资源创建调度节点和计算节点

         ​​​​​​​3) Spark 框架根据需求将计算逻辑根据分区划分成不同的任务

         4) 调度节点将任务根据计算节点状态发送到对应的计算节点进行计算

        从以上流程可以看出RDD 在整个流程中主要用于将逻辑进行封装,并生成 Task 发送给 Executor节点执行计算

(5)基础编程

         
        接下来我们就一起看看 Spark 框架中 RDD 是具体是如何进行数据处理的。
        1)RDD 创建
        在spark中创建RDD的方式有四种(一般用前两种较多):
  •  从集合(内存)中创建 RDD:从集合中创建 RDDSpark 主要提供了两个方法:parallelize 和makeRDD。从底层代码实现来讲,makeRDD 方法其实就是 parallelize 方法
  • 从外部存储(文件)创建 RDD:由外部存储系统的数据集创建RDD包括:本地的文件系统,所有 Hadoop 支持的数据集,比如 HDFS、HBase等
  • 从其他RDD 创建:主要是通过一个 RDD 运算完后,再产生新的 RDD
  • 直接创建RDD(new):使用new 的方式直接构造RDD,一般由Spark框架自身使用​​​​​​​     
         2) RDD 并行度与分区  
        默认情况下,Spark 可以将一个作业切分多个任务后,发送给 Executor 节点并行计算,而能
够并行计算的任务数量我们称之为并行度。这个数量可以在构建 RDD 时指定。记住,这里的并行执行的任务数量,并不是指的切分任务的数量,不要混淆了。
  • 读取内存数据时,数据可以按照并行度的设定进行数据的分区操作
  • ​​​​​​​读取文件数据时,数据是按照 Hadoop 文件读取的规则进行切片分区,而切片规则和数据读取的规则有些差异

        3)RDD 转换算子

     RDD转换算子是功能的补充和封装,将旧的RDD包装成新的RDD(map,flatMap)RDD根据数据处理方式的不同将算子整体上分为Value类型、双Value类型(指双源)和Key-Value类型

  • Value类型:map、mapPartitions、mapPartitionsWithIndex、flatMap、glom、groupBy、filter、sample、distinct、coalesce、reparation、sortBy等
  • 双Value类型:intersection、union、subtract、zip
  • Key-Value类型:partitionBy、reduceByKey、groupByKey、aggregateByKey、foldByKey、combineByKey、sortByKey、join、leftOuterJoin、cogroup等

其中reduceByKey和groupByKey的区别:

  • shuffle 的角度 reduceByKey groupByKey 都存在 shuffle 的操作,但是 reduceByKey
    可以在 shuffle 前对分区内相同 key 的数据进行预聚合( combine )功能,这样会减少落盘的
    数据量,而 groupByKey 只是进行分组,不存在数据量减少的问题, reduceByKey 性能比高。
  • 从功能的角度 reduceByKey 其实包含分组和聚合的功能。 GroupByKey 只能分组,不能聚
    合,所以在分组聚合的场合下,推荐使用 reduceByKey ,如果仅仅是分组而不需要聚合。那
    么还是只能使用 groupByKey
​​​​​​​

        4)行动算子  

        行动算子是触发任务和作业的执行(collect)

        reduce、collect、count、first、take、takeOrdered、aggregate、countByKey、save相关算子、fold、foreach

        5)RDD序列化

         闭包检查         

        从计算的角度, 算子以外的代码都是在 Driver 端执行, 算子里面的代码都是在 Executor 端执行。那么在 scala 的函数式编程中,就会导致算子内经常会用到算子外的数据,这样就 形成了闭包的效果,如果使用的算子外的数据无法序列化,就意味着无法传值给 Executor 端执行,就会发生错误,所以需要在执行任务计算前,检测闭包内的对象是否可以进行序列化,这个操作我们称之为闭包检测

        序列化属性

        从计算的角度, 算子以外的代码都是在 Driver 端执行, 算子里面的代码都是在 Executor端执行

        6)RDD依赖关系

        a:RDD依赖关系

         这里所谓的依赖关系,其实就是两个相邻 RDD之间的关系

        b:RDD血缘关系

        RDD血缘关系是指多个连续的RDD的依赖关系。因为RDD不保存数据,所以RDD为了提高容错性,需要将RDD之间的关系保存下来。一旦出现错误,可以根据血缘关系将数据源重新读取进行计算。

​​​​​​​ 

        c:RDD窄依赖

        窄依赖表示每一个父(上游)RDD Partition 最多被子(下游)RDD 的一个 Partition 使用, 窄依赖我们形象的比喻为独生子女。新的RDD的一个分区的数据依赖于旧的一个RDD分区的数据,这个依赖称为OneToOne依赖

 

        d:RDD宽依赖

        宽依赖表示同一个父(上游)RDD Partition 被多个子(下游) RDD Partition 依赖,会
引起 Shuffle,总结:宽依赖我们形象的比喻为多生。新的RDD的一个分区的数据依赖于旧的多个RDD分区的数据,这个依赖称为Shuffle依赖

         阶段和任务划分

        DAG(Directed Acyclic Graph)有向无环图是由点和线组成的拓扑图形,该图形具有方向,不会闭环。例如,DAG 记录了 RDD 的转换过程和任务的阶段。

        任务划分中分为:ApplicationJobStage Task

  • Application:初始化一个 SparkContext 即生成一个 Application
  • Job:一个 Action 算子就会生成一个 Job
  • StageStage 等于宽依赖(ShuffleDependency)的个数加 1。当RDD中存在shuffle依赖时,阶段会自动加1:阶段数量=shuffle的依赖数量+1
  • Task:一个 Stage 阶段中,最后一个 RDD(ResultStage只有一个,最后需要执行的阶段)的分区个数就是 Task 的个数。 任务的数量= 当前阶段中最后一个RDD的分区数量。

        阶段和任务划分具体图:

        ShuffleMapStage=>ShuffleMapTask            ResultStage=>ResultTask

        7)RDD持久化

        上图的问题是最后会出错,无法实现。因为RDD不存储数据,如果一个RDD需要重复使用,那么需要重新从头再次执行来获取数据。RDD对象可以重用,但是数据无法重用 

        RDD对象的持久化操作不一定是为了重用。在数据执行较长时,或数据比较重要的场合也可可以采用持久化操作。 

        缓存、检查点和persist的区别:

  • RDD Cache缓存:将数据临时存储在内存中进行数据重用;会在血缘关系中添加新的依赖,一旦出现问题,可以重头读取数据
  • CheckPoint检查点:将数据长久地保存在磁盘文件中进行数据重用;涉及到磁盘IO,性能较低,但数据安全;为了保证数据安全,所以一般情况下,会独立执行作业;为了能够提高效率,一般情况下,是需要和Cache联合使用;执行过程中,会切断血缘关系。重新建立新的血缘关系;checkpoint等同于改变数据源
  • persist:将数据临时存储在磁盘文件中进行数据重用;涉及到磁盘IO,性能较低,但数据安全;如果作业执行完毕,临时保存的数据文件将会丢失

        8)RDD 分区器

        Spark 目前支持 Hash 分区和 Range 分区,和用户自定义分区。Hash 分区为当前的默认 分区。分区器直接决定了 RDD 中分区的个数、RDD 中每条数据经过 Shuffle 后进入哪个分区,进而决定了 Reduce 的个数。

  • 只有 Key-Value 类型的 RDD 才有分区器,非 Key-Value 类型的 RDD 分区的值是 None
  •  每个 RDD 的分区 ID 范围:0 ~ (numPartitions - 1),决定这个值是属于那个分区的。

        Hash 分区:对于给定的 key,计算其 hashCode,并除以分区个数取余​​​​​​​ 

        Range 分区:将一定范围内的数据映射到一个分区中,尽量保证每个分区数据均匀,而且分区间有序

         9)RDD 文件读取与保存

        Spark 的数据读取及数据保存可以从两个维度来作区分:文件格式以及文件系统。

  • 文件格式分为:text 文件、csv 文件、sequence 文件以及 Object 文件;
  • 文件系统分为:本地文件系统、HDFSHBASE 以及数据库。

2、累加器

        累加器用来把 Executor 端变量信息聚合到 Driver 端。在 Driver 程序中定义的变量,在
Executor 端的每个 Task 都会得到这个变量的一份新的副本,每个 task 更新这些副本的值后,
传回 Driver 端进行 merge

3、广播变量

        广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个
或多个 Spark 操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表,
广播变量用起来都很顺手。在多个并行操作中使用同一个变量,但是 Spark 会为每个任务
分别发送。

        闭包数据,都是以Task为单位发送的,每个任务中包含闭包数据这样可能会导致,一个Executor包含大量重复的数据,一个Executor中含有大量重复的数据,并且占有大量的内存。

        Executor其实是一个JVM,所以在启动时,会自动分配内存完全可以将任务中的闭包数据放置在Executor的内存中,达到共享的目的。

        Spark中的广播变量就可以将闭包的数据保存到Executor的内存中。

        Spark中的广播变量不能够更改:分布式共享只读变量 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值