spark大數據架構初學入門基礎詳解

Spark是什麼

 


a) 是一種通用的大數據計算框架


b) Spark Core 離線計算


        Spark SQL 交互式查詢


 Spark Streaming 實時流式計算


 Spark MLlib 機器學習


 Spark GraphX 圖計算


c) 特點:


i. 一站式:一個技術堆棧解決大數據領域的計算問題


ii. 基於內存


d) Spark2009年誕生於伯克利大學的AMPLab實驗室


2010年正式開源了Spark項目


2013年Spark成爲Apache下的項目


2014年飛速發展,成爲Apache的頂級項目


2015年在國內興起,代替mr,hive,storm等


作者:辛湜(shi)


e) Spark和Hive:


Spark優點:


i. 速度快


ii. Spark SQL支持大量不同的數據源


f) Spark 和Storm


i. 計算模型不一樣


ii. Spark吞吐量大


g) 特點:快,易用,通用,兼容性


h) spark運行模式


i. local(本地)


ii. standalone(集羣)


iii. on yarn(由 yarn作爲資源調度Spark負責任務調度和計算)


iv. on mesos(由mesos作爲資源調度S)


v. on cloud()


i) 配置步驟


=======================on yarn====================


【說明】


1. spark任務運行在yarn上,由yarn來進行資源調度和管理,spark只負責任務的調度 和計算


2. 不需要配置和啓動spark集羣


3. 只需要在提交任務的節點上安裝並配置spark on yarn 模式


4. 必須找一臺節點安裝spark


5. 步驟:


i. 安裝配置JDK


ii. vi spark-env.sh


1. export  JAVA_HOME=/opt/modules/jdk1.7_6.0


2. export  HADOOP_CONF_DIR = /opt/modules/hadoop/etc/hadoop


iii. 測試spark on yarn 模式是否安裝成功


iv. 網絡測試:http://hadoop-yarn1.beicai.com:8088


=====================sdandalone模式==============


【說明】


1.  spark運行在spark 集羣上,由spark進行資源調度管理,同時還負責任務的調度和 計算


2. 需要配置和啓動spark集羣


3. 步驟:


i. 安裝配置JDK


ii. 上傳並解壓Spark


iii. 建立軟連接 ln -s spark spark 或者修改名稱


iv. 配置環境變量


v. 安裝配置Spark,修改spark配置文件(spark-env.sh, slaves)


1. vi spark-env.sh


a) export  JAVA_HOME=/opt/modules/jdk(jdk位置)


b) export SPARK_MASTER_IP=hadoop-yarn1.beicai.com


c) export SPARK_MASTER_PORT=7077


2.  vi slaves(用於指定在哪些節點上啓動worker)


a) hadoop-yarn2.beicai.com


hadoop-yarn3.beicai.com


vi. 將spark發送給其他主機


vii. 啓動


/opt/modules/spark/bin/start-all.sh


vii. 查看SparkUI界面:http://hadoop-yarn1.beicai.com:8080


4. 


j) 


一、Spark原理


  1、Spark的運行原理


i、分佈式


Ii、主要基於內存(少數情況基於磁盤)


Iii、迭代式計算


2、Spark 計算模式 VS  MapReduce  計算模式對比


 


          Mr這種計算模型比較固定,只有兩種階段,map階段和reduce階段,兩個階段結束    後,任務就結束了,這意味着我們的操作很有限,只能在map階段和reduce階段,    也同時意味着可能需要多個mr任務才能處理完這個job


 


   Spark 是迭代式計算,一個階段結束後,後面可以有多個階段,直至任務計算完      成,也就意味着我們可以做很多的操作,這就是Spark計算模型比mr 強大的地方


 


三、什麼是Spark RDD?


 


1、什麼是RDD?


彈性的,分佈式的,數據集


 


(RDD在邏輯上可以看出來是代表一個HDFS上的文件,他分爲多個分區,散落 在Spark的多個節點上)


3、RDD----彈性


當RDD的某個分區的數據保存到某個節點上,當這個節點的內存有限,保存不了這個 分區的全部數據時,Spark就會有選擇性的將部分數據保存到硬盤上,例如:當worker 的內存只能保存20w條數據時,但是RDD的這個分區有30w條數據,這時候Spark就 會將多餘的10w條數據,保存到硬盤上去。Spark的這種有選擇性的在內存和硬盤之間的權衡機制就是RDD的彈性特點所在


 


4、Spark的容錯性


RDD最重要的特性就是,提供了容錯性,可以自動的從失敗的節點上恢復過來,即如 果某個節點上的RDD partition(數據),因爲節點的故障丟了,那麼RDD會自動的通過 自己的數據來源重新計算該partition,這一切對使用者來說是透明的



2、Spark的開發類型


 


   (1)、核心開發:離線批處理 / 演示性的交互式數據處理


        


       (2)、SQL查詢:底層都是RDD和計算操作


 


       (3)、底層都是RDD和計算操作


 


       (4)、機器學習


 


       (5)、圖計算


 


3、Spark 核心開發(Spark-core == Spark-RDD)步驟


 


   (1)、創建初始的RDD


 


   (2)、對初始的RDD進行轉換操作形成新的RDD,然後對新的RDD再進行操作,直 至操作計算完成


 


(3)、將最後的RDD的數據保存到某種介質中(hive、hdfs,MySQL、hbase...)


 


五、Spark原理


Driver,Master,Worker,Executor,Task各個節點之間的聯繫


 


 


Spark中的各節點的作用:


1、driver的作用:


    (1)、 向master進行任務的註冊


(2)、構建運行任務的基本環境


(3)、接受該任務的executor的反向註冊


(4)、向屬於該任務的executor分配任務


 


2、什麼是driver?


   我們編寫的程序打成jar包後,然後找一臺能夠連接spark集羣的節點做任務的driver,具體的表現爲SparkSubmit


 


3、Master的作用:


   (1)、監控集羣;


   (2)、動態感知worker的上下線;


   (3)、接受driver端註冊請求;


   (4)、任務資源的調度


 


4、Worker的作用:


   (1)、定時向master彙報狀態;


   (2)、接受master資源調度命令,進行資源的調度


   (3)、啓動任務的容器Executor


 


5、Executor的作用:


   (1)、保存計算的RDD分區數據;


   (2)、向Driver反向註冊;


   (3)、接受Driver端發送來的任務Task,作用在RDD上進行執行


 


 


Spark 編程的流程:


 


1、我們編寫的程序打包成jar包,然後調用Spark-Submit 腳本做任務的提交


 


2、啓動driver做任務的初始化


 


3、Driver會將任務極其參數(core,memory,driver相關的參數)進行封裝成ApplicationDescript通過taskSchedulerImpl 提交給Master


 


4、Master接受到driver端註冊任務請求時,會將請求參數進行解析,並封裝成APP,然後進行持久化,並且加入到其任務隊列中的waitingAPPs


 


5、當輪到咱們提交的任務運行時,master會調用schedule()這個方法,做任務資源調度


 


6、Master將調度好的資源封裝成launchExecutor,發送給指定的worker


 


7、Worker接收到發送來的launchExecutor時,會將其解析並封裝成ExecutorRunner,然後調用start方法,啓動Executor


 


8、Executor啓動後,會向任務的Driver進行反向註冊


 


9、當屬於這個任務的所有executor啓動成功並反向註冊完之後,driver會結束SparkContext對象的初始化


 


10、當sc 初始化成功後,意味着運行任務的基本環境已經準備好了,driver會繼續運行我們編寫好的代碼


 


11、開始註冊初始的RDD,並且不斷的進行轉換操作,當觸發了一個action算子時,意味着觸發了一個job,此時driver就會將RDD之間的依賴關係劃分成一個一個的stage,並將stage封裝成taskset,然後將taskset中的每個task進行序列化,封裝成launchtask,發送給指定的executor執行


 


12、Executor接受到driver發送過來的任務task,會對task進行反序列化,然後將對應的算子(flatmap,map,reduceByKey。。。。)作用在RDD分區上


 


 


六、RDD詳解


 


 1、什麼是RDD?


RDD(Resilient Disttibuted Dataset)叫做彈性的分佈式的數據集,是spark中最基本的數據抽象,它代表一個不可變,可分區,裏面的元素可並行計算的集合


 


 2、RDD的特點:


自動容錯


位置感知性調度


伸縮性


 


 3、RDD的屬性:


(1)、一組分片(partition),即數據集的基本組成單位。對於RDD來說,每個分片都會被一個計算任務處理,並決定並行計算的粒度,用戶可以在創建RDD時指定RDD的分片個數,如果沒有指定,那麼就會採用默認值,默認值就是程序所分配到的CPU Core的數目


(2)、一個計算每個分區的函數。Spark中RDD的計算是以分片爲單位的,每個RDD都會實現computer函數以達到這個目的。Computer函數會對迭代器進行復合,不需要保存每次計算的結果。


(3)、RDD之間的依賴關係。RDD的每次轉換都會生成一個新的RDD,所以RDD之間就會形成類似於流水一樣的前後依賴關係。在部分分區數據丟失時,Spark可以通過這個依賴關係重新計算丟失的分區數據,而不是對RDD的所有分區進行重新計算。


(4)、一個partition,即RDD的分片函數。當前Spark中實現了兩種類型的分片函數,一個是基於hashPartitioner,另外一個是基於範圍的RangePartitioner。只有對於key-value的RDD,纔會有Partitioner,非key-value的RDD的Partitioner的值是None。Partitioner函數不但決定了RDD本身的分片數量,也決定了partition RDD Shuffle輸出時的分片數量。


(5)、一個列表,存儲存取每個Partition的優先位置(preferred location)。對於一個HDFD文件來說。這個列表保存的就是每個Partition所在的快的位置。按照“移動數據不如移動計算”的理念。Spark在進行任務調度的時候,會儘可能的將計算任務分配到所要處理數據塊的存儲位置。


 


 


4、RDD的創建:


   進行Spark核心編程時,首先要做的事就是創建一個初始的RDD。Spark Core提供了三種創建RDD的方式:


(1)、使用程序中的集合創建RDD (調用parallelize()方法)


(2)、使用本地文件創建RDD  (調用textFile()方法)


(3)、使用HDFD文件創建RDD  (調用textFile()方法)


 


七、算子


   


   1、什麼是算子?


是RDD中定義的作用在每一個RDD分片上的函數,可以對RDD中的數據進行轉換 和操作


 


   2、RDD算子的分類


(1)、Transformation算子,這類算子變換不觸發提交作業(特點就是lazy特性)


返回的是一個RDD


(2)、Action算子,這類算子會觸發SparkContext提交作業(觸發一個spark job的運行,從而觸發這個action之前所有的transformation的執行)


返回的是一個spark對象


   


   3、常用的Transformation算子


八、RDD分區排序


 


  I、分區


兩種實現方式:coalesce  和 repartition(底層調用coalesce)


 


coalesce(numPartitons,isShuffle)


第一個參數是重分區後的數量,第二個參數是是否進行shuffle


如果原來有N個分區,重分區後有M個分區


如果 M > N ,必須將第二參數設置爲true(也就是進行shuffle),等價於 repartition(numPartitons)    如果是false將不起作用  


如果M < N


100-->10 重分區後的分區數比原來的小的多,那麼久需要使用shuffle,也即是設置爲true


100-->90 重分區後的分區數和原來的差不多的,那麼就不需要使用shuffle,也就是設置爲false


 


II、排序


sortBy(x => x)  這個算子中帶有隱式轉換參數


 


x 能夠排序(比較大小),那麼這個類就必須有比較大小的功能,也就是實現了compareTo 或者compare


 


實現二次排序有兩種方法:


1、繼承Comparable 接口 或者 Ordered


2、隱式轉換:可以定義隱式轉換函數(Ordered)或者隱式轉換值(Ordering)


 


九、自定義分區


 


自定義分區


要求:按照key將對應的value輸出到指定的分區中


解釋:自定義一個自定義分區類,繼承partitioner,實現他的兩個方法


      1、numPartitions


      2、getPartition


具體的功能根據項目的要求自定義實現,然後調用partitionBy方法,new出自定義的類,傳入參數即可


九、RDD持久化原理


   


1、持久化場景:對於一個rdd會被多次引用到,並且這個rdd計算過程複雜,計算時間特變耗時


 


2、如何進行持久化,調用rdd.persist方法或cache方法,cache方法底層就是調用persist方法


 


******************persist(StorageLevel.MEMORY_ONLY)*******************


如果對RDD做持久化,默認持久化級別是storageLevel.MEMORY_ONLY ,也就是持久化到內存中去,這種持久化級別是效率最快的,但是由於是純Java 對象,保存到內存中,那麼內存可能保存的數量就會較少


***************persist(StorageLevel.MEMORY_ONLY_SER)****************


如果當我們集羣資源有限時,那麼我們可以採用MEMORY_ONLY_SER,也就是將Java對象進行序列化之後持久到內存中去,這種持久化的好處是能夠持久化更多的數據到內存中,但是由於在持久化時需要序列化,取出來之後又需要反序列化這一過程,這個過程會消耗CPU計算資源,性能相對於MEMORY_ONLY 這種持久化級別來說稍微弱點,但是還是比較高效的


 


3、如何選擇RDD持久化策略?


Spark提供的多種持久化級別,主要是爲了在CPU和內存消耗之間進行取捨,下面是一些通用的持久化級別的選擇建議:


  1)、優先使用MEMORY_ONLY,如果可以緩存所有數據的話,那麼就使用這種策略,因爲純內存速度最快,而且沒有序列化,不需要消耗CPU進行反序列化操作


  2)、如果MEMORY_ONLY策略,無法存儲所有數據的話,那麼使用MEMORY_ONLY_SER,將數據進行序列化存儲,純內存操作還是非常快的,只是要消耗CPU進行反序列化


  3)、如果需要進行快速的失敗恢復,那麼就選擇帶後綴爲_2的策略,進行數據的備份,這樣在失敗時,就不需要重新計算了


  4、能不使用DISK相關的策略,就不要使用,有的時候,從磁盤讀取數據,還不如重新計算一次


 


 


十一、共享變量


 


1、共享變量分爲兩種:廣播變量  和   累加器


 


廣播變量(broadcast)


 


2、日常所遇問題


  因爲每個task都需要拷貝這樣的一個副本到executor去執行,那麼我們可以想象一下,如果有1000 個task在某個worker上執行,而這個副本有100M,那麼意味着我們需要拷貝100G的數據都到某個worker上執行,這樣的話會大大消耗我們的網絡流量,同時會加大executor的內存消耗,從而增加了我們spark作業的運行時間,大大降低了spark作業的運行效率,增加了作業失敗的概率


 


3、如何解決以上問題,也就是說什麼時候使用廣播變量?


  當RDD引用到了一個外部變量並且這個外部變量數據量不小,同時這個RDD對應的task數量特別多,那麼此時使用廣播共享變量再合適不過了


  我們可以將這種大的外部變量做成廣播變量,外部變量做成廣播變量的時候,那麼每個executor的內存中只會有一個外部變量,而這個副本針對所有的task都是共享的,這樣的話就減少了網絡流量消耗,降低了executor的內存消耗,提高了spark作業運行效率和縮短了運行時間,同時降低了作業失敗的概率


 


 


4、廣播變量的使用流程:


   1)、某個executor的第一個task先執行,首先會從自己的blockManager中查找外部變量,如果沒有就從鄰居的executor的blockManager的內存中獲取這個外部變量,如果還是獲取不到,就從driver端獲取,拷貝這個外部變量到本地的executor的blockManager


   2)、當這個executor的其他task執行時,就不需要從外面獲取這個外部變量的副本,直接從本地的blockManager中獲取即可


 


 


5、如何獲取廣播變量的值?


   可以直接調用廣播變量的value() 這個方法即可


 


【注意】廣播變量是隻讀的,不可寫


 


 


累加器(Accumulator)


 


Spark提供的Accumulator ,主要用於多個節點對一個變量進行共享性的操作,Accumulator只是提供了累加的功能。但是卻給我們提供了多個task對一個變量並行操作的功能,但是task只能對Accumulator進行累加操作


【注意】task只能對Accumulator進行類加操作,只有Driver程序可以讀取Accumulator的值


RDD分區和容錯機制講解

1、RDD 的Lineage血統


   RDD只支持粗粒度轉換,即在大量記錄上執行的單個操作,將創建RDD的一系列Lineage(血統)記錄下來。以便恢復丟失的分區


 


2、RDD的依賴關係


   RDD和它的父RDD的關係有兩種不同的類型:


1)、窄依賴(一對一,多對一)


形象的比喻:獨生子女


2)、寬依賴(多對多)


形象的比喻:超生


 


註釋:劃分stage的依據就是寬依賴,也就是RDD之間是否有shuffle,shuffle過程就是一個寬依賴過程,shuffle之前的tasks就屬於一個stage,shuffle之後的也屬於一個stage,shuffle之前和之後的操作都是窄依賴


【注意】shuffle過程分爲:shuffle Write過程 和 shuffle read過程


 


4、DAG的生成(有向無環圖)和任務的劃分


   DAG(Directed Acyclic Graph)叫做有向無環圖(有方向無循環的圖)


 


5、一個wordCount過程會產生多少個RDD?


   至少會產生五個RDD,


第一個,從HDFS中加載後得到一個RDD(即使用sc.textFile()算子),即HadoopRDD


  在sc.textFile()過程中還會產生一個RDD(調用map算子),產生一個MapPartitionRDD


第二個,使用flatMap算子,得到一個MapPartitionRDD


第三個,使用map算子,得到一個MapPartitionRDD


第四個,使用reduceByKey算子,也就是在經過了shuffle過程後又會得到一個shuffledRDD


第五個,使用saveAsTextFile算子,再產生一個MapPartitionRDD 



spark程序提交流程講解


Spark任務簡介:


   Spark-submit--->SparkSubmit-->main-->submit-->doRunMain-->RunMain-->通過反射創建我們編寫的主類的實例對象,調用main方法-->開始執行我們編寫的代碼-->初始化SparkContext對象-->創建初始的RDD-->觸發action算子-->提交job-->worker執行任務-->任務結束


 


Spark任務詳解: 


  1)、將我們編寫的程序打成jar包


 


  2)、調用spark-submit腳本提交任務到集羣上運行


 


  3)、運行sparkSubmit的main方法,在這個方法中通過反射的方式創建我們編寫的主類的實例對象,然後調用main方法,開始執行我們的代碼(注意,我們的spark程序中的driver就運行在sparkSubmit進程中)


 


  4)、當代碼運行到創建SparkContext對象時,那就開始初始化SparkContext對象了


 


  5)、在初始化SparkContext對象的時候,會創建兩個特別重要的對象,分別是:DAGScheduler


和TaskScheduler


 


【DAGScheduler的作用】將RDD的依賴切分成一個一個的stage,然後將stage作爲taskSet提交給DriverActor


 


  6)、在構建taskScheduler的同時,會創建兩個非常重要的對象,分別是DriverActor和ClientActor


 


【clientActor的作用】向master註冊用戶提交的任務


【DriverActor的作用】接受executor的反向註冊,將任務提交給executor


 


  7)、當clientActor啓動後,會將用戶提交的任務和相關的參數封裝到ApplicationDescription對象中,然後提交給master進行任務的註冊


 


  8)、當master接受到clientActor提交的任務請求時,會將請求參數進行解析,並封裝成Application,然後將其持久化,然後將其加入到任務隊列waitingApps中


 


  9)、當輪到我們提交的任務運行時,就開始調用schedule(),進行任務資源的調度


 


  10)、master將調度好的資源封裝到launchExecutor中發送給指定的worker


 


  11)、worker接受到Maseter發送來的launchExecutor時,會將其解壓並封裝到ExecutorRunner中,然後調用這個對象的start(), 啓動Executor


 


  12)、Executor啓動後會向DriverActor進行反向註冊


 


  13)、driverActor會發送註冊成功的消息給Executor


 


  14)、Executor接受到DriverActor註冊成功的消息後會創建一個線程池,用於執行DriverActor發送過來的task任務


 


  15)、當屬於這個任務的所有的Executor啓動並反向註冊成功後,就意味着運行這個任務的環境已經準備好了,driver會結束SparkContext對象的初始化,也就意味着new SparkContext這句代碼運行完成


 


  16)、當初始化sc成功後,driver端就會繼續運行我們編寫的代碼,然後開始創建初始的RDD,然後進行一系列轉換操作,當遇到一個action算子時,也就意味着觸發了一個job


 


  17)、driver會將這個job提交給DAGScheduler


 


  18)、DAGScheduler將接受到的job,從最後一個算子向前推導,將DAG依據寬依賴劃分成一個一個的stage,然後將stage封裝成taskSet,並將taskSet中的task提交給DriverActor


 


  19)、DriverActor接受到DAGScheduler發送過來的task,會拿到一個序列化器,對task進行序列化,然後將序列化好的task封裝到launchTask中,然後將launchTask發送給指定的Executor


 


  20)、Executor接受到了DriverActor發送過來的launchTask時,會拿到一個反序列化器,對launchTask進行反序列化,封裝到TaskRunner中,然後從Executor這個線程池中獲取一個線程,將反序列化好的任務中的算子作用在RDD對應的分區上


 


【注意】


Spark的任務分爲爲兩種:


  a、shuffleMapTask:shuffle之前的任務


  b、resultTask:shuffle之後的任務


 


Spark任務的本質:


  將RDD的依賴關係切分成一個一個的stage,然後將stage作爲TaskSet分批次的發送到Executor上執行


 


 


十三、Checkpoint


  


 1、使用checkpoint的場景:


     某個RDD會被多次引用,計算特別複雜,計算特別耗時


     擔心中間某些關鍵的,在後面會反覆幾次使用的RDD,可能會因爲節點的故障,導致持久化數據的丟失


 


 2、如何對RDD進行checkpoint?


1)、設置還原點目錄,設置checkpoint目錄


2)、調用RDD的checkpoint的方法對該RDD進行checkpoint


 


 3、checkpoint的原理


1)、RDD調用了checkpoint方法之後,就接受RDDCheckpointData對象的管理


2)、RDDCheckpointData對象會負責將調用了checkpoint的RDD 的狀態設置爲MarkedForCheckpoint


3)、當這個RDD所在的job運行結束後,會調用最後一個RDD的doCheckpoint,根據其血統向上查找,查找到被標註爲MarkedForCheckpoint狀態的RDD,將其狀態改變爲checkpointingInProgress


4)、啓動一個單獨的job,將血統中標記爲checkpointingInProgress的RDD進行checkpoint,也就是將RDD的數據寫入到checkpoint的目錄中去


5)、當某個節點發生故障,導致包括持久化的數據全部丟失,此時會從還原點目錄還原RDD的每個分區的數據,這樣就不需要從頭開始計算一次


 


4、checkpoint需要注意的地方


因爲RDD在做checkpoint的時候,會單獨啓動一個job對需要進行checkpoint的RDD進行重新計算,這樣就會增加spark作業運行時間,所以spark強烈建議在做checkpoint之前,應該對需要進行checkpoint的RDD進行持久化(即調用 .cache)


 


5、checkpoint 和持久化的區別


1)、是否改變血統:


   持久化(.cache):不會改變RDD的依賴關係,也就是不會改變其血統


   Checkpoint:會改變RDD的血統,做了checkpoint的RDD會清除其所有的依賴關係,並將其父RDD強制設置爲checkpointRDD,並且將RDD的狀態更改爲checkpointed


 


2)、RDD的數據的可靠性:


   持久化:只是將RDD的數據持久化到內存或磁盤中,但是如果節點發生故障,那麼持久化的數據還是會丟失


   Checkpoint:checkpoint的數據保存在第三方高可靠的分佈式的文件系統中,機試節點發生故障,數據也不會丟失,所以checkpoint比持久化可靠性更高


 


 


6、後續


   我們實現了checkpoint 之後,在某個task 又調用了該RDD的iterator() 方法時,就實現了高容錯機制,即使RDD的持久化數據丟失,或者壓根兒就沒有持久化,但是還是可以通過readCheckpointOrComputer() 方法,優先從父RDD-----checkpointRDD中讀取,HDFS(外部文件系統)的數據


 


 


 


 


 


 


 


 


第二部分  spark-sql


 


一、Spark-SQL前世今生


 


  1、Spark SQL的特點


1)、支持多種數據源:Hive、RDD、Parquet、JSON、JDBC等。


2)、多種性能優化技術:in-memory columnar storage、byte-code generation、cost model動態評估等。


3)、組件擴展性:對於SQL的語法解析器、分析器以及優化器,用戶都可以自己重新開發,並且動態擴展


 


  2、Spark SQL的性能優化技術簡介


1)、內存列存儲(in-memory columnar storage)


2)、字節碼生成技術(byte-code generation)


3)、Scala代碼編寫的優化


 


 


  3、Spark SQL and DataFrame


Spark SQL是Spark中的一個模塊,主要用於進行結構化數據的處理。它提供的最核心的編程抽象,就是DataFrame。同時Spark SQL還可以作爲分佈式的SQL查詢引擎。Spark SQL最重要的功能之一,就是從Hive中查詢數據。


 


DataFrame,可以理解爲是,以列的形式組織的,分佈式的數據集合。它其實和關係型數據庫中的表非常類似,但是底層做了很多的優化。DataFrame可以通過很多來源進行構建,包括:結構化的數據文件,Hive中的表,外部的關係型數據庫,以及RDD。


 


 


二、Spark-sql的使用


 


  1、RDD轉換爲DataFrame(兩種)


1)、使用反射的方式來推斷包含了特定數據類型的RDD的元數據


2)、通過編程接口來創建DataFrame


 


  2、UDF自定義函數和UDAF自定義聚合函數


UDF,其實更多的是針對單行輸入,返回一個輸出


UDAF,則可以針對多行輸入,進行聚合計算,返回一個輸出,功能更加強大


 


  3、Spark-SQL工作原理


SqlParse  --------->  解析器


 


Analyser  --------->  分析器


 


Optimizer  --------->   優化器


 


SparkPlan  --------->   物理計劃



流程:


 


1)、自己編寫的SQL語句


大家要知道,只要在數據庫類型的技術裏面,比如:最傳統的MySQL,Oracle等,包括現在大數據領域的數據倉庫,比如hive,他的基本的SQL執行的模型,都是類似的,首先都要生成一條SQL語句的執行計劃


 


2)、通過SqlParser(解析器)生成未解析的邏輯計劃(unresolved LogicalPlan)


3)、通過Analyzer(分析器)生成解析後的邏輯計劃(resolved LogicalPlan)


4)、通過Optimizer(優化器)生成優化後的邏輯計劃(optimized LogicalPlan)


實際上,比如傳統的Oracle等數據庫,通常都會生成多個執行計劃,然後呢,最後有一個優化器,針對多個計劃,選擇一個最好的計劃,而SparkSql這兒的優化指的是,比如說,剛生成的執行計劃中,有些地方的性能是顯而易見的,不太好,舉例說明:


比如說,我們有一個SQL語句,select name from (select ... from ...) where ..=..;


此時,在執行計劃解析出來的時候,其實就是按照他原封不動的樣子,來解析成可以執行的計劃,但是呢,Optimizer 在這裏其實就會對執行計劃進行優化,比如說,發現where 條件,其實可以放在子查詢中,這樣,子查詢的數量大大變小,可以優化執行速度,此時,可能就會變成如下這樣:select name from (select name from ...where ..=..)


 


5)、通過SparkPlan,生成最後的物理計劃(PhysicalPlan)


到物理計劃這裏,那麼其實就是非常“接地氣”的計劃了。就是說,已經很明朗了,從那幾個文件讀取什麼數據,從那幾個文件中讀取,如何進行關聯等等


 


6)、在executor中執行物理計劃


邏輯的執行計劃,更多的是偏向於邏輯,比如說吧,大致就是這種樣子的,


From table students=>filter ... => select name ...


這裏基本上,邏輯計劃都是採用Tree ,樹形結構


 


7)、生成RDD


Select  name  from  students => 解析,從哪裏去查詢,students表,在哪個文件裏,從哪個文件中查詢哪些數據,比如說是name這個列,此外,複雜的SQL,還有,比如說查詢時,是否對錶中的數據進行過濾和篩選,更不用說,複雜時,需要有多表的JOIN(咋傳統數據庫中,比如MySQL,執行計劃還涉及到如何掃描和利用索引)


 


 


 


  4、spark-SQL性能優化


 


1)、設置shuffle過程的並行度:spark.sql.shuffle.partitions(SQLContext.setConf())


 


2)、在hive數據倉庫建設過程中,合理設置數據類型,比如能設置爲int的,就不要設置爲bigInt,減少數據類型導致不必要的內存開銷


 


3)、編寫SQL時,儘量給出明確的列名,比如select name from students。不要寫select * 的方式。


 


4)、並行處理查詢結果:對於spark-SQL查詢的結果,如果數據量比較大,比如超過1000條,那麼就不要一次性的collect()到driver再處理,使用foreach()算子,並行處理查詢結果


5)、緩存表:對於一條SQL語句可能對此使用到的表,可以對其進行緩存,使用 sqlContext.cacheTable(tableName),或者DataFrame.cache()即可,spark-SQL會用內存列存儲的格式進行表的緩存,然後spark-sql就可以僅僅掃描需要使用的列,並且自動優化壓縮,來最小化內存使用和GC開銷,SQLContext.uncacheTable(tableName)可以將表從緩存中移除,用SQLContext。setConf(),設置spark.sql.inMemoryColumnarStorage.batchSize參數(默認10000),可以設置列存儲的單位


6)、廣播join表:spark.sql.autoBroadcastJoinThreshold,默認10485760 (10 MB)。在內存夠用的情況下,可以增加其大小,參數設置了一個表在join的時候,最大在多大以內,可以被廣播出去優化性能


 


 5、Hive on Spark配置


1)、安轉配置好Hive和Spark


2)、Set hive.execution.engine=spark;


3)、set spark.master=spark://mini1:7077


 


 


 


第三部分 spark-streaming


 


1,  Dstream


 


Dstream是sparkStreaming的數據模型,本質就是一連串不間斷的RDD,但是它是一個時間段的RDD.這些時間段的RDD源源不斷的連接在一起。


這個時間可以自己設置,時間設置的越短,實時性越高,但是性能消耗也越大。


 


 


2,  spark streaming從kafka獲取數據,有哪幾種方式?


 


有兩種方式:


1.通過receiver的方式,


2,通過direct的方式,dirrect的方式需要自己來管理偏移量。


 


 


3,  sparkStreaming和storm的區別


 


sparkStreaming是spark裏面的一個做流式準實時計算的組件,它使用的數據結構是Dstream,Dstream裏面是一連串時間片的rdd。


相比於storm,sparkStreaming在實時性,保證數據不丟失方面都不佔用優勢,spark streaming在spark支持者眼中的優勢是spark Streaming具有高吞吐性,最本質來說,sparkStreaming相比於storm的優勢是sparkStreaming可以和spark core,spark SQL無縫整合。


 


 


4.對於需要多次引用的,並且這個dstream計算時間特別耗時,數據特別重要,那麼我們就需要對dstream進行checkpoint,(只有多次引用的,進行持久化就可以了),因爲即使對這個dstream進行持久化,數據也可能會丟失,而checkpoint數據丟失的可能性小,但是這樣會影響spark-streaming的數據吞吐量,因爲在做計算的同時,還需要將數據寫入到外部存儲系統中,會降低spark性能,影響吞吐量,非必要情況下不建議使用


 


5.如何對dstream做checkpoint


 


首先設置還原點目錄,其次調用dstream的checkpoint方法


【注意】:dstream的checkpoint的週期一定要是產生batch時間的整數倍,同時spark官方建議將checkpoint的時間設置爲至少10秒。通常來說,將checkpoint間隔設置爲窗口操作的滑動間隔的5-10倍


 


 


6.spark程序在啓動時,會去這個checkpointPath目錄下查看是否有保存的driver的元數據(1.dstream的操作轉換關係,2.未處理完的batch)信息,當spark-streaming程序在二次啓動後就會去checkpointPath目錄下還原這個程序,加載未處理的batch元數據信息在內存中恢復,繼續進行任務處理


 


 


 


7.爲了保證spark-streaming程序7*24小時運行,那麼我們程序應該具備高可靠性,怎樣具備高可靠性?


 


a.程序出現故障,driver死掉了,流式程序應該具備自動重啓的功能


b.沒有計算完成的rdd在程序異常停止後,下次啓動後還會將未處理的rdd進行處理


【注意】:要在spark_submit中,添加--deploy-mode參數,默認其值爲client,即在提交應用的機器上啓動driver,但是要能夠自動重啓driver,就必須將其值設置爲cluster;此外,需要添加--supervise參數,失敗後自動重啓


//spark_submit --executor-memory 1g --total-execute-cores 5 --deploy-model cluster --supervise


 


 


 


8.啓用預寫機制


a.預寫日誌機制,簡寫爲WAL,全稱爲Write Ahead Log,從spark1.2版本開始,就引入了基於容錯的文件系統的WAL機制。如果啓用該機制,Receiver接收到的所有數據都會寫入配置的checkpoint目錄中的預寫日誌。這中機制可以讓driver在恢復的時候,避免數據丟失,並且可以確保整個實時計算過程中零數據丟失



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