大数据 T4 Spark基础(附实例分析)

288 阅读8分钟

专栏 大数据 数据处理原理
如果对你有帮助求个赞或者关注,谢谢谢谢。

这篇文章是接前文进行创作的(同一专栏内),之前已经解释过的概念在此不再赘述比如MapReduce,如果有兴趣从头到尾的详细了解,可以查看专栏.

为什么要用spark

前文说过,Hadoop的有一些缺点,比如每次操作(Map 或者 Reduce)都需要把中间结果写入到磁盘中,这导致了极大的读写开销,如果需要多次进行Map和Reduce,影响会更大(然而这才是大多数情况下的工作场景)。并且也不能处理流式数据等问题。简而言之,处理速度慢,处理延迟大。因此“可能”需要一种新的东西来解决这些问题,解决这一问题的工具就是spark。

Hadoop 到 spark的转变。

  • 从05年-10年之间,硬件迅速发展,内存容量,读写速度与价格发生了极大的变化,这导致将所有中间结果临时保存在内存中成为可能(就是内存大了,不用读写进磁盘了,一直放在内存中备用)。
  • 依靠于硬件的进步,spark诞生了。它最初的起源是University of California, Berkeley大学的一个课程项目。然后把它开源了
  • 简单来说,spark最初就是将Hadoop的读写转为全部在内存中操作。红框框住的那一部分没了。

image.png 看起来好像没什么大不了,因为这个图中只有一次map,一次reduce。但是反映在大量数据、多次操作中,速度有巨大的提升。如下图所示。

image.png

仅仅就是不进行读写了吗?

  • 新的概念:RDD(Resilient Distributed Datasets)。
    • RDD是Apache Spark中的概念,它是一个可并行操作的、可分区的、容错的分布式数据集合。可以先把他想象为就是一个Excel表的格式(当然,他不一定非要是这种格式,后面再说)。Spark在运行中使用了名为RDD的结构来存储数据。
    • RDD可以被进行分区(Partition)处理。比如一张表,前10行属于第一分区,之后的是第二分区。
      image.png

Q:RDD 与 HDFS的区别

A:RDD是一种抽象的数据集合,可以在内存中进行分布式计算和处理。它提供了一组操作来处理和转换数据。而HDFS是一个分布式文件系统,用于存储和管理大规模数据集。

RDD可以以任意它支持的形式存到磁盘中,并且可以从各种数据源中读取。意思就是,我只需要保证经过的转化,数据可以变成想要的格式,这个格式就是RDD。就像数据结构中的堆栈,不同的语言有不同的实现方法,甚至同一种语言都有多种实现,比如Java的ArrayList与LinkedList。我不想知道具体实现,我只需要在使用的时候能以我预想的方式进行工作。(当然不同的实现方式会有不同的优缺点)

RDD提供了一组丰富的转换和操作,可以在分布式环境中对数据进行处理。Spark使用RDD来实现弹性的、高度可扩展的计算模型。而HDFS主要用于数据的存储和访问,他是一个文件系统。

RDD更加灵活,它可以进行拆分,并且分块读取。这就意味着他可以进行并行计算,也不用像HDFS那样一下就得读取一个128m的块。Note: 其实我在这里的直接对比并且说RDD更灵活其实并不是很严谨,因为RDD只是一个概念上的东西,现实中还要看具体实现是什么样的。但是至少对操作人员来说,他们可以使用RDD做各种灵活操作。

Q:RDD就是用来规定数据应该以什么样的格式进行存储的对吗?

不太对,它只是一种抽象的数据集合,在spark中,用户可以对RDD进行各种操作,比如Split,filter等,但是它并不是一种实实在在的,计算机的存储方式。RDD可以从多种数据源(如文件系统、Hive表、数据库等)中创建,并可以在内存中进行分布式计算和处理。RDD的重点是在分布式环境中提供高性能的数据操作和转换能力,以支持各种数据处理任务。

最简单的Spark执行流程

理解了RDD后,我们暂时就可以完全放下HDFS了,因为Spark中,只有RDD,一切的操作都是对RDD进行操作(即使他们的底层仍然可能是HDFS进行存储,但是这不重要)。spark也提供了很多操作RDD的内置函数比如Map(),flatMap(),Filter()。

image.png 没有频繁的读写,他看起来比之前Hadoop的操作要简单多了。

它仍然太抽象了?

  • 我不知道Map到底是干嘛的,不就是Map和Reduce可以完成任何的数据处理工作吗?怎么还有flatMap和Filter?
  • 你说的spark内置了许多功能又是干嘛的?
  • Map的作用到底是什么,Reduce具体又是啥?

Spark实例分析

这里我们给一个具体例子:比如我想要计算一本书中某个单词的数量(就用“Zelda”好了)。

  1. 首先这本书应该是一个电子版的,那么它就一定会以某种特定的格式存在电脑中(.txt, .axw3)等。

  2. 通过RDD Loader读取这本书,并将它转变为一个RDD(最简单的情况)。并将它分为两部分(P1和P2),并且第一个分区中(P1),将前半本书的数据平均分为三条信息,P2中将后半本书将数据平均分为两条。接下来就是对数据进行Map了。

    • Map的过程其实就是对数据进行转换的过程。在转换的过程中,实现自己想要的操作。要想进行操作,就得先弄清楚,我们有什么,我们想要什么
  3. 我们有什么:有一个RDD,这个RDD有两个分区(partation),第一个分区中又将数据分为三部分(<Row1,Value1>, <Row2,Value2>,<Row3,Value3>),第二个分区中将此分区的数据分为两部分(<Row1,Value1>, <Row2,Value2>).
    我们想要什么:“Zelda”这个单词的数量。

image.png 4. Map操作:<R1,V1>中的value是很长一段文字,因此我们可以进行的操作是:将<Row1,value1> 变为 <Row1, Number_of_the_word>. 这样我们的输出就变成了<Row1,Integer1>。接下来就是在Map的过程中写个简单的函数,找出这个number就好了。

  1. 完成计算之后,就开始讲他们进行递归合并了,如果不清楚可以翻看同专栏T2 MapReduce. image.png
  2. 那FlatMap呢,按照之前的思路,FlatMap的输出是按照制定的规则,输出一个列表,这个列表中含有多个元素。比如“Hello Hello World”,对他使用flatMap,转换的格式是空格分割,并且计算出现次数。输出为List< <Hello, 1>, <Hello,1>, <World,1>>.
  3. 这个例子中,它可以输出List< <word1,1>, <word2,1>, <word3, 1> ..... >(word1可能与word2相等。).这个List巨大无比,每个单词都是一个二元组,然后再进行递归合并。因此这个例子并不适合FlatMap。

Map与Reduce的本质。

从上述例子中可以看到,MapReduce也只是一个概念,Map的本质是转化(Transformation),将我们有的转化为需要的(刚刚的例子就是,一个长String转化为一个数字count),然后将他们合并(Reduce)得到想要的结果。

既然Map的本质就是转化,那么转化的方式就有一对一和一对多,spark中,Map()可以将一个数据转化为另一个数据(String - Integer), FlatMap()可以将一个数据转为一个List(String -> List<word1,word2...>).

解决问题的思路

在使用spark进行计算之前,要如何思考? 我们有什么-> ... -> 我们需要什么都是已知的,我们只需要想办法将有的转为需要的,然后将他们加起来就好了。

再次回顾刚刚的例子,有的:String,要的:Count 那么我只需要按照要求(当前单词 == “Zelda”?)的出来这个值然后返回,再将这些值算出来就好了。

接下来呢?

这里并不打算一个个列举每个spark都有哪些内置函数,他们的传入值和返回值是什么等文档性内容,因为他们并不应该以博客或者文章的形式出现。但我仍然会列一些函数,因为他们在spark中属于两种类型(Transformation和Action)。之后我会写一篇其他类型的文章,里面会有一些详细的例子,并且使用代码来解决这些问题(我会给出整个架构,只需要往里面加Map与Reduce相关的核心操作就好)。

所以下一步:spark如何优化运行过程?有向无环图(DAG)与懒启动。