Spark学习(一):概述

Spark学习(一):概述

上周六面试腾讯时被问到是否了解Spark,彼时对Spark毫无接触故答不了解,面试结束后了解到Spark与MapReduce渊源颇深,去年夏天学习MIT6.824分布式系统设计时曾深入学习过MapReduce(分布式学习:MapReduce - pinoky - 博客园 (cnblogs.com))故对Spark产生兴趣,由此开始学习

Spark诞生原因

MapReduce作为一个分布式、并行处理的计算框架,存在着诸多缺陷如下:

  • 仅支持Map,Reduce两种语义操作
  • 由于MapReduce操作数据涉及到大量磁盘IO,故执行效率低,时间开销大
  • MapReduce主要适用于大规模离线批处理,不适合迭代计算、交互式计算、实时流处理等场景

计算框架众多、选型困难、学习成本高就成为了大数据领域的一大痛点,常见的计算框架就有如下几种:

  • 批处理:MapReduce
  • 流处理:Storm,Flink
  • 交互式计算:Impala,Presto
  • ……

业界迫切需要统一计算框架,在一个统一框架下实现批处理、流处理、交互式计算、机器学习,于是Spark应运而生

Spark特点

  • Spark Core:实现了 Spark 的基本功能,包含 RDD、任务调度、内存管理、错误恢复、与存储系统交互等模块。
  • Spark SQL:Spark 用来操作结构化数据的程序包。通过 Spark SQL,我们可以使用 SQL 操作数据。
  • Spark Streaming:Spark 提供的对实时数据进行流式计算的组件。提供了用来操作数据流的 API。
  • Spark MLlib:提供常见的机器学习(ML)功能的程序库。包括分类、回归、聚类、协同过滤等,还提供了模型评估、数据导入等额外的支持功能。
  • GraphX(图计算):Spark 中用于图计算的 API,性能良好,拥有丰富的功能和运算符,能在海量数据上自如地运行复杂的图算法。
  • 集群管理器:Spark 设计为可以高效地在一个计算节点到数千个计算节点之间伸缩计算。
  • Structured Streaming:处理结构化流,统一了离线和实时的 API。

使用Scala语言开发的Spark提供了多种运行模式,具有高吞吐、低延时、通用易扩展、高容错等特点,同时也可兼容hadoop等框架,降低迁移成本

Spark RDD 与 编程模型

RDD,即弹性分布式数据集,Spark基于RDD进行计算,其的特点如下

  • 是分布在集群中的只读对象集合
  • 由多个partition组成
  • 通过转换操作构造
  • 失败后自动重构
  • 存储在内存或磁盘中

RDD主要有两种操作:Transformation,Action

  • Transformation:惰性执行,只记录转换关系,不触发计算
    • 将Scala集合或Hadoop输入数据构造成一个新RDD
    • 通过已有的RDD产生新的RDD
    • 例如:map、filter、flatmap、union等
  • Action:真正触发计算
    • 通过RDD计算得到一个值或一组值
    • 例如:first、collect、saveAsTextFile、foreach

以一个简单的词频统计为例 简单介绍一下Spark基于RDD的编程模型

  • 在textFile阶段,首先将数据从HDFS中读出变成RDD
  • 进入flatMap阶段,将RDD中的数据按某分隔符进行分隔,在本例中以“\t”为分隔符
  • 随后map阶段,会将RDD中的每个单词的词频记为1,即val rdd3 = rdd2.map((_,1))
  • 再接下去进行shuffle,将相同key的数据reduce到同一个节点上去统计词频,即reduceByKey((_+_))
  • 最终再将reduce得到的RDD保存为数据文件,放入HDFS中

通过这个例子可以明显地感觉到,基于RDD的编程模型 与 单机编程是基本上一致的(不同于MapReduce,MapReduce是典型的分布式编程,需要指定map阶段各个节点的处理动作,也需要指定reduce阶段各个节点的操作)

为什么说RDD是弹性的:由于RDD的数据保存在内存中,如果说执行过程中某个partition出现错误,不需要重新回到HDFS从头开始执行,而是只需要回到上一个阶段重新计算即可,这在flatMap、map这种一对一的处理阶段尤其方便(因为这种一对一的计算往往都是在同一个节点上进行的)

RDD的宽依赖与窄依赖

窄依赖:即父RDD中的分区最多只能被一个子RDD的一个分区使用,也就是一对一的关系,如下图map、filter、union都是典型的窄依赖,在这种依赖下子RDD如果有部分partition数据丢失或损坏,只需从对应的父RDD重新计算即可恢复

宽依赖:即子RDD分区依赖父RDD的所有分区,如groupByKey、sortByKey、reduceByKey,在这种依赖下子RDD如果部分partitio数据丢失或损坏,必须从所有父RDD的partion重新计算,所以相对于窄依赖需要付出更多的代价,应该尽量避免使用

Spark的程序运行架构

Master为主节点,Driver为作业提交管理程序,Worker为从节点

Client向Master提交命令后,Driver会先向Master申请执行n个task的资源executor,然后把sparkcontext分发到worker上的executor上执行,待worker执行结束后会向Driver进行汇报,Driver发现所有task执行完成后就向Master申请资源的释放

一个作业的执行可以分为以下几个阶段:

  • 生成逻辑查询计划:主要关注于 RDD状态的解析,(比如map阶段:RDD从[string]变成[string,int]的转变)

  • 生成物理查询计划:主要关注底层数据的状态 ,根据DAG图是否有宽窄依赖,做stage的切分(也可以说根据是否发生shuffle进行切分)

    • 同一个stage里面的转换,可以放在同一个节点上面处理
    • stage数量越多,shuffle越多,性能越差
  • 任务调度与任务执行:在同一个stage下、进行一对一转换的partition可以合并为一个task,以上图为例,可以划分为7个task,最终分发给executor执行

posted @ 2024-09-23 21:22  pinoky  阅读(21)  评论(0编辑  收藏  举报