Spark是一個基於內存的,用於大規模數據處理(離線計算、實時計算、快速查詢(交互式查詢))的統一分析引擎。
它內部的組成模塊,包含SparkCore,SparkSQL,SparkStreaming,SparkMLlib,SparkGraghx等...
它的特點:
Spark計算速度是MapReduce計算速度的10-100倍
MR支持1種計算模型,Spsark支持更多的計算模型(算法多)
Spark 能夠進行離線計算、交互式查詢(快速查詢)、實時計算、機器學習、圖計算
Spark支持大數據中的Yarn調度,支持mesos。可以處理hadoop計算的數據。
二、Spark有幾種部署方式,請分別簡要論述
1) Local:運行在一臺機器上,通常是練手或者測試環境。
2)Standalone:構建一個基於Mster+Slaves的資源調度集群,Spark任務提交給Master運行。是Spark自身的一個調度系統。
3)Yarn: Spark客戶端直接連接Yarn,不需要額外構建Spark集群。有yarn-client和yarn-cluster兩種模式,主要區別在於:Driver程序的運行節點。
4)Mesos:國內大環境比較少用。
三、Spark提交作業的參數
因為我們Spark任務是採用的Shell腳本進行提交,所以一定會涉及到幾個重要的參數,而這個也是在面試的時候容易被考察到的「細節」。
executor-cores —— 每個executor使用的內核數,默認為1,官方建議2-5個,我們企業是4個
num-executors —— 啟動executors的數量,默認為2
executor-memory —— executor內存大小,默認1G
driver-cores —— driver使用內核數,默認為1
driver-memory —— driver內存大小,默認512M四、簡述Spark的作業提交流程
Spark的任務提交方式實際上有兩種,分別是YarnClient模式和YarnCluster模式。大家在回答這個問題的時候,也需要分類去介紹。千萬不要被冗長的步驟嚇到,一定要學會總結差異,發現規律,通過圖形去增強記憶。
在YARN Client模式下,Driver在任務提交的本地機器上運行,Driver啟動後會和ResourceManager通訊申請啟動ApplicationMaster,隨後ResourceManager分配container,在合適的NodeManager上啟動ApplicationMaster,此時的ApplicationMaster的功能相當於一個ExecutorLaucher,只負責向ResourceManager申請Executor內存。
ResourceManager接到ApplicationMaster的資源申請後會分配container,然後ApplicationMaster在資源分配指定的NodeManager上啟動Executor進程,Executor進程啟動後會向Driver反向註冊,Executor全部註冊完成後Driver開始執行main函數,之後執行到Action算子時,觸發一個job,並根據寬依賴開始劃分stage,每個stage生成對應的taskSet,之後將task分發到各個Executor上執行。
在YARN Cluster模式下,任務提交後會和ResourceManager通訊申請啟動ApplicationMaster,隨後ResourceManager分配container,在合適的NodeManager上啟動ApplicationMaster,此時的ApplicationMaster就是Driver。
Driver啟動後向ResourceManager申請Executor內存,ResourceManager接到ApplicationMaster的資源申請後會分配container,然後在合適的NodeManager上啟動Executor進程,Executor進程啟動後會向Driver反向註冊,Executor全部註冊完成後Driver開始執行main函數,之後執行到Action算子時,觸發一個job,並根據寬依賴開始劃分stage,每個stage生成對應的taskSet,之後將task分發到各個Executor上執行。
五、你是如何理解Spark中血統(RDD)的概念?它的作用是什麼?
RDD 可是Spark中最基本的數據抽象,我想就算面試不被問到,那自己是不是也應該非常清楚呢!
下面提供菌哥的回答,供大家參考:
RDD是彈性分布式數據集,是Spark中最基本的數據抽象,代表一個不可變、可分區、裡面的元素可並行計算 的集合。
提供了一個抽象的數據模型,將具體的應用邏輯表達為一系列轉換操作(函數)。另外不同RDD之間的轉換操作之間還可以形成依賴關係,進而實現管道化,從而避免了中間結果的存儲,大大降低了數據複製、磁碟IO和序列化開銷,並且還提供了更多的API(map/reduec/filter/groupBy...)
如果還想錦上添花,可以添上這一句:
「RDD在Lineage依賴方面分為兩種Narrow Dependencies與Wide Dependencies,用來解決數據容錯時的高效性以及劃分任務時候起到重要作用
」六、簡述Spark的寬窄依賴,以及Spark如何劃分stage,每個stage又根據什麼決定task個數?Spark的寬窄依賴問題是SparkCore部分的重點考察內容,多數出現在筆試中,大家需要注意。
窄依賴:父RDD的一個分區只會被子RDD的一個分區依賴
寬依賴:父RDD的一個分區會被子RDD的多個分區依賴(涉及到shuffle)
那Stage是如何劃分的呢?
根據RDD之間的依賴關係的不同將Job劃分成不同的Stage,遇到一個寬依賴則劃分一個Stage。
每個stage又根據什麼決定task個數?
Stage是一個TaskSet,將Stage根據分區數劃分成一個個的Task。
這裡為了方便大家理解,貼上一張過程圖
七、列舉Spark常用的transformation和action算子,有哪些算子會導致Shuffle?我們在Spark開發過程中,避不開與各種算子打交道,其中Spark 算子分為transformation 和 action 算子,下面列出一些常用的算子,具體的功能還需要小夥伴們自行去了解。
transformation
action
如果面試官問你,那小夥幾,有哪些會引起Shuffle過程的Spark算子呢?
你只管自信的回答:
八、reduceByKey與groupByKey的區別,哪一種更具優勢?既然你上面都提到 reduceByKey 和groupByKey ,那哪一種更具優勢,你能簡單分析一下嗎?
能問這樣的問題,已經暗示面試官的水平不低了,那麼我們該如何回答呢:
reduceByKey:按照key進行聚合,在shuffle之前有combine(預聚合)操作,返回結果是RDD[k,v]。
groupByKey:按照key進行分組,直接進行shuffle
所以,在實際開發過程中,reduceByKey比groupByKey,更建議使用。但是需要注意是否會影響業務邏輯。
九、Repartition和Coalesce 的關係與區別,能簡單說說嗎?
這道題就已經開始摻和有「源碼」的味道了,為什麼呢?
1)關係:
兩者都是用來改變RDD的partition數量的,repartition底層調用的就是coalesce方法:coalesce(numPartitions, shuffle = true)
2)區別:
repartition一定會發生shuffle,coalesce 根據傳入的參數來判斷是否發生shuffle。
一般情況下增大rdd的partition數量使用repartition,減少partition數量時使用coalesce。
十、簡述下Spark中的緩存(cache和persist)與checkpoint機制,並指出兩者的區別和聯繫
關於Spark緩存和檢查點的區別,大致可以從這3個角度去回答:
Persist 和 Cache將數據保存在內存,Checkpoint將數據保存在HDFS
Persist 和 Cache 程序結束後會被清除或手動調用unpersist方法,Checkpoint永久存儲不會被刪除。
Persist 和 Cache,不會丟掉RDD間的依賴鏈/依賴關係,CheckPoint會斬斷依賴鏈。
十一、簡述Spark中共享變量(廣播變量和累加器)的基本原理與用途
關於Spark中的廣播變量和累加器的基本原理和用途,答案較為固定,大家無需刻意去記憶。
累加器(accumulator)是Spark中提供的一種分布式的變量機制,其原理類似於mapreduce,即分布式的改變,然後聚合這些改變。累加器的一個常見用途是在調試時對作業執行過程中的事件進行計數。
廣播變量是在每個機器上緩存一份,不可變,只讀的,相同的變量,該節點每個任務都能訪問,起到節省資源和優化的作用。它通常用來高效分發較大的對象。
十二、當Spark涉及到資料庫的操作時,如何減少Spark運行中的資料庫連接數?嗯,有點「調優」的味道,感覺真正的「風暴」即將到來,這道題還是很好回答的,我們只需要減少連接資料庫的次數即可。
使用foreachPartition代替foreach,在foreachPartition內獲取資料庫的連接。
十三、能介紹下你所知道和使用過的Spark調優嗎?恐怖如斯,該來的還是會來的,慶幸自己看了菌哥的面試殺招,絲毫不慌:
資源參數調優num-executors:設置Spark作業總共要用多少個Executor進程來執行executor-memory:設置每個Executor進程的內存executor-cores:設置每個Executor進程的CPU core數量driver-memory:設置Driver進程的內存spark.default.parallelism:設置每個stage的默認task數量開發調優「①使用reduceByKey/aggregateByKey替代groupByKey
②使用mapPartitions替代普通map
③使用foreachPartitions替代foreach
④使用filter之後進行coalesce操作
⑤使用repartitionAndSortWithinPartitions替代repartition與sort類操作
」「在算子函數中使用到外部變量時,默認情況下,Spark會將該變量複製多個副本,通過網絡傳輸到task中,此時每個task都有一個變量副本。如果變量本身比較大的話(比如100M,甚至1G),那麼大量的變量副本在網絡中傳輸的性能開銷,以及在各個節點的Executor中佔用過多內存導致的頻繁GC(垃圾回收),都會極大地影響性能。
」「在可能以及合適的情況下,使用佔用內存較少的數據結構,但是前提是要保證代碼的可維護性。
」如果能夠儘可能的把這些要點說出來,我想面試官可能就一個想法:
十四、如何使用Spark實現TopN的獲取(描述思路或使用偽代碼)?能讓你使用偽代碼來描述這已經非常「苛刻」了,但是不慌,這裡提供3種思路供大家參考:
(1)按照key對數據進行聚合(groupByKey)
(2)將value轉換為數組,利用scala的sortBy或者sortWith進行排序(mapValues)
注意:當數據量太大時,會導致OOM
(1)取出所有的key
(2)對key進行迭代,每次取出一個key利用spark的排序算子進行排序
(1)自定義分區器,按照key進行分區,使不同的key進到不同的分區
(2)對每個分區運用spark的排序算子進行排序