Spark整理

Spark介紹

 

  1. 一個分佈式的並行計算框架
  2. spark是下一代的map-reduce,擴展了mr的數據處理流程
  3. executor都是裝載在container裏運行,container默認內存是1G(參數yarn.scheduler.minimum-allocation-mb定義)
  4. AM(Application Master)在Spark中叫driver,AM向RM申請的是executor資源,當分配完資源後,executor啓動後,由spark的AM向
  5. executor分配task,分配多少task、分配到哪個executor由AM決定,可理解爲spark也有個調度過程,這些task都運行在executor的坑裏
  6. Executor有線程池多線程管理這些坑內的task

Executor伴隨整個app的生命週期(申請的進程的內存一直到任務結束)
線程池模型,省去進程頻繁啓停的開銷

MapReduce的問題


調度慢,啓動map、reduce太耗時
計算慢,每一步都要保存中間結果落磁盤
API抽象簡單,只有map和reduce兩個原語(需要通過腳本把map和reduce串起來)
缺乏作業流描述,一項任務需要多輪mr

具體描述:
MR中 : 啓動map進程,啓動reduce進程,所以啓動慢 
spark:先啓動executor進程,再啓動線程:比如10個線程:8 map task(線程)2 reduce(線程)

MR:map->reduce的中間結果在磁盤
spark:map->reduce的中間結果也在磁盤(默認)
除非,進行cache(它調用的是persist)默認在內存中

spark只需要通過代碼就能把很多的數據處理串在一起:
df = spark.map.reduce
df1 = df.groupBy().count()
通過spark shell的方式查看具體的數據

Spark解決的問題


– 最大化利用內存cache(內存計算下,Spark比MR快100倍)
– 中間結果放內存,加速迭代
  input --> iter1 --> 分佈式內存 --> iter2 分佈式內存
– 某結果集放內存,加速後續查詢和處理,解決運行慢的問題
  input --> 分佈式內存 --> query1,query2,...
- 豐富的API(解決API單一問題)
  包括Transformations和Action
  Transfomation變換的api,比如map可對每一行做變換,filter過濾出符合條件的行等,這些API實現用戶算法,靈活。
  spark提供很多轉換和動作,很多基本操作如Join,GroupBy已經在RDD轉換和動作中實現。不需用戶自己實現。

  寫操作就是action:寫磁盤,寫內存
  cache屬於transformation,df.cache告訴任務df需要執行之後放到內存中
- 完整作業描述,將用戶的整個作業穿起來。關鍵是這3行。可以立即解釋。不像mr那樣,需要實現多個map和reduce腳本,解決MR缺乏作業流描述問題
  val file = sc.textFile(hdfs://input)
  val counts = file.flatMap(
  line => line.split(" "))
              .map(word => (word, 1))
              .reduceByKey(_ + _)
  counts.saveAsTextFile(hdfs://output)

Spark核心


• Spark基於彈性分佈式數據集(RDD)模型。
• RDD( Resilient Distributed Dataset ):彈性分佈式數據集(相當於集合),它的本質是數據
  集的描述(只讀的、可分區的分佈式數據集),而不是數據集本身
• RDD的關鍵特徵:
   RDD使用戶能夠顯式將計算結果保存在內存中,控制數據的劃分
   使用更豐富的操作來處理,只讀(由一個RDD變換得到另一個RDD,但是不能對本身的RDD修改)
   記錄數據的變換而不是數據本身保證容錯(lineage)

• RDD採用數據應用變換(map,filter,join),若部分數據丟失,RDD擁有足夠的信息得知這部分數據是如何計算得到的,
  可通過重新計算來得到丟失的數據
  容錯:1.備份數據 2.記錄更新方式
   變換方式:rdd1->rdd2->rdd3
   可以知道:rdd2 = rdd1->rdd2
• 恢復數據方法很快,無需大量數據複製操作,可以認爲Spark是基於RDD模型的系統
– 懶操作,延遲計算,action的時候才操作
– 瞬時性,用時才產生,用完就釋放

RDD來源:


– 讀取數據,如從HDFS中讀數據構建RDD(Sparkcontext (sc)是spark的入口,編寫spark程序用到
  的第一個類,包含sparkconf sparkenv等類)
– 通過別的RDD轉換過來
   val b = a.map(x => (x, 1))
– 定義一個scala數組
   val c = sc.parallelize(1 to 10, 1)
– 有一個已經存在的RDD通過持久化操作生成
  val d = a.persist(), a.saveAsHadoopFile(“/xxx/xxx/”)
- Dataframe轉換過來,這樣就可以從hive過來數據

 

Spark針對RDD提供的操作:transformations和action

  •  transformations(如上文)是RDD之間的變換,action會對數據執行一定的操作
  •  transformations採用懶策略,僅在對相關RDD進行action提交時才觸發計算

RDD分區和依賴:
• 每個RDD包含了數據分塊/分區(partition)的集合,每個partition是不可分割的
– 實際數據塊的描述(實際數據到底存在哪,或者不存在)
– 其值依賴於哪些partition

寬依賴和窄依賴:(rddA=>rddB)

 寬依賴: B的每個partition依賴於A的所有partition(需要用到之前所有的數據)
    如groupByKey、reduceByKey、join……,由A產生B時會先對A做shuffle分桶
 窄依賴: B的每個partition依賴於A的常數個partition(需要用到之前部分的數據)
    如map、filter、union等     (圖片來自網絡)

• 從後往前,將寬依賴的邊刪掉,連通分量及其在原圖中所有依賴的RDD,構成一個stage
• DAG是在計算過程中不斷擴展 ,在action後纔會 啓動計算
• 每個stage內部儘可能多地包含一組具有窄依賴關係的轉換,並將它們流水線並行化(pipeline)

• 從後往前,將寬依賴的邊刪掉,連通分量及其在原圖中所有依賴的RDD,構成一個stage
• DAG是在計算過程中不斷擴展 ,在action後纔會 啓動計算
• 每個stage內部儘可能多地包含一組具有窄依賴關係的轉換,並將它們流水線並行化(pipeline)
• 每個partition的計算就是一個task,task是調度的基本單位
• 一個stage會等待它包含的其他stage中的任務全部完成才加入調度
• 遵循數據局部性原則,使得數據傳輸代價最小
 
1. 如果一個任務需要的數據在某個節點的內存中,這個任務就會被分配至那個節點
  2. 需要的數據在某個節點的文件系統中,就分配至那個節點
     (此時的調度指的是:由spark的AM來決定計算partition的task,分配到哪個executor上)
• 如果此task失敗,AM會重新分配task
• 如果task依賴的上層partition數據已經失效了,會先將其依賴的partition計算任務再重算一遍
• 寬依賴中被依賴partition,可以將數據保存HDFS,以便快速重構(checkpoint)
 
注: 窄依賴只依賴上層一個partition,恢復代價較少;寬依賴依賴上層所有partition,如果數據丟
       失,上層所有partiton都要重算
• 可以指定保存一個RDD的數據至節點的cache中,如果內存不夠,會LRU釋放一部
  分,仍有重構的可能

 

Spark優化相關

內存管理


• Executor的內存分爲3塊
    第一塊:讓task執行代碼,默認佔executor總內存的20%
    第二塊:task通過shuffle過程拉取上一個stage的task的輸出後,進行聚合等操作時使用,默認也佔20%
    第三塊:讓RDD持久化時使用,默認佔60%
• Task的執行速度和每個executor進程的CPU Core數量有直接關係,一個CPU Core同一
    時間只能執行一個線程,每個executor進程上分配到的多個task,都是以task一條線程的
    方式,多線程併發運行的。如果CPU Core數量比較充足,而且分配到的task數量比較合
    理,那麼可以比較快速和高效地執行完這些task線程

重要的參數


• num-executors:該作業總共需要多少executor進程執行(建議50~100個左右合適)
• executor-memory:單個excutor的能使用的內存的大小,executor-memory *num-executors
  就是本次任務需要的內存(儘量不要超過最大總內存的1/3~1/2 4G~8G較合適)
• executor-cores:單個executor 執行給的core的數量,不能超過單節點的core的總和;
  單個core同一時間只能執行一個task,在不影響其他人作業,且不超過節點的core的上限的時候,這個值越大執行的效率越高;該參數決定每個
  executor進程並行執行task線程的能力(不要超過總CPU Core的1/3~1/2 2~4個較合適) 

 

開發原則


1、避免創建重複的RDD
2、儘可能複用同一個RDD  
3、對多次使用的RDD進行持久化處理
   藉助cache()和persist()方法
4、避免使用shuffle類算子
  在spark作業運行過程中,最消耗性能的地方就是shuffle過程
  將分佈在集羣中多個節點上的同一個key,拉取到同一個節點上,進行聚合和join處理,比如
  groupByKey、reduceByKey、join等算子,都會觸發shuffle,map爲非shuffle算子

5、使用map-side預聚合的shuffle操作
6、使用Kryo優化序列化性能(不使用默認的Java序列化機制)

 

Spark技術棧


• Spark和Hadoop關係: Spark依賴於HDFS文件系統,如果是Spark on YARN部署模式,又依賴於YARN計算框架
• Spark Core:基於RDD提供操作接口,利用DAG進行統一的任務規劃
• Spark SQL:Hive的表 + Spark的裏。通過把Hive的HQL轉化爲Spark DAG計算來實現
• Spark Streaming:Spark的流式計算框架
• MLIB:Spark的機器學習庫,包含常用的機器學習算法
• GraphX:Spark圖並行操作庫

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