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上形成存儲文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章