關於Spark的面試題,你應該知道這些!

寫在前面: 博主是一名軟件工程系大數據應用開發專業大二的學生,暱稱來源於《愛麗絲夢遊仙境》中的Alice和自己的暱稱。作爲一名互聯網小白,寫博客一方面是爲了記錄自己的學習歷程,一方面是希望能夠幫助到很多和自己一樣處於起步階段的萌新。由於水平有限,博客中難免會有一些錯誤,有紕漏之處懇請各位大佬不吝賜教!個人小站:http://alices.ibilibili.xyz/ , 博客主頁:https://alice.blog.csdn.net/
儘管當前水平可能不及各位大佬,但我還是希望自己能夠做得更好,因爲一天的生活就是一生的縮影。我希望在最美的年華,做最好的自己

        之前分享過一篇博客,👉不會這20個Spark熱門技術點,你敢出去面試大數據嗎?,那一篇確實是非常精華,提煉出了非常重要同樣非常高頻的Spark技術點,也算是收到了一些朋友們的好評。本篇博客,博主打算再出個番外篇,也就是再爲大家分享一些Spark面試題,敢問各位準備好了麼~

在這裏插入圖片描述


1、Spark Application在沒有獲得足夠的資源,job就開始執行了,可能會導致什麼問題發生?

        執行該job時候集羣資源不足,導致執行job結束也沒有分配足夠的資源,分配了部分Executor,該job就開始執行task,應該是task的調度線程和Executor資源申請是異步的;如果想等待申請完所有的資源再執行job的:需要將spark.scheduler.maxRegisteredResourcesWaitingTime設置的很大;spark.scheduler.minRegisteredResourcesRatio 設置爲1,但是應該結合實際考慮,否則很容易出現長時間分配不到資源,job一直不能運行的情況。

2、driver的功能是什麼?

  • 一個Spark作業運行時包括一個Driver進程,也是作業的主進程,具有main函數,並且有SparkContext的實例,是程序的人口點;
  • 功能:負責向集羣申請資源向master註冊信息,負責了作業的調度,負責作業的解析、生成Stage並調度Task到Executor上。包括DAGScheduler,TaskScheduler

3、Spark中Work的主要工作是什麼?

        主要功能:管理當前節點內存,CPU的使用狀況,接收master分配過來的資源指令,通過ExecutorRunner啓動程序分配任務。

        worker就類似於包工頭,管理分配新進程,做計算的服務,相當於process服務。

        需要注意的是:

        1)worker會不會彙報當前信息給master?worker心跳給master主要只有workid,它不會發送資源信息以心跳的方式給master,master分配的時候就知道work,只有出現故障的時候纔會發送資源。

        2)worker不會運行代碼,具體運行的是Executor是可以運行具體appliaction寫的業務邏輯代碼,操作代碼的節點,它不會運行程序的代碼的。

4、Spark爲什麼比mapreduce快?

  1. spark是基於內存進行數據處理的,MapReduce是基於磁盤進行數據處理的
  2. spark中具有DAG有向無環圖,DAG有向無環圖在此過程中減少了shuffle以及落地磁盤的次數
  3. spark是粗粒度資源申請,也就是當提交spark application的時候,application會將所有的資源申請完畢,如果申請不到資源就等待,如果申請到資源才執行application,task在執行的時候就不需要自己去申請資源,task執行快,當最後一個task執行完之後task纔會被釋放。而MapReduce是細粒度資源申請,當提交application的時候,task執行時,自己申請資源,自己釋放資源,task執行完畢之後,資源立即會被釋放,task執行的慢,application執行的相對比較慢。

5、Mapreduce和Spark的都是並行計算,那麼他們有什麼相同和區別?

  • hadoop的一個作業稱爲job,job裏面分爲map task和reduce task,每個task都是在自己的進程中運行的,當task結束時,進程也會結束。
  • spark用戶提交的任務成爲application,一個application對應一個sparkcontext,app中存在多個job,每觸發一次action操作就會產生一個job。這些job可以並行或串行執行,每個job中有多個stage,stage是shuffle過程中DAGSchaduler通過RDD之間的依賴關係劃分job而來的,每個stage裏面有多個task,組成taskset有TaskSchaduler分發到各個executor中執行,executor的生命週期是和app一樣的,即使沒有job運行也是存在的,所以task可以快速啓動讀取內存進行計算。
  • hadoop的job只有map和reduce操作,表達能力比較欠缺而且在mr過程中會重複的讀寫hdfs,造成大量的io操作,多個job需要自己管理關係。 而spark的迭代計算都是在內存中進行的,API中提供了大量的RDD操作如join,groupby等,而且通過DAG圖可以實現良好的容錯

6、Spark應用程序的執行過程是什麼?

  1. 構建Spark Application的運行環境(啓動SparkContext),SparkContext向資源管理器(可以是Standalone、Mesos或YARN)註冊並申請運行Executor資源;
  2. 資源管理器分配Executor資源並啓動StandaloneExecutorBackend,Executor運行情況將隨着心跳發送到資源管理器上;
  3. SparkContext構建成DAG圖,將DAG圖分解成Stage,並把Taskset發送給Task Scheduler。Executor向SparkContext申請Task,Task Scheduler將Task發放給Executor運行同時SparkContext將應用程序代碼發放給Executor。
  4. Task在Executor上運行,運行完畢釋放所有資源。

7、spark on yarn Cluster 模式下,ApplicationMaster和driver是在同一個進程麼?

        是,driver 位於ApplicationMaster進程中。該進程負責申請資源,還負責監控程序、資源的動態情況。

8、Spark on Yarn 模式有哪些優點?

  1. 與其他計算框架共享集羣資源(eg.Spark框架與MapReduce框架同時運行,如果不用Yarn進行資源分配,MapReduce分到的內存資源會很少,效率低下);資源按需分配,進而提高集羣資源利用等。
  2. 相較於Spark自帶的Standalone模式,Yarn的資源分配更加細緻
  3. Application部署簡化,例如Spark,Storm等多種框架的應用由客戶端提交後,由Yarn負責資源的管理和調度,利用Container作爲資源隔離的單位,以它爲單位去使用內存,cpu等。
  4. Yarn通過隊列的方式,管理同時運行在Yarn集羣中的多個服務,可根據不同類型的應用程序負載情況,調整對應的資源使用量,實現資源彈性管理。

9、spark中的RDD是什麼,有哪些特性?

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

        五大特性:

  • A list of partitions:一個分區列表,RDD中的數據都存儲在一個分區列表中
  • A function for computing each split:作用在每一個分區中的函數
  • A list of dependencies on other RDDs:一個RDD依賴於其他多個RDD,這個點很重要,RDD的容錯機制就是依據這個特性而來的
  • Optionally,a Partitioner for key-value RDDs(eg:to say that the RDD is hash-partitioned):可選的,針對於kv類型的RDD纔有這個特性,作用是決定了數據的來源以及數據處理後的去向
  • 可選項,數據本地性,數據位置最優

10、spark如何防止內存溢出?

        driver端的內存溢出 :

        可以增大driver的內存參數:spark.driver.memory (default 1g)

        map過程產生大量對象導致內存溢出:

        具體做法可以在會產生大量對象的map操作之前調用repartition方法,分區成更小的塊傳入map。

        數據不平衡導致內存溢出:

        數據不平衡除了有可能導致內存溢出外,也有可能導致性能的問題,解決方法和上面說的類似,就是調用repartition重新分區。

        shuffle後內存溢出:

        shuffle內存溢出的情況可以說都是shuffle後,單個文件過大導致的。在Spark中,join,reduceByKey這一類型的過程,都會有shuffle的過程,在shuffle的使用,需要傳入一個partitioner,大部分Spark中的shuffle操作,默認的partitioner都是HashPatitioner,默認值是父RDD中最大的分區數,這個參數通過spark.default.parallelism控制(在spark-sql中用spark.sql.shuffle.partitions) , spark.default.parallelism參數只對HashPartitioner有效,所以如果是別的Partitioner或者自己實現的Partitioner就不能使用spark.default.parallelism這個參數來控制shuffle的併發量了。如果是別的partitioner導致的shuffle內存溢出,就需要從partitioner的代碼增加partitions的數量。

        standalone模式下資源分配不均勻導致內存溢出:

        這種情況的解決方法就是同時配置–executor-cores或者spark.executor.cores參數,確保Executor資源分配均勻。使用rdd.persist(StorageLevel.MEMORY_AND_DISK_SER)代替rdd.cache()。

rdd.cache()和rdd.persist(Storage.MEMORY_ONLY)是等價的,在內存不足的時候rdd.cache()的數據會丟失,再次使用的時候會重算,而rdd.persist(StorageLevel.MEMORY_AND_DISK_SER)在內存不足的時候會存儲在磁盤,避免重算,只是消耗點IO時間

11、spark中cache和persist的區別?

        cache:緩存數據,默認是緩存在內存中,其本質還是調用persist。

        persist:緩存數據,有豐富的數據緩存策略。數據可以保存在內存也可以保存在磁盤中,使用的時候指定對應的緩存級別就可以了。

12、Spark手寫WordCount程序

        這個常出現在筆試階段,手寫WordCount算是一項基本技能。

//創建SparkConf並設置App名稱和master地址
val conf=new SparkConf().setAppName(“wc”).setMaster(“Local[*])
//創建SparkContext,該對象是提交Spark App的入口
val sc=new SparkContext(conf)
//使用sc創建RDD並執行相應的transformation和action
val result=sc.textFile(“輸入文件的路徑”)
Val rdd2=result.flatmap(x=>x.split(“ ”))
.map((_,1)).reduceBykey((_+_)).saveAsTextFile(“輸出文件路徑”)
//關閉鏈接
sc.stop()

13、Spark中創建RDD的方式總結3種

        1、從集合中創建RDD;

val rdd = sc.parallelize(Array(1,2,3,4,5,6,7,8))
val rdd = sc.makeRDD(Array(1,2,3,4,5,6,7,8))

        2、從外部存儲創建RDD;

val rdd= sc.textFile("hdfs://node01:8020/data/test")

        3、從其他RDD創建。

val rdd1 = sc.parallelize(Array(1,2,3,4))
val rdd2 =rdd.map(x=>x.map(_*2))

14、常用算子

        這個涉及到的算子就比較多了,感興趣的朋友可以去看看博主的這兩篇博客:

        Spark之【RDD編程】詳細講解(No2)——《Transformation轉換算子》

        Spark之【RDD編程】詳細講解(No3)——《Action行動算子》

        絕對不會讓你失望的~

15、什麼是寬窄依賴

        窄依賴指的是每一個父RDD的Partition最多被子RDD的一個Partition使用。
        寬依賴指的是多個子RDD的Partition會依賴同一個父RDD的Partition,會引起shuffle。

16、任務劃分的幾個重要角色

        RDD任務切分中間分爲:Application、Job、Stage和Task

        1)Application:初始化一個SparkContext即生成一個Application;

        2)Job:一個Action算子就會生成一個Job;

        3)Stage:根據RDD之間的依賴關係的不同將Job劃分成不同的Stage,遇到一個寬依賴則劃分一個Stage;

        4)Task:Stage是一個TaskSet,將Stage劃分的結果發送到不同的Executor執行即爲一個Task

17、SparkSQL中RDD、DataFrame、DataSet三者的區別與聯繫?

RDD

        彈性分佈式數據集;不可變、可分區、元素可以並行計算的集合。

優點:

  • RDD編譯時類型安全:編譯時能檢查出類型錯誤;
  • 面向對象的編程風格:直接通過類名點的方式操作數據。

缺點:

  • 序列化和反序列化的性能開銷很大,大量的網絡傳輸;
  • 構建對象佔用了大量的heap堆內存,導致頻繁的GC(程序進行GC時,所有任務都是暫停)

DataFrame

        DataFrame以RDD爲基礎的分佈式數據集。

優點:

  • DataFrame帶有元數據schema,每一列都帶有名稱和類型。
  • DataFrame引入了off-heap,構建對象直接使用操作系統的內存,不會導致頻繁GC。
  • DataFrame可以從很多數據源構建;
  • DataFrame把內部元素看成Row對象,表示一行行的數據
  • DataFrame=RDD+schema

缺點

  • 編譯時類型不安全;
  • 不具有面向對象編程的風格。

Dataset

        DataSet包含了DataFrame的功能,Spark2.0中兩者統一,DataFrame表示爲DataSet[Row],即DataSet的子集。

        (1)DataSet可以在編譯時檢查類型;

        (2)並且是面向對象的編程接口。

        (DataSet 結合了 RDD 和 DataFrame 的優點,並帶來的一個新的概念 Encoder。當序列化數據時,Encoder 產生字節碼與 off-heap 進行交互,能夠達到按需訪問數據的效果,而不用反序列化整個對象。)。

三者之間的轉換:

在這裏插入圖片描述

18、自定義函數的過程

        1)創建DataFrame

scala> val df = spark.read.json("/export/spark/examples/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

        2)打印數據

scala> df.show()
+----+-------+
| age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|

        3)註冊UDF,功能爲在數據前添加字符串

scala> spark.udf.register("addName", (x:String)=> "Name:"+x)
res5: org.apache.spark.sql.expressions.UserDefinedFunction = UserDefinedFunction(<function1>,StringType,Some(List(StringType)))

        4)創建臨時表

scala> df.createOrReplaceTempView("people")

        5)應用UDF

scala> spark.sql("Select addName(name), age from people").show()
+-----------------+----+
|UDF:addName(name)| age|
+-----------------+----+
|     Name:Michael|null|
|        Name:Andy|  30|
|      Name:Justin|  19|

        本篇博客就分享到這裏,建議所有沒看過開頭提到的《不會這20個Spark熱門技術點,你敢出去面試大數據嗎?》這篇博客的朋友都去閱讀一下,真的牆裂推薦!!!

        如果以上過程中出現了任何的紕漏錯誤,煩請大佬們指正😅

        受益的朋友或對大數據技術感興趣的夥伴記得點贊關注支持一波🙏

        希望我們都能在學習的道路上越走越遠😉
在這裏插入圖片描述

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