Spark_2 RDD

为什么需要学习RDD

在工作当中,如果能使用DF、DS来编程的话,尽量不要使用RDD来进行编程。因为DF、DS 本身封装的比较好,所以建议使用面向DataFrame 和 DataSet 的API 来进行编程。
但是,RDD 对开发 DF、DS 的API有好处,且在流式处理时,本质上还是对RDD进行操作。

RDD可以让开发者大大降低开发分布式应用程序的门槛。如果没有任何分布式计算框架,我要做分布式开发的话,需要自己考虑:
1. 数据的拆分
2. 通信机制
3. 作业挂掉了怎么办
4. 作业调度到哪个节点去执行
5. 序列化
但是有了RDD的话,就会降低很多门槛,因为RDD把这些功能已经封装好了。

RDD概述

RDD(Resilient Distributed Dataset):提供了一个抽象数据架构,避免了中间结果存储。是分布式对象集合,本质上是只读的分区记录集合
在Spark中,RDD是最基础的抽象单元
RDD操作:行动(返回非RDD),转换(返回RDD)
典型执行过程:
1.RDD读入外部数据
2.进行一系列“转换”操作,产生不同的RDD
3.最后一个RDD经过“行动”,输出到Driver

“行动”才会真正发生计算,而“转换”是记录相互之间的依赖关系
当“行动”要进行输出时,Spark根据RDD的依赖关系生成DAG,从起点开始计算

建立的“转换”然后生成DAG图称为一个“血缘关系”
血缘关系连接起来的RDD操作实现管道化,这就保证了中途不需要保存数据,而是直接管道式流入下一步

RDD 不可变,集合中的元素能够被分区并能够并行操作

  1. 弹性: Spark可以做到在分布式计算的时候可以容错,如果某一个节点挂了,或者某一个部分的数据丢失了
    可以通过RDD的一些机制来修复。弹性体现在计算之上
  2. 分布式:意味着,数据可以跨节点存储在集群之上。程序运行时,也是跨节点运行。分布式可以提升工作效率,是快的根本
  3. 数据集:可以被拆分成很多个分区来存储和计算。 可以通过读一个文件、编程、转换来创建一个数据集。
  4. 不可变的:RDD一旦产生就没办法改变 RDDA ==> RDDB 这个RDDB 必然是新的
  5. RDD的元素可以被拆分为一片片:Block/InputSplit 把大的拆分为很多小的
    这些被拆分的一片一片的可以以并行的方式
    RDDA (1,2,3,4,5,6,7,8,9) 拆分为三个partition;operated +1 对于三个Partition都运行
    hadoop001:(1,2,3) Partition1
    hadoop002:(4,5,6) Partition2
    hadoop003:(7,8,9) Partition3

RDD的定义

abstract class RDD[T: ClassTag](
@transient private var sc: SparkContext,
@transient private var deps: Seq[Dependency[
]]
) extends Serializable with Logging{…}
1)抽象类 RDD不能够直接使用的,借助于子类实现,使用时直接使用其子类
2)可序列化 序列化框架的好坏直接影响性能
3)日志
4)T 带泛型的,意味着可以支持各种数据类型
5)SparkContext sc
6)@transient

RDD的五大特点:

每一个RDD都应该有的

  1. A list of partitions 一个RDD由很多个分区构成,就相当于每个文件由很多个block块构成
  2. A function for computing each split 做计算的话是对于所有的分区做计算
  3. A list of dependencies on other RDDS RDD之间都有依赖关系 RDDA==>RDDB==>RDDC==>RDDD 如果RDDC里面的一个分区挂掉了,可以从RDDB里面的对应的分区转换一下就可以了。体现了RDD的弹性。这是一个流水线一样的一个前后的依赖关系,当一个分区的数据丢失了的话,spark可以根据这种依赖关系,重新计算这个分区的分区数据,然后倒入。并不是计算所有分区的数据,只计算这个分区的数据
  4. Optionally(可选的),a Partitioner for key-value RDDS(默认使用哈希)
  5. Optionally,a list of preferred locations to each split on 对于每一个分片计算会有preferred locations,数据本地性的一种说法 最好在哪里进行

移动计算而不是移动数据:减少了数据的网络和IO读取

木桶原理:不是以最快的task来说,而是以最慢的task来说时间

数据存储的时候是一定要切分的,切割的,大的切分成小的然后以多副本的方式来存储,以便于容错。计算的时候,也是需要切分的,默认按照block块的大小。一个task去处理两个block块的大小的数据也是可以的

HDFS + Spark 来替换 HDFS + mapreduce

五大特点在源码中的体现

  1. def compute(split: Partition, context: TaskContext): Iterator[T]
    对RDD进行计算,其实是对它里面的分区做计算 (2)
  2. protected def getPartitions: Array[Partition]
    RDD是由一系列分区组成(1)
  3. protected def getDependencies: Seq[Dependency[_]] = deps
    RDD之间有很多依赖关系(3)
  4. protected def getPreferredLocations(split: Partition): Seq[String] = Nil
    确定preferred locations (5)

RDD的创建

There are two ways to create RDDs:
1. parallelizing an existing collection in your driver program
把一个已经存在的集合以并行化的方式转换为RDD,一般用于测试的时候,自己造数据的时候
2. referencing a dataset in an external storage system,
such as a shared filesystem, HDFS, HBase, or
any data source offering a Hadoop InputFormat
把一些外部的数据集转换为RDD 这种方式比较常用

Parallelized Collections

		val data = Array(1,2,3,4,5)
		val distData = sc.parallelize(data) //在执行到这里时,只是进行了数据转换,还没有开始操作
		distData.collect   //这是一个action的动作,真正完成一个Spark job

One important parameter for parallel collections is the number of partitions to cut the dataset into.
Spark will run one task for each partition of the cluster.
默认
会有两个Task //可能因为启动spark-shell 时 是 ./spark-shell --master local[2] 启动两个线程,也就是两个core
而这个分成几个partition可以自己设置
val distData = sc.parallelize(data,5)
设置分成5 个 partition
也就是进行5 个task

External Datasets

Spark can create distributed datasets from any storage source supported
by Hadoop, including your local file system, HDFS, Cassandra, HBase, Amazon S3, etc.
Spark supports text files, SequenceFiles, and any other Hadoop InputFormat.

Text file RDDs can be created using SparkContext’s textFile method.
Read a text file from HDFS, a local file system (available on all nodes), or any
Hadoop-supported file system URI, and return it as an RDD of Strings.
尤其注意 如果是本地的话/Standalone,一定要available on all nodes

		val distFile = sc.textFile("路径+文件名")
		原文件:
		hello	world	hello
		hello	world	welcome

		进行distFile.collect后,结果是一个 distFile:org.apache.spark.rdd.RDD[String]
		//Array[String]= Array(hello		world	hello,hello	world	welome)
		源文件是两行,所以这里数组里上两个元素(两个字符串)
		可以从本地和HDFS上读取数据
		val distFile = sc.textFile("file:///home/hadoop/data/ruozeinput.txt")
		val distFile = sc.textFile("hdfs://hadoop001:9000/xxxx")

一些注意事项

(1)If using a path on the local filesystem,
the file must also be accessible at the same path on worker nodes.
Either copy the file to all workers
or use a network-mounted shared file system.
local path:all nodes

(2)All of Spark’s file-based input methods,
including textFile, support running on directories,
可以支持访问目录,直接将目录下的文件全部读入,全部以Array[String]表示
compressed files, and wildcards as well.
也可以读取压缩的文件,通配符
For example, you can use textFile("/my/directory"),
textFile("/my/directory/.txt"), and textFile("/my/directory/.gz").

(3)The textFile method also takes an optional second argument for controlling the number of partitions of the file
textFile的第二个参数可以指定 number of partitions of the file
(4)Apart from text files, Spark’s Scala API also supports several other data formats
sc.wholeTextFiles 可以读取一个目录的 (filename,content) 和sc.textFile的返回值不一样
sc.sequenceFile
hadoopRDD:
distFile.saveAsTextFile(“hdfs://hadoop001:9000/out/”)
这样会在HDFS上形成存储文件

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值