Spark简介

一、spark简介

1、概述

    Spark是一种快速、通用、可扩展的大数据分析引擎,项目是用Scala进行编写。目前,Spark生态系统已经发展成为一个包含多个子项目的集合,其中包含SparkSQL、Spark Streaming、GraphX、MLib、SparkR等子项目,Spark是基于内存计算的大数据并行计算框架。除了扩展了广泛使用的 MapReduce 计算模型,而且高效地支持更多计算模式,包括交互式查询和流处理。Spark 适用于各种各样原先需要多种不同的分布式平台的场景,包括批处理、迭代算法、交互式查询、流处理。通过在一个统一的框架下支持这些不同的计算,Spark 使我们可以简单而低耗地把各种处理流程整合在一起。而这样的组合,在实际的数据分析 过程中是很有意义的。不仅如此,Spark 的这种特性还大大减轻了原先需要对各种平台分 别管理的负担。

2、spark内置项目

2.1、Spark Core:实现了 Spark 的基本功能,包含任务调度、内存管理、错误恢复、与存储系统 交互等模块。Spark Core 中还包含了对弹性分布式数据集(resilient distributed dataset,简称RDD)的 API 定义。
2.2、Spark SQL:是 Spark 用来操作结构化数据的程序包。通过 Spark SQL,我们可以使用 SQL 或者 Apache Hive 版本的 SQL 方言(HQL)来查询数据。Spark SQL 支持多种数据源,比 如 Hive 表、Parquet 以及 JSON 等。
2.3、Spark Streaming:是 Spark 提供的对实时数据进行流式计算的组件。提供了用来操作数据流的 API,并且与 Spark Core 中的 RDD API 高度对应。
2.4、Spark MLlib:提供常见的机器学习(ML)功能的程序库。包括分类、回归、聚类、协同过滤等,还提供了模型评估、数据 导入等额外的支持功能。
2.5、集群管理器:Spark 设计为可以高效地在一个计算节点到数千个计算节点之间伸缩计 算。为了实现这样的要求,同时获得最大灵活性,Spark 支持在各种集群管理器(cluster manager)上运行,包括 Hadoop YARN、Apache Mesos,以及 Spark 自带的一个简易调度 器,叫作独立调度器。

二、RDD概念

1、RDD为什么会产生

    RDD是Spark的基石,是实现Spark数据处理的核心抽象。那么RDD为什么会产生呢?
    Hadoop的MapReduce是一种基于数据集的工作模式,面向数据,这种工作模式一般是从存储上加载数据集,然后操作数据集,最后写入物理存储设备。数据更多面临的是一次性处理。
   ;MR的这种方式对数据领域两种常见的操作不是很高效。第一种是迭代式的算法。比如机器学习中ALS、凸优化梯度下降等。这些都需要基于数据集或者数据集的衍生数据反复查询反复操作。MR这种模式不太合适,即使多MR串行处理,性能和时间也是一个问题。数据的共享依赖于磁盘。另外一种是交互式数据挖掘,MR显然不擅长。
 MR中的迭代
在这里插入图片描述
 Spark中的迭代:
在这里插入图片描述
    我们需要一个效率非常快,且能够支持迭代计算和有效数据共享的模型,Spark应运而生。RDD是基于工作集的工作模式,更多的是面向工作流。

2、RDD概述

2.1什么是RDD

    RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。在 Spark 中,对数据的所有操作不外乎创建 RDD、转化已有RDD 以及调用 RDD 操作进行求值。每个 RDD 都被分为多个分区,这些分区运行在集群中的不同节点上。RDD 可以包含 Python、Java、Scala 中任意类型的对象, 甚至可以包含用户自定义的对象。RDD具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。
    RDD支持两种操作:转化操作和行动操作。RDD 的转化操作是返回一个新的 RDD的操作,比如 map()和 filter(),而行动操作则是向驱动器程序返回结果或把结果写入外部系统的操作。比如 count() 和 first()。
Spark采用惰性计算模式,RDD只有第一次在一个行动操作中用到时,才会真正计算。Spark可以优化整个计算过程。默认情况下,Spark 的 RDD 会在你每次对它们进行行动操作时重新计算。如果想在多个行动操作中重用同一个 RDD,可以使用 RDD.persist() 让 Spark 把这个 RDD 缓存下来。

2.2RDD的属性

1)一组分片(Partition),即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。

2)一个计算每个分区的函数。Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。

3)RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。

4)一个Partitioner,即RDD的分片函数。当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于于key-value的RDD,才会有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。

5)一个列表,存储存取每个Partition的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。按照“移动数据不如移动计算”的理念,Spark在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。
    RDD是一个应用层面的逻辑概念。一个RDD多个分片。RDD就是一个元数据记录集,记录了RDD内存所有的关系数据。

2.3RDD弹性

1)自动进行内存和磁盘数据存储的切换
   Spark优先把数据放到内存中,如果内存放不下,就会放到磁盘里面,程序进行自动的存储切换
2)基于血统的高效容错机制
   在RDD进行转换和动作的时候,会形成RDD的Lineage依赖链,当某一个RDD失效的时候,可以通过重新计算上游的RDD来重新生成丢失的RDD数据。
3)Task如果失败会自动进行特定次数的重试
   RDD的计算任务如果运行失败,会自动进行任务的重新计算,默认次数是4次。
4)Stage如果失败会自动进行特定次数的重试
  如果Job的某个Stage阶段计算失败,框架也会自动进行任务的重新计算,默认次数也是4次。
5)Checkpoint和Persist可主动或被动触发
   RDD可以通过Persist持久化将RDD缓存到内存或者磁盘,当再次用到该RDD时直接读取就行。也可以将RDD进行检查点,检查点会将数据存储在HDFS中,该RDD的所有父RDD依赖都会被移除。
6)数据调度弹性
   Spark把这个JOB执行模型抽象为通用的有向无环图DAG,可以将多Stage的任务串联或并行执行,调度引擎自动处理Stage的失败以及Task的失败。
7)数据分片的高度弹性
   可以根据业务的特征,动态调整数据分片的个数,提升整体的应用执行效率。
   RDD全称叫做弹性分布式数据集(Resilient Distributed Datasets),它是一种分布式的内存抽象,表示一个只读的记录分区的集合,它只能通过其他RDD转换而创建,为此,RDD支持丰富的转换操作(如map, join, filter, groupBy等),通过这种转换操作,新的RDD则包含了如何从其他RDD衍生所必需的信息,所以说RDDs之间是有依赖关系的。基于RDD之间的依赖,RDD会形成一个有向无环图DAG,该DAG描述了整个流式计算的流程,实际执行的时候,RDD是通过血缘关系(Lineage)一气呵成的,即使出现数据分区丢失,也可以通过血缘关系重建分区,总结起来,基于RDD的流式计算任务可描述为:从稳定的物理存储(如分布式文件系统)中加载记录,记录被传入由一组确定性操作构成的DAG,然后写回稳定存储。另外RDD还可以将数据集缓存到内存中,使得在多个操作之间可以重用数据集,基于这个特点可以很方便地构建迭代型应用(图计算、机器学习等)或者交互式数据分析应用。可以说Spark最初也就是实现RDD的一个分布式系统,后面通过不断发展壮大成为现在较为完善的大数据生态系统,简单来讲,Spark-RDD的关系类似于Hadoop-MapReduce关系。

三、RDD转换算子

  RDD根据数据处理方式的不同将算子整体上分为Value类型、双Value类型和Key-Value类型
1、value类型

1.1 map:将处理的数据逐条进行映射转换,这里的转换可以是类型的转换,也可以是值的转换。
1.2 mapPartitions:将待处理的数据以分区为单位发送到计算节点进行处理,这里的处理是指可以进行任意的处理,哪怕是过滤数据。
(1)mapPartitions以分区为单位进行计算,和map算子很像
(2)区别在与map算子是一个一个执行,每次处理一条数据,而mapPartitions一个分区一个分区执行,类似于批处理,如果一个分区的数据没有处理完,那么所有的数据都不会释放,即使前面处理完的数据也不会释放,容易出现内存溢出,所以当内存足够大时,推荐使用mapPartitions
(3) map是全量操作,不能丢失数据
(4) mapPartitions一次性获取分区所有数据,可以执行迭代器集合的所有操作,如filter
1.3 mapPartitionsWithIndex:将待处理的数据以分区为单位发送到计算节点进行处理,这里的处理是指可以进行任意的处理,哪怕是过滤数据,在处理时同时可以获取当前分区索引
3.4 flatMap:将处理的数据进行扁平化后再进行映射处理,所以算子也称之为扁平映射
1.5 glom:将同一个分区的数据直接转换为相同类型的内存数组进行处理,分区不变
1.6 groupBy:将数据根据指定的规则进行分组, 分区默认不变,但是数据会被打乱重新组合,我们将这样的操作称之为shuffle。极限情况下,数据可能被分在同一个分区中

   // todo groupBy根据指定规则进行分组,指定规则的返回值就是分组的key
    //      groupBy的返回值为元组
    //      元组的一个元素表示分组的key
    //      元组的第二个元素表示分组key的可迭代集合
    //      groupBy执行完毕后,会将数据进行分组操作,但是分区数量是不会改变的,不同组的数据会进行打乱
    //      如果将上游分区的数据打乱重新组合在下游分区数据中,我们将这个操作称为shuffle
    //      如果数据被打乱重新组合,那么将会出现不均匀的情况,可以改变下游RDD的分区数量

1.7 filter:将数据根据指定的规则进行筛选过滤,符合规则的数据保留,不符合规则的数据丢弃。当数据进行筛选过滤后,分区不变,但是分区内的数据可能不均衡,生产环境下,可能会出现数据倾斜。

1.8 sample:根据指定的规则从数据集中抽取数据
1.9 coalesce:根据数据量缩减分区,用于大数据集过滤后,提高小数据集的执行效率,当spark程序中,存在过多的小任务的时候,可以通过coalesce方法,收缩合并分区,减少分区的个数,减小任务调度成本
coalesce不能扩大分区,因为在分区缩减时,数据不会打乱重新组合,没有shuffle的过程。
1.10 repartition:该操作内部其实执行的是coalesce操作,参数shuffle的默认值为true。无论是将分区数多的RDD转换为分区数少的RDD,还是将分区数少的RDD转换为分区数多的RDD,repartition操作都可以完成,因为无论如何都会经shuffle过程。
1.11 sortBy:该操作用于排序数据。在排序之前,可以将数据通过f函数进行处理,之后按照f函数处理的结果进行排序,默认为正序排列。排序后新产生的RDD的分区数与原RDD的分区数一致。

2 key-value类型

2.1 reducewByKey与groupByKey的区别
 groupByKey面向整个数据集,而不是某一个分区,对一个分区的数据执行完成后不能执行后续操作,需要等待其他分区的数据全部到达后,才能执行后续操作,但是在内存中等待,可能导致内存溢出,执行失败,等待的过程应该依靠磁盘文件进行等待,一个分区就是一个task,如果处理过程中存在shuffle操作,那么会将task一分为二。
 reduceByKey在shuffle之前可以在分区内进行聚合操作,称之为预聚合,这样,shuffle落盘数据量减少了,提高了性能。
  reduceByKey不一定有shuffle
  reduceByKey为了提高效率,默认有缓存
2.2 aggregateByKey:将数据根据不同的规则进
行分区内计算和分区间计算
2.3 foldByKey:当分区内计算规则和分区间计算规则相同时,aggregateByKey就可以简化为foldByKey
2.4 combineByKey:最通用的对key-value型rdd进行聚集操作的聚集函数(aggregation function)。类似于aggregate(),combineByKey()允许用户返回值的类型与输入不一致。
2.5 reducewByKey,aggregateByKey,foldByKey,combineByKey的区别

从源码角度看,4个算子底层调用方法相同
  def combineByKeyWithClassTag[C](
      createCombiner: V => C,
      mergeValue: (C, V) => C,
      mergeCombiners: (C, C) => C,
      partitioner: Partitioner,
      mapSideCombine: Boolean = true,
      serializer: Serializer = null)

    //    第一个参数:将计算的第一个值(value)处理
    //     第二个参数:分区内的计算规则
    //     第三个参数:分区间的计算规则
      createCombiner: V => C,
      mergeValue: (C, V) => C,
      mergeCombiners: (C, C) => C,
      
 reducewByKey 
   // (v: V) => v, func, func
   不会对第一个value进行处理,分区内和分区间的计算规则相同
 aggregateByKey
  //  (v: V) => cleanedSeqOp(createZero(), v),   cleanedSeqOp, combOp
  会将初始值和第一个value使用分区内计算规则进行计算
 foldByKey
 //(v: V) => cleanedFunc(createZero(), v),cleanedFunc, cleanedFunc
 分区内和分区间计算规则相同,初始值和第一个value使用分区内计算规则进行计算
 combineByKey
//  createCombiner, mergeValue, mergeCombiners
第一个参数就是对第一个value进行处理,所以无需初始值

2.6 sortByKey:在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的
2.7 join:在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素连接在一起的(K,(V,W))的RDD,如果key不相等,则无法连接,如果相同key存在多个,则笛卡尔乘积

2.8 leftOuterJoin:类似于SQL语句的左外连接
2.9 cogroup:在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable,Iterable))类型的RDD

四、行动算子

 行动算子执行后,会获取到作业的结果,会产生Job对象,然后提交这个Job对象
4.1 reduce:聚集RDD中的所有元素,先聚合分区内数据,再聚合分区间数据
4.2 collect:在驱动程序中,以数组Array的形式返回数据集的所有元素,会将所有分区计算的数据拉取到当前节点,可能造成内存溢出。
4.3 aggregate:分区的数据通过初始值和分区内的数据进行聚合,然后再和初始值进行分区间的数据聚合,初始值分区内计算会参与,分区间也会参与
4.4 fold:折叠操作,aggregate的简化版操作
4.5 foreach:分布式遍历RDD中的每一个元素,调用指定函数

val rdd: RDD[Int] = sc.makeRDD(List(1,2,3,4))

// 收集后打印
// 集合中的方法是在当前节点执行的
//在当前的节点中完成循环
rdd.map(num=>num).collect().foreach(println)

println("****************")

// 分布式打印
//rdd中的方法称为算子,算子的逻辑代码是在分布式节点executer执行的
//将循环在不同的节点中完成
//算子之外的代码是在driver中执行的
rdd.foreach(println)

五、核心组件

1 、Driver

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

2、 Executor

 Spark Executor是集群中工作节点(Worker)中的一个JVM进程,负责在 Spark 作业中运行具体任务(Task),任务彼此之间相互独立。Spark 应用启动时,Executor节点被同时启动,并且始终伴随着整个 Spark 应用的生命周期而存在。如果有Executor节点发生了故障或崩溃,Spark 应用也可以继续执行,会将出错节点上的任务调度到其他Executor节点上继续运行。
 Executor有两个核心功能:
(1)负责运行组成Spark应用的任务,并将结果返回给驱动器进程
(2)它们通过自身的块管理器(Block Manager)为用户程序中要求缓存的 RDD 提供内存式存储。RDD 是直接缓存在Executor进程内的,因此任务可以在运行时充分利用缓存数据加速运算。

六、RDD依赖关系

1.窄依赖:表示一个父RDD的partition最多被子RDD的一个partition使用,可以形象的比喻为独生子女
2.宽依赖:表示同一个父RDD的patiition被多个子RDD的partition依赖,会引起shuffle
3.阶段的划分:如果计算过程存在落盘,那么应该划分阶段
 如果计算过程中没有落盘,那么就是一个完整的阶段
 如果计算过程中存在落盘,那么应该把阶段一分为二
 spark阶段的划分,取决于shuffle依赖的过程
 阶段的个数=shuffle依赖的数量+1
4。任务的划分
RDD任务切分中间分为:Application,Job,Stage和Task

  • Applicaton:初始化一个SparkContext即生成一个Application
  • Job:一个Action就会生成一个Job
  • Stage:Stage等同于宽依赖的个数加1
  • Task:一个Stage阶段中,最后一个RDD的分区个数就是Task的个数
七、RDD持久化

1.RDD的cache缓存
 RDD通过cache或persist方法将前面的计算结果缓存,默认情况下会把数据以序列化的方式缓存在JVM内存中。但是并不是这两个方法被调用就立即缓存,而是触发后面的Action算子时,该RDD会被缓存在计算节点的内存中,供后面重用。

八、累加器

分布式共享只写变量

    //  todo 声明累加器
    val sum = sc.longAccumulator("sum")

    //   todo  执行计算式spark会将累加器发送到excutor。不同excutor端读取不到累加器的结果
    //    计算完毕后,excutor会将计算结果返回到driver端
    //     driver获取到多个累加器的结果,两两合并,最后得到累加器的执行结果

九、广播变量

分布式共享只读变量

object SparkRDD_BC {

  def main(args: Array[String]): Unit = {
    //1.创建SparkConf并设置App名称
    val conf: SparkConf = new SparkConf().setAppName("bc").setMaster("local[*]")
    //2.创建SparkContext,该对象是提交Spark App的入口
    val sc: SparkContext = new SparkContext(conf)

    // todo spark计算数据时,使用的闭包操作中,会导致变量被不同的task使用,那会会传递到excutor多份
    //         这样的话,excutor存在大量的冗余数据,导致性能下降
   val rdd:RDD[(String,Int)] = sc.makeRDD(List(("a",1),("b",1),("c",1),("d",1)))
      val list = List(("a",1),("b",1),("c",1),("d",1))

    val broad = sc.broadcast(list)

    // todo 为了解决join的性能问题,可以将数据独立出来,防止shuffle操作
    //       这样会导致每个task会复制一份,excutor中会存在大量数据
    //       这样的话可以使用广播变量,将数据存在excutor的内存当中
      val map = rdd.map{
        case (word, count) => {
          var count2 = 0
          for (kv <- broad.value) {
            var k = kv._1
            var v = kv._2

            if (k == word) {
              count2 = v
            }
          }
          (word, (count, count2))
        }
      }
      val str = map.collect().mkString(",")
      println(str)
    sc.stop()
  }
}

十、sparksql

 用于处理结构化数据的spark模块

十一、sparkstreaming

 sparkstreaming无法实现真正的流式数据处理,使用了微批次数据数据,是一个准实时处理引擎。
 和Spark基于RDD的概念很相似,Spark Streaming使用离散化流(discretized stream)作为抽象表示,叫作DStream。DStream 是随时间推移而收到的数据的序列。在内部,每个时间区间收到的数据都作为 RDD 存在,而DStream是由这些RDD所组成的序列(因此得名“离散化”)。所以简单来讲,DStream就是对RDD在实时数据处理场景的一种封装。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码出天空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值