RDD到底是什麼?RDD的API

我一拳打彎你A柱發表於2020-11-18

RDD到底是什麼?RDD的API

大家好,我是W

今天給大家帶來一篇關於Spark和RDD的部落格,由於我也是初學者,所以沒法帶來那麼深刻的東西,但是我希望用我的感性認知帶給大家一點靈感,畢竟剛開始學習Spark的時候我對RDD概念、Spark流程是有很多困惑的,我覺得大家也可能存在這種問題。OK,接下來我將從以下幾個角度來講RDD和Spark:1、 Spark簡介、對比hadoop、生態,2、 RDD概念

1、 Spark簡介、對比hadoop、生態

1.1 Spark簡介

Spark官網,可以看到官方對Spark的概述:

Spark Overview

Apache Spark is a unified analytics engine for large-scale data processing. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution graphs. It also supports a rich set of higher-level tools including Spark SQL for SQL and structured data processing, MLlib for machine learning, GraphX for graph processing, and Structured Streaming for incremental computation and stream processing.
Apache的Spark是一個用於大規模資料處理的統一分析引擎。它提供了一系列Java、Scaala、Python的高階API以及優化引擎,所以支援統一的操作。它同樣的提供了一系列豐富的高階工具,包括用於SQL查詢、結構化資料處理的Spark SQL,用於機器學習的MLlib庫,用於圖處理的GraphX庫,以及用於增量計算和流處理的Streaming庫。

可以看到官網對Spark的定義就是一個大一統的框架,其中存在做結構化資料處理的元件Spark SQL,有用於機器學習的MLlib元件等等。在我實際學習的過程中可以感覺到元件間的關係就好像積木一樣,需要的時候插上即可。

1.2 Spark對比Hadoop

Spark對比hadoop最大的特點就是快,在官網上第一張圖就擺出來Spark比hadoop快了百倍,Spark的運算是基於記憶體的,而hadoop則需要通過HDFS將資料持久化到磁碟,所以顯然是快的,但是快多少還是要看實際生產環境吧。

可是除了這點就沒了嗎?其實還有的,在《大資料基礎:Spark工作原理及基礎概念》中給大家羅列出來了:

特點說明
spark 計算速度快spark將每個任務構建成DAG進行計算,內部的計算過程通過彈性式分散式資料集RDD在記憶體在進行計算,相比於hadoop的mapreduce效率提升了100倍。
易於使用spark 提供了大量的運算元,開發只需呼叫相關api進行實現無法關注底層的實現原理。相較於以前離線任務採用mapreduce實現,實時任務採用storm實現,目前這些都可以通過spark來實現,降低來開發的成本。同時spark 通過spark SQL降低了使用者的學習使用門檻,還提供了機器學習,圖計算引擎等。
支援多種的資源管理模式學習使用中可以採用local 模型進行任務的除錯,在正式環境中又提供了standalone,yarn等模式,方便使用者選擇合適的資源管理模式進行適配。
社群支援spark 生態圈豐富,迭代更新快,成為大資料領域必備的計算引擎。

1.3 Spark生態圈

其實剛剛介紹Spark的時候已經講了一點了,大家請看圖:

在這裡插入圖片描述

這是我找到比較合理的一張圖,它把不同的工作內容分層,結構比較清晰。

說明
資源排程層因為我們的任務是要提交到叢集上執行的,不同的結點有不同的工作,所以需要對計算資源進行排程,而在這一層的資源排程方式就有很多:local模式、StandAlone模式、yarn模式、mesos模式等等。
計算層計算層主要使用的是spark-core這個spark的核心庫,其面向的是離線的計算,而R、Python這些就是所支援的語言。
儲存層儲存層包括一系列的儲存元件,最常見的比如有hadoop-HDFS、MySQL、HBASE、MongoDB、Redis等等,這些均是spark生態可以對接的儲存元件,而右邊的sparkSQL顯然是支援這些資料來源的,而下方的MLlib等等顯然需要資料的支援。
資料流在做實時計算的時候streaming可以對接flume、kafka等元件。

2、 RDD的概念(RDD到底是什麼)、Spark的工作流程

這兩個話題涉及了很多因素,我感覺這一篇文章還是不可能講的很清楚,但是我會用我能做到的最樸素的語言給大家感性的講一講。同時,我建議大家多做幾個小案例來加深認識。

2.1 RDD的概念

2.1.1 官方的定義

RDD是Spark中最重要的概念,其全稱叫做Resilient Distributed Dataset (RDD),即彈性分散式資料集,是一種可容錯的、可以被並行操作元素集合,是Spark中處理所有資料的一種基本抽象。

光是看這一句還是不夠的,我在原始碼中找來註釋給大家看一下,我建議大家仔細看下原始碼的註釋

/**
 * A Resilient Distributed Dataset (RDD), the basic abstraction in Spark. Represents an immutable,
 * partitioned collection of elements that can be operated on in parallel. This class contains the
 * basic operations available on all RDDs, such as `map`, `filter`, and `persist`.
 * 一個彈性分散式資料集(RDD),是Spark裡的基本抽象。
 * 它代表了可以被並行操作的不可變的分割槽元素集合。這個類包含了各種RDD都支援的基本操作,比如map、filter、persist等。
 * 
 * In addition,[[org.apache.spark.rdd.PairRDDFunctions]] contains operations available only on RDDs of key-value pairs, such as `groupByKey` and `join`;
 * 此外,org.apache.spark.rdd.PairRDDFunctions裡還包含了只有鍵值對(key-value)型別RDD可用的操作,比如groupByKey、join等。
 * 
 * [[org.apache.spark.rdd.DoubleRDDFunctions]] contains operations available only on RDDs of Doubles; 
 * org.apache.spark.rdd.DoubleRDDFunctions 裡包含了只有Double資料型別的RDD可用的操作。
 * 
 * and [[org.apache.spark.rdd.SequenceFileRDDFunctions]] contains operations available on RDDs that can be saved as SequenceFiles.
 * org.apache.spark.rdd.SequenceFileRDDFunctions 裡包含了可以被序列化成檔案的RDD所包含的操作。
 * 
 * All operations are automatically available on any RDD of the right type (e.g. RDD[(Int, Int)] through implicit.
 * 所有的操作都可以通過implicit來賦予。
 * 
 * Internally, each RDD is characterized by five main properties:
 * 在RDD內部,每一個RDD都由這五個主要特徵來描述:
 * 
 *  - A list of partitions
 *  - 一系列分割槽
 *  
 *  - A function for computing each split
 *  - 對每一個分片做計算的函式
 *  
 *  - A list of dependencies on other RDDs
 *  - 一系列對其他RDD的依賴
 *  
 *  - Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
 *  - 視情況而定,一個作用於鍵值對RDD的分割槽器
 *  
 *  - Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)
 *  - 視情況而定, 要計算每個分片的首選位置的列表
 *
 * All of the scheduling and execution in Spark is done based on these methods, allowing each RDD
 * to implement its own way of computing itself. Indeed, users can implement custom RDDs (e.g. for
 * reading data from a new storage system) by overriding these functions. Please refer to the
 * <a href="http://people.csail.mit.edu/matei/papers/2012/nsdi_spark.pdf">Spark paper</a>
 * for more details on RDD internals.
 * Spark裡的所有scheduling和execution都是基於這些方法(通過賦予RDD操作的方式)來實現其自身的計算方式,當然使用者可以通過重寫方法自定義RDD。
 */

最後註釋中還貼心的給出了RDD的提出的論文:《Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing》

RDD的操作分為兩大類,Transformation、Action。

Transformation是對已有的RDD進行轉換(記錄下一步操作)然後生成新的RDD,採用的是lazy策略,不會立即計算出結果。

Action是讓已有的RDD對資料執行它的操作。

表格來自:大資料之Spark簡介及RDD說明

Transformation
方法(運算元)說明
map(func)返回一個新的RDD,該RDD由每一個輸入元素經過func函式轉換後組成
filter(func)返回一個新的RDD,該RDD由經過func函式計算後返回值為true的輸入元素組成
flatMap(func)類似於map,但是每一個輸入元素可以被對映為0或多個輸出元素(所以func應該返回一個序列,而不是單一元素)
mapPartitions(func)類似於map,但獨立地在RDD的每一個分片上執行,因此在型別為T的RDD上執行時,func的函式型別必須是Iterator[T] => Iterator[U]
mapPartitionsWithIndex(func)類似於mapPartitions,但func帶有一個整數參數列示分片的索引值,因此在型別為T的RDD上執行時,func的函式型別必須是(Int, Interator[T]) => Iterator[U]
sample(withReplacement, fraction, seed)根據fraction指定的比例對資料進行取樣,可以選擇是否使用隨機數進行替換,seed用於指定隨機數生成器種子
union(otherDataset)對源RDD和引數RDD求並集後返回一個新的RDD
intersection(otherDataset)對源RDD和引數RDD求交集後返回一個新的RDD
distinct([numTasks]))對源RDD進行去重後返回一個新的RDD
groupByKey([numTasks])在一個(K,V)的RDD上呼叫,返回一個(K, Iterator[V])的RDD
reduceByKey(func, [numTasks])在一個(K,V)的RDD上呼叫,返回一個(K,V)的RDD,使用指定的reduce函式,將相同key的值聚合到一起,與groupByKey類似,reduce任務的個數可以通過第二個可選的引數來設定
aggregateByKey(zeroValue)(seqOp, combOp, [numTasks])
sortByKey([ascending], [numTasks])在一個(K,V)的RDD上呼叫,K必須實現Ordered介面,返回一個按照key進行排序的(K,V)的RDD
sortBy(func,[ascending], [numTasks])與sortByKey類似,但是更靈活
join(otherDataset, [numTasks])在型別為(K,V)和(K,W)的RDD上呼叫,返回一個相同key對應的所有元素對在一起的(K,(V,W))的RDD
cogroup(otherDataset, [numTasks])在型別為(K,V)和(K,W)的RDD上呼叫,返回一個(K,(Iterable,Iterable))型別的RDD
cartesian(otherDataset)笛卡爾積
pipe(command, [envVars])
coalesce(numPartitions)
repartition(numPartitions)
repartitionAndSortWithinPartitions(partitioner)
Action
方法(運算元)說明
reduce(func)通過func函式聚集RDD中的所有元素,這個功能必須是課交換且可並聯的
collect()在驅動程式中,以陣列的形式返回資料集的所有元素
count()返回RDD的元素個數
first()返回RDD的第一個元素(類似於take(1))
take(n)返回一個由資料集的前n個元素組成的陣列
takeSample(withReplacement,num, [seed])返回一個陣列,該陣列由從資料集中隨機取樣的num個元素組成,可以選擇是否用隨機數替換不足的部分,seed用於指定隨機數生成器種子
takeOrdered(n, [ordering])
saveAsTextFile(path)將資料集的元素以textfile的形式儲存到HDFS檔案系統或者其他支援的檔案系統,對於每個元素,Spark將會呼叫toString方法,將它裝換為檔案中的文字
saveAsSequenceFile(path)將資料集中的元素以Hadoop sequencefile的格式儲存到指定的目錄下,可以使HDFS或者其他Hadoop支援的檔案系統。
saveAsObjectFile(path)
countByKey()針對(K,V)型別的RDD,返回一個(K,Int)的map,表示每一個key對應的元素個數。
foreach(func)在資料集的每一個元素上,執行函式func進行更新。

2.1.2 我的感性認識

剛開始我對RDD也是很迷惑,它是在哪裡體現了並行化計算的?但是當我真正正正做一個完整的案例時,我才對他有那麼一點理解。

大家可以想一個完整的離線計算案例,比如:

我們需要計算美團上外賣的標籤,那麼我們會有類似以下資料集:

商品ID使用者ID評價(String)
109283yyyyxxx味道還不錯,就是有點貴
109283swssim雖然有點貴,但是分量足
109284swssim好難吃!

我們的目標是針對商品做標籤,依據是商品出現最多的5個評價標籤。

  • 1、 首先我們通過sparkContext讀取資料
  • 2、 因為我們拿到的是評價String,所以做分詞,這裡假設分詞調包成功,評價此時不再是一個長長的話,而是:評價1,評價2
  • 3、 接下來,提取出商品ID,評價
  • 4、 根據商品ID聚類,即groupByKey
  • 5、 對後面標籤做操作…

請大家注意第3步,我們的程式放到叢集中,而叢集中顯然不止一臺worker,即顯然不止一個executor,所以我們整個spark叢集中每一個executor拿到的只是整個資料集的一部分(第一臺拿0 - n-1行,第二臺拿n - 2n-1行類似這樣),但是我們的操作是寫在一份程式裡面,如何對不同機器中的資料集做統一的操作呢?

這顯然就是RDD的作用,程式提交時會經過cluster manager分配資源、通過driver提交程式碼到executor,然後經過各種scheduler把程式進行分析,分成多個stage每一個stage代表了不需要跨機器執行的操作的集合(比如map、filter),而當出現要跨機器操作(比如collect、reduce)時,則會把資料集中到一臺機器去操作。

說了那麼多,RDD到底是什麼呢?

解釋1 : 因為每一臺機器都知道哪幾步本機器不需要依靠別人可以自己做(stage),所以可以先做,不需要看別人臉色,而遇到大家統一的操作時通過網路把資料合併由一臺機器做。RDD就是定義這些操作的物件,RDD操作的物件就是分佈在不同機器上的同一格式的資料集。

解釋2 : 資料集分佈在不同機器中,RDD定義了各個機器對這份資料的同一操作(先做什麼再做什麼)。就好像你安排你的小弟,去不同銀行,插入銀行卡,輸入密碼,取5000塊錢,然後拿回來,最後給你彙總一樣。

參考

總結

Spark毫無疑問是個非常優秀的框架,其中的元件就彷彿積木一般隨時插拔。RDD作為Spark的最重要的概念,對Spark整個框架起著至關重要的作用。RDD的操作分為Transoformation和Action兩種,其核心理念是定義一個抽象的資料操作,從而方便每個分割槽針對各自所管理的資料做統一的操作。今天這篇部落格可能還有很多沒法講清楚的地方,接下來我會繼續把Spark的其他概念、RDD涉及的相關概念更詳細的給大家理清楚。

相關文章