本章要點(diǎn):
- 什么是spark
- Spark生態(tài)圈
- RDD編程模型
1.1 什么是Spark
Apache Spark是一個(gè)由加州大學(xué)伯克利分校開(kāi)發(fā)的一站式通用大數(shù)據(jù)框架榔昔,是圍繞速度势决、易用性和復(fù)雜分析構(gòu)建的大數(shù)據(jù)處理框架虚缎。Spark的核心技術(shù)是彈性分布式數(shù)據(jù)集(Resilient Distributes Dataset吕世,RDD)翻翩,提供了更加豐富的MapReduce模型檐盟,擁有Hadoop MapReduce的所有優(yōu)點(diǎn)褂萧,但是與Hadoop和Storm等其他大數(shù)據(jù)和MapReduce技術(shù)相比,Spark還有如下優(yōu)勢(shì):Spark提供了一個(gè)全面葵萎、統(tǒng)一的框架用于管理各種有著不同性質(zhì)(文本數(shù)據(jù)导犹、圖表數(shù)據(jù)等)的數(shù)據(jù)集和數(shù)據(jù)源(批量數(shù)據(jù)或?qū)崟r(shí)的流數(shù)據(jù))的大數(shù)據(jù)處理的需求,還支持復(fù)雜的機(jī)器學(xué)習(xí)羡忘。
1.2 Spark 生態(tài)圈
Spark是基于RDD谎痢,提供了一站式多維度的大數(shù)據(jù)計(jì)算模型【淼瘢可以在一個(gè)技術(shù)棧里快速對(duì)數(shù)據(jù)進(jìn)行批處理节猿、即席查詢、機(jī)器學(xué)習(xí)漫雕、圖計(jì)算和準(zhǔn)實(shí)時(shí)流處理等滨嘱。Spark整個(gè)生態(tài)系統(tǒng)與稱為伯克利數(shù)據(jù)分析棧(RDAS)。其核心框架是Spark蝎亚,同時(shí)BDAS涵蓋支持?jǐn)?shù)據(jù)結(jié)構(gòu)化數(shù)據(jù)SQL查詢與分析的查詢引擎Spark SQL九孩,提供具有機(jī)器學(xué)習(xí)功能的系統(tǒng)MLbase及底層的分布式機(jī)器學(xué)習(xí)庫(kù)MLlib、并行圖計(jì)算框架GraphX发框、流計(jì)算框架Spark Streaming躺彬、采樣近似計(jì)算查詢引擎BlinkDB、內(nèi)存分布式文件系統(tǒng)Tachyon梅惯、資源管理框架Mesos等子項(xiàng)目宪拥。這些子項(xiàng)目在Spark上層提供了更高層、更豐富的計(jì)算范式铣减。
Spark架構(gòu)圖如下:
- Spark Core:包含Spark的基本功能她君;尤其是定義RDD的API、操作以及這兩者上的動(dòng)作葫哗。其他Spark的庫(kù)都是構(gòu)建在RDD和Spark Core之上的
- Spark SQL:提供通過(guò)Apache Hive的SQL變體Hive查詢語(yǔ)言(HiveQL)與Spark進(jìn)行交互的API缔刹。每個(gè)數(shù)據(jù)庫(kù)表被當(dāng)做一個(gè)RDD球涛,Spark SQL查詢被轉(zhuǎn)換為Spark操作。
- Spark Streaming:對(duì)實(shí)時(shí)數(shù)據(jù)流進(jìn)行處理和控制校镐。Spark Streaming允許程序能夠像普通RDD一樣處理實(shí)時(shí)數(shù)據(jù)
- MLlib:一個(gè)常用機(jī)器學(xué)習(xí)算法庫(kù)亿扁,算法被實(shí)現(xiàn)為對(duì)RDD的Spark操作。這個(gè)庫(kù)包含可擴(kuò)展的學(xué)習(xí)算法鸟廓,比如分類从祝、回歸等需要對(duì)大量數(shù)據(jù)集進(jìn)行迭代的操作。
- GraphX:控制圖引谜、并行圖操作和計(jì)算的一組算法和工具的集合牍陌。-GraphX擴(kuò)展了RDD API,包含控制圖员咽、創(chuàng)建子圖毒涧、訪問(wèn)路徑上所有頂點(diǎn)的操作。
RDD 即 Resilient Distributes Dataset(彈性分布數(shù)據(jù)集), 是spark中最基礎(chǔ)骏融、最常用的數(shù)據(jù)結(jié)構(gòu)链嘀。其本質(zhì)是把input source 進(jìn)行封裝萌狂,封裝之后的數(shù)據(jù)結(jié)構(gòu)就是RDD档玻,提供了一系列操作,比如 map茫藏、flatMap误趴、filter等。input source種類繁多务傲,比如hdfs上存儲(chǔ)的文件凉当、本地存儲(chǔ)的文件,相應(yīng)的 RDD的種類也有很多售葡。不同的input source 對(duì)應(yīng)著不同的RDD類型看杭。比如從hdfs上讀取的text對(duì)應(yīng)著HadoopRDD, val hRdd= sc.textFile(“hfs://…….”) 生成的就是HadoopRDD。
1.3 RDD
Spark的理論基礎(chǔ)是RDD,RDD讓Spark實(shí)現(xiàn)了"one stack to rule them all" (一個(gè)技術(shù)堆棧統(tǒng)一數(shù)據(jù)處理)的目標(biāo)挟伙。
1.3.1 RDD抽象概念
RDD是彈性分布式數(shù)據(jù)集的簡(jiǎn)稱楼雹,是一個(gè)抽象的概念。它主要有以下五個(gè)特征:
- 一個(gè)分片列表 partition list
- 一個(gè)計(jì)算函數(shù)compute尖阔,對(duì)每一個(gè)split(分片)進(jìn)行計(jì)算
- 對(duì)其他RDD的依賴列表dependencies list贮缅;依賴又分寬依賴和窄依賴。(可容錯(cuò))
- partitioner for key-value RDDs.比如說(shuō) hash-partitioned rdd(這是可選的介却,并不是所有的add都會(huì)有這個(gè)特征)
- 對(duì)每一個(gè)split計(jì)算的優(yōu)先位置 Preferred Location谴供。比如對(duì)一個(gè)hdfs文件進(jìn)行計(jì)算時(shí),可以獲取優(yōu)先計(jì)算的block locations齿坷。
為了便于理解RDD桂肌,這里給出比較通俗易懂的描述:
- 首先RDD的定義為RDD[T]数焊,可以將RDD理解成T實(shí)例的一個(gè)集合
- 對(duì)應(yīng)的分區(qū)就是將這一組T實(shí)例的集合拆分成多個(gè)子集,這的子集就是數(shù)據(jù)分區(qū)崎场。數(shù)據(jù)以Block昌跌,即塊方式存儲(chǔ)在HDFS上,加載后照雁,在Spark中蚕愤,子集合實(shí)際上對(duì)應(yīng)著分區(qū)的概念。分區(qū)就是將對(duì)應(yīng)大數(shù)據(jù)量的T實(shí)例集合切成多個(gè)小數(shù)據(jù)量的T實(shí)例子集合饺蚊。這個(gè)集合萍诱,對(duì)應(yīng)的內(nèi)部代碼其實(shí)就是Iterator[T]
- 用戶構(gòu)建該RDD的父RDD即是該RDD的父依賴,由于可以有多個(gè)父依賴的RDD因此有對(duì)應(yīng)父RDD的一個(gè)依賴列表污呼。
- 計(jì)算每個(gè)分片的函數(shù)compute裕坊,體現(xiàn)了惰性計(jì)算的特性,比如:MapPartionsRDD燕酷,對(duì)應(yīng)的compute函數(shù)記錄了該RDD對(duì)父依賴的各個(gè)分區(qū)的操作籍凝,也就是記錄了對(duì)MapPartionsRDD各個(gè)分區(qū)的輸入員數(shù)據(jù)進(jìn)行的計(jì)算。
- Key - Value RDD苗缩,其實(shí)就是T類型為Key - Vaule對(duì)的類型饵蒂。
1.3.2 RDD的操作
RDD的操作分為兩類:Transformation與Action。其中Transformation是惰性執(zhí)行的酱讶,惰性執(zhí)行表示真正需要的時(shí)候才會(huì)執(zhí)行退盯,這里實(shí)在需要具體的Action去觸發(fā)才會(huì)開(kāi)始執(zhí)行,每個(gè)Action的觸發(fā)都會(huì)提交一個(gè)Job泻肯。
一個(gè)典型的操作流程圖:
- 首先通過(guò)textFile操作從外部存儲(chǔ)系統(tǒng)HDFS中讀取文件渊迁,構(gòu)建出兩個(gè)RDD實(shí)例A和C;
- 然后A做flapMap和Map轉(zhuǎn)換操作灶挟,對(duì)C做Map型操作和reduceByKey轉(zhuǎn)換操作琉朽;
- 最后對(duì)得到的B和E兩個(gè)做聯(lián)合操作,并通過(guò)saveAsSequenceFile操作將最終的F實(shí)例持久化到外部存儲(chǔ)系統(tǒng)HDFS上稚铣。
Transformation和Action這兩者的區(qū)別可以從它們的返回值查看箱叁,Transformation是將一個(gè)RDD轉(zhuǎn)換為新的RDD,而Action操作會(huì)將結(jié)果反饋到Driver Program或者存儲(chǔ)到外部存儲(chǔ)系統(tǒng)上榛泛。
1.3.3 RDD 的依賴關(guān)系
RDD的依賴分為債依賴和寬依賴蝌蹂,如圖:
- 其中每一個(gè)方框表示一個(gè)RDD,其內(nèi)的陰影表示RDD的分區(qū)曹锨。
- 對(duì)于窄依賴孤个,可以進(jìn)行pipeline操作,即允許在單個(gè)集群節(jié)點(diǎn)上流水線式的執(zhí)行沛简,這個(gè)節(jié)點(diǎn)可以計(jì)算所有父級(jí)分區(qū)齐鲤。
- 而在節(jié)點(diǎn)失敗后的恢復(fù)效率上斥废,在窄依賴中,只有在失敗節(jié)點(diǎn)上丟失的父級(jí)分區(qū)需要重新計(jì)算给郊,并且這些丟失的父級(jí)分區(qū)可以并行的在不同的節(jié)點(diǎn)上重新計(jì)算牡肉。與此相反,在寬依賴的繼承關(guān)系中淆九,單個(gè)失敗的節(jié)點(diǎn)可能導(dǎo)致一個(gè)RDD的所有祖先RDD中的一些分區(qū)丟失统锤,導(dǎo)致計(jì)算的重新執(zhí)行。
對(duì)于RDD依賴可以從以下兩個(gè)方面理解:
- 依賴本身是描述兩個(gè)RDD之間的關(guān)系炭庙。但一個(gè)RDD可以與多個(gè)RDD有依賴關(guān)系饲窿。
- 寬依賴和窄依賴的判斷:在RDD的各個(gè)分區(qū)中對(duì)父RDD的分區(qū)的依賴關(guān)系
-> 窄依賴:子RDD的每個(gè)分區(qū)依賴于常數(shù)個(gè)父分區(qū)(與數(shù)據(jù)規(guī)模無(wú)關(guān))
-> 寬依賴:子RDD的每個(gè)分區(qū)依賴于所有的父RDD的分區(qū)
1.3.4 一個(gè)典型的DAG
Spark將數(shù)據(jù)在分布式環(huán)境下分區(qū),然后講作業(yè)轉(zhuǎn)化為DAG焕蹄,并分階段進(jìn)行DAG的調(diào)度和任務(wù)的分布式并行處理逾雄。
DAG典型示意圖如下:
描述了DAG調(diào)度時(shí)會(huì)根據(jù)Shuffle將Job劃分為Stage,比如A到B之間腻脏,以及F到G之間的數(shù)據(jù)需要經(jīng)過(guò)Shuffle過(guò)程鸦泳,因此A和F是stage的劃分點(diǎn),以及RDD的Lineage(血統(tǒng))關(guān)系永品。其中做鹰,實(shí)線圓角方框標(biāo)識(shí)的是RDD,方框中的矩形塊為分區(qū)腐碱。
這里通過(guò)G和F這兩個(gè)RDD間的依賴關(guān)系誊垢,描述了如何執(zhí)行Stage掉弛。如上圖症见,RDD G對(duì)F的依賴為寬依賴,即對(duì)應(yīng)有Shuffle過(guò)程殃饿,因?yàn)閷?duì)于G這個(gè)RDD就會(huì)創(chuàng)建一個(gè)Stage谋作,這里是Stage3。
RDD的Lineage關(guān)系乎芳,可以從族譜角度去理解遵蚜。即描述了RDD是從哪來(lái)的,以及怎么來(lái)的信息奈惑。
RDD G上一個(gè)Action的執(zhí)行將會(huì)以寬依賴作為基于為分區(qū)來(lái)建構(gòu)各個(gè)Stage吭净,對(duì)各Stage內(nèi)部的窄依賴則前后連接構(gòu)成流水線。
Spark通過(guò)Lineage機(jī)制實(shí)現(xiàn)高容錯(cuò)肴甸,基于DAG圖寂殉,Lineage是輕量級(jí)而高效的,操作之間相互具備Lineage的關(guān)系原在,每個(gè)操作只關(guān)心其父操作友扰,各個(gè)分片的數(shù)據(jù)之間互不影響彤叉,出現(xiàn)錯(cuò)誤的時(shí)候只要恢復(fù)單個(gè)分片或分區(qū)即可。
DAG的Lineage 機(jī)制可以從兩個(gè)方面進(jìn)行理解:
- RDD之間的數(shù)據(jù)流圖村怪,即RDD的各個(gè)分區(qū)的數(shù)據(jù)是從哪來(lái)的
- 基于數(shù)據(jù)流圖之上的操作算子流圖秽浇,即這些數(shù)據(jù)傳遞過(guò)來(lái)的時(shí)候經(jīng)過(guò)哪些算子的操作
可以從RDD的抽象概念來(lái)解析Lineage的這兩個(gè)方面的特性:
- RDD的分區(qū)列表(數(shù)據(jù)塊列表)和對(duì)父RDD的依賴列表:對(duì)應(yīng)RDD類的getPartion和getDependencies,這兩個(gè)方法記錄了改RDD的數(shù)據(jù)來(lái)源甚负,以及來(lái)源數(shù)據(jù)如何獲燃砘馈(對(duì)應(yīng)窄依賴和寬依賴)
其中,RDD各個(gè)分區(qū)的數(shù)據(jù)來(lái)源可以從外部存儲(chǔ)系統(tǒng)或Scala數(shù)據(jù)集獲取梭域,也可以從其他父RDD獲取击喂。 - 計(jì)算每個(gè)分片的函數(shù):對(duì)應(yīng)RDD類的compute方法,該方法記錄了該RDD對(duì)它各個(gè)分區(qū)的數(shù)據(jù)來(lái)源進(jìn)行的計(jì)算碰辅。