一、Spark官網走讀筆記

Spark基礎概念

RDD 彈性分佈式數據集

  • 彈性:當內存計算資源不足時,可以刷到磁盤上,rdd使用checkpoint在數據更新和丟失後對數據模型進行重建

  • 分佈式:可以分佈在多臺機器上進行計算

  • 數據集:一組只讀的,可分區的分佈式數據集合,將形同屬性的數據記錄放在一起,每個分區相當於一個數據集片段

Spark概念關鍵詞

  • Master stand-alone模式中的主節點,管理所有work節點
  • Worker stand-alone模式中work節點,負責任務的執行
  • Driver 運行application的main方法
  • Executor 負責Task的執行
  • Job 一個Application中會有多個Job
  • Task Task分爲ShuffleMapTask和ResultTask
  • TaskSet 在DagScheduler發送到TaskScheduler時 task的集合
  • Stage 一個job會有多個Stage ,stage也分爲ResultStage和ShuffleMapStage
  • DAGScheduler job基於stage的有向無環圖
  • TaskScheduler 將TaskSet交給Work運行,
  • yarn-cluster driver和Appmaster一起
  • yarn-client driver在客戶端,和appmaster分開的

RDD 創建方式

  • 集合方式創建
val num = Array(1,2,3,4,5)
val rdd = sc.parallelize(num)
  • 外部數據集
val rdd  = sc.textFile("hdfs:///xxx")

RDD轉換

sc.textFile 得到 HadoopRDD

.map/.faltMap 得到 MapPartitionsRDD

.reduceByKey 會先調用隱式轉換 rddToPairRDDFunction方法,去調用PairRDDFunctions的reduceBykey方法,會返回一個ShuffledRDD

任務執行起點

當RDD中出現action算子時,每個action算子會觸發sc.runJob啓動任務

RDD 算子

  • Transform:

map,filter,flatMap,sample,union,distict,groupByKey,reduceByKey,sortByKey,join,mapPartitions

  • Action:

collect,count,take,first,saveAsTextFile

  • Controller算子:

cache , persist

spark dependency

NarrowDependency

  • OneToOneDependency extends NarrowDependency
    即parent rdd和child rdd中的partitions一一對應,例如 map filter

  • RangeDependency extends NarrowDependency
    多個Rdd合併到一個RDD,每個parent rdd佔子Rdd的一個區間,例如 union

ShuffleDependency

RDD生產DAG過程

RDD.action–>sparkContext.runjob()–> dagScheduler.runJob --> submitJob --> eventProcessLoop.post --> DAGSchedulerEventProcessLoop.onReceive --> doOnReceive --> handleJobSubmitted --> createResultStage

DAG提交任務過程

  1. stage 生成過程
    createResultStage --> getOrCreateParentStages --> getShuffleDependencies.toList(獲取到所有的父dependency) --> getOrCreateShuffleMapStage(dependency 獲取Some類型Stage或ShuffleMapStage )

Spark external shuffle service

External shuffle Service是長期存在於NodeManager進程中的一個輔助服務。通過該服務來抓取shuffle數據,減少了Executor的壓力,在Executor GC的時候也不會影響其他Executor的任務運行。

spark dataset和dataframe的區別

在spark2中 DataFrame = DataSet[Row]

  • DataSet是有明確類型定義的數據集合,在scala中可以用case class表示
  • DataSet靜態類型和運行時類型檢查,語法,分析錯誤在編譯階段就會拋出,DataFrame語法錯誤,會在編譯階段報錯,分析錯誤(字段不存在)則運行時才能拋出。 單純的sql則均需要在運行時才能拋出。
  • DataFrame和DataSet會經過 catalyst優化,生成邏輯和物理執行計劃,查詢會效率高。
  • 假如你需要豐富的語義,對半結構化數據處理,filter map sum aggregation等,注重類型檢查,python, 使用tungsten等就使用DataFrame和DataSet吧

Spark-sql知識點

  • spark2.0 以sparksesseion爲統一的入口
  • import spark.implicits._ 導入可以將RDD轉化爲DataFrame
  • spark2.0 可以完整的hive支持,udf等,不需要額外的配置
  • df.createOrReplaceTempView(“people”) 註冊臨時視圖,作用域時會話級別
  • df.createGlobalTempView(“people”) 註冊全局視圖,作用域時整個spark application
  • 可以通過繼承UserDefinedAggregateFunction[非類型安全] 實現自定義的聚合函數
  • 可以通過繼承Aggregator實現[類型安全]的自定義聚合函數
  • df = spark.read.format(“json”).read(“xxx”) 可以指定 json parquet jdbc orc csv text libsvm
  • spark sql調優 設置spark.sql.shuffle.partitions默認200
  • spark動態資源最小 spark.dynamicAllocation.minExecutors=1
  • spark動態資源最大 spark.dynamicAllocation.maxExecutors=1000
  • spark thrift server和hivesever2其實一樣,都依賴於hive的metastore
  • User defined aggregation functions (UDAF)
  • Apache Arrow 作爲標準數據交換格式,不要再序列化和反序列化,設計時採用適配器模式,適配各個大數據組件,列式存儲,基於內存

spark sql不支持hive的部分

  • 不支持bucket
  • hive可以小文件合併,sparksql不支持
  • 僅元數據查詢,sparksql也會啓動任務去執行
  • udf 重寫的子類中部分函數沒有實際意義,部分UDF不兼容

structed streaming

  • Structed Streaming是基於Spark sql 引擎構建的
  • 流批統一都可以基於sparksql
  • 豐富的語言支持,scala java python r
  • 快速 可擴展 容錯,端到端的exectly-once
  • Structed Streaming 可以實現端到端的100ms的exactly-once。spark2.3引入了“Continuous Processing” 可以實現低至1ms的at least once
  • structedstreaming的核心思想就是將實時流看作是連續追加的表,datastream as an unbounded table
  • structed Streaming 輸出模式output mode有三種,complete mode, append mode, update mode
  • strutted streaming 處理eventtime和延遲數據
  • Structed streaming 可以實現端到端的exactly-once,必須source是可以回放,sink是冪等的
  • structed Streaming 可以實現sechma推導,也可以實現分區發現
  • 窗口聚合函數,watermarker到12:11時纔會就算12:00-12:10的窗口結果
  • spark2.0,開始支持了動態流和靜態流join
  • spark2.3 開始支持動態流和動態流的join,output 模式只能是append,不能在join之前使用聚合函數
  • spark structed streaming 在雙流join時會以慢的watermark爲全局watermark ,在2.4版本中可以通過參數spark.sql.streaming.multipleWatermarkPolicy 設置max或min(默認),設置爲max之後,慢的流數據可能會被丟棄

Structed Streaming清理窗口狀態的幾個條件:
1.output mode必須是append 或 update
2.聚合必須有event-time列
3.聚合列必須和窗口eventTime是同一個字段, 錯例:df.watermark(“time”,“1 min”).groupby(“time2”).count
4.watermarker函數需要在聚合函數之前被調用

Spark shuffle

spark shuffle 需要消耗大量的網絡IO,序列化反序列化,讀取數據磁盤IO,Cpu

  • 通過使用reduceByKey 替換groupbykey
  • 用broadcast+filter替換join
  • Mapvalues替換map
  • 先去重在合併
  • hashshuffle

SortShuffleManager
普通運行機制:每個task只產生一個文件
bypass機制:每個task只產生一個文件,少了排序過程

參數配置:
shuffle write 緩衝區,shuffle read 緩衝區
shuffle io retrywait,可以增大 增加shuffle的穩定性
spark.shuffle.memoryFraction 默認0.2,shuffle read用於聚合的內存比例
spark.shuffle.consolidatefiles 默認爲false,在hashShuffleManager時設置爲true會開啓shuffle write 文件的合併

並行度調優:
spark.sql.default.parlism

spark數據傾斜的表現就是 有executor回oom cpu打滿

kudu是支持隨機讀寫,同時支持olap引擎

開始流查詢任務

需要設置以下參數:
1.sink. 輸入格式,類型,地址等
2.output mode 輸出類型
3.唯一查詢名
4.checkpoint
5.trigger interval 觸發週期

輸出模式

structed streaming 輸出模式,append update compelete
狀態操作和join有很多功能不支持

sink類型
file sink,
kafka sink,
foreach sink 自定義sink,實現close open proess方法,
cosole sink 用於調試,
memory sink 用於調試

觸發器

micro-batch 默認,連續批次,上一個執行完成即開始下一個批次
fiexed-interval micro batches 固定週期微批
one-time micro batch 一次執行微批
continous with fixed checkpoint interval

流查詢監控

可以使用query.lastProgress返回json類型的數據
也可以用query.status
也可以使用streaming Linstener 異步獲取任務進度

容錯保證

使用wal + checkpoint

spark streaming

  • spark steaming 的編程模型是DStreams(代表一系列的RDD)

  • spark steaming 的步驟

      new sparkConf, 
      new StramingContext,
      lines =  new DStream, 
      words = lines.flatMap(_.split(" ")),
      pairs = words.map(word => (word,1)), 
      result = pairs.reduceByKey( _ + _ )
      result.print
      ssc.start
      ssc.awaitTremination
    
  • 一個Jvm中只能有一個StreamContext

  • spark streaming source 有兩類,1.基本輸入,文件(不需要receiver,文件的修改是會被忽略的,只檢測路徑下的新文件) 網絡 2.外部數據源,kafka flume

  • spark streaming 本地模式 local[x] x需要大於1 ,不然只會運行receiver進程

  • sparkstreaming 狀態操作步驟 1.定義狀態 2.定義狀態更新函數

  • 調用updateStateByKey需要配置checkpoint

  • sparkstreaming 的操作可以分爲:算子類,窗口操作類,join

  • saveAsTextfile saveasobjectfile saveashadoopfile ,當然也可以用foreachaRDD(func)自定義輸出

  • 使用foreachrdd時一定要在內部調用rdd.foreachPartition

  • sparkstreaming 可以和 Dataframe 結合,註冊臨時表createOrReplaceTempView,使用spl語句查詢

  • DStrams和RDD類似,開發者可以對其進行持久化, presist()

  • checkpoint 需要藉助外界可靠存儲,比如hdfs s3等 ,通過streamingContext.checkpoint(path), 可以由getOrCreate方法獲得scc,間隔週期不能太小,會影響吞吐量,建議設置爲滑動窗口週期的5-10倍,時間是批次間隔的倍數。checkpoint的數據有兩類 1 元數據(配置,算子操作,未完成的批次)2.數據checkpoint(比如中間計算的狀態RDD)

  • broadcast和accumulators的狀態在checkpoint恢復時不能重新實例化,需要在編碼時創建單例以便在任務重啓時進行實例化

  • spark steaming 任務部署

      1.打包
      2.executors內存配置
      3.配置checkpoint
      4.配置wal,不過會影響吞吐
      5.設置最大接受速率 spark.straming.receiver.maxRate ,對於kafka direct模式使用參數
      spark.streaming.kafka.maxRatePerPartition .在spark 1.5版本後,引入了spark.streaming.backpressure.enable=true啓動背壓。消費速率會自動計算
    
  • spark streaming 任務監控

       1.RestApi 
       2.繼承StreamingListener
       3.重要參數 processing time(批次處理時間) 和 scheduler delay (處理延遲)
    
  • sparkstreaming 任務調優

    • 減少批次的執行時間
      • 首先不要讓數據接受receiver成爲瓶頸。可以並行多個receiver,提高吞吐量。
      • 接收器的塊間隔,接收的數據會在存儲在spark內存之前合併爲數據塊。任務數=批次間隔/塊間隔 所以要儘量的減少塊間隔時間,但是推薦不少於50ms
      • 對於多個receiver的情況,可以調用repartition方法 對數據進行重新分區
      • 計算的並行度 可以通過spark.default.parllsiem設置,默認是rdd的分區數
      • 數據的反序列化和序列化會帶來很大的cpu消耗,第一種。通過receiver接收到的數據默認是StorageLevel.Memory_and_disk_2即數據被反序列化存儲以減少cpu消耗,而且爲了容錯,在內存不足時會將數據保存在磁盤。第二種。因爲有窗口這類操作,數據會多次處理,所以默認時以StogeLevel.memory_only_ser即序列化方式存儲的,和spark core的 memory 不同。序列化的保存方式更耗cpu。綜上所述。使用kryo可以減少內存和cpu消耗
    • 設置合理的批次時間

      • 可以通過延遲時間來測試批次時間設置是否合理
    • 設置合理的內存

      • sparkstreaming 程序所使用的算子類很大程度決定了內存的使用量,比如window,updateStateByKey等就會需要大量內存,比如map,filter就需要少量內存
      • receiver一般會將數據進行序列化,StrogeLevel.memory_disk_ser_2,如果內存不夠會進行寫磁盤,這會耗費很大的性能。所以receiver需要配置足夠的內存
      • gc 通過gc的設置,不希望流計算任務因爲gc有很大的暫停
        • 減少gc 1 啓用kryo減少rdd的內存和cpu,也可以使用spark.rdd.compress 壓縮rdd,減少了內存但是會增加cpu
        • 清除舊數據 streamingContext.remeber()設置
        • 建議使用cms垃圾回收器
        • 其他 比如使用堆外內存,更多的executor減少GC
  • 需要記住的點:

    • receiver接收到數據後,每隔blockinterval會生成一個block, blockmanager會將block分發給其他executor
    • 每一個block interval意味着創建一個RDD分區,每個分區對應一個Task
    • blockinterval 調大意味着 每個block的數據更多。spark.locality.wait調大會增加本地處理數據塊的機會,需要在兩個參數之間做平衡
    • 可以使用dataStrem.repartition進行重新分區
    • 如果批處理時間超過了批間隔時間,會導致receiver內存溢出,拋出blocknotfoundexecption,目前沒有好的暫停辦法,使用spark.streaming.receiver.maxRate來限制接收的速率
  • 容錯

    • rdd是一個不可變的,確定的,可重複計算的不可變數據集,worker故障導致的rdd分區數據丟失,可以通過lineage重新計算。不論什麼錯誤spark都可以保證結果的最終正確
    • 三種容錯機制 at least once,at most once,exactly once
    • 接收端:在spark1.3後使用direct api可以和Kafka實現exectly-oncea語義
    • 輸出端:支持冪等更新,事物更新

spark 配置

  • local[2]代表最小並行度
  • 動態加載spark配置 spark-submit --name --master --conf --conf 可以使用多個conf
  • SparkConf設置的參數優先級高於spark-submit,高於conf/spark-defaults
  • spark 參數分爲兩類 程序屬性和運行時參數

spark 調優

由於spark基於內存計算的特性,在集羣中執行的任務,cpu、內存、網絡io都可能成爲瓶頸,假如數據適合存儲在內存中,那麼瓶頸就是網絡寬帶,但還是需要一些調優。比如將rdd以序列化形式存儲以減少內存。spark優化主要是兩個方面,1.數據序列化,對於網絡io至關重要 2.內存

數據序列化

  • spark默認使用java 序列化框架,kryo序列化是java的10倍,但是kryo需要你提前註冊

內存調優

三個方面:對象佔用內存,訪問對象,以及垃圾回收。通常情況下Java對象訪問很快,但是與原始數據相比會膨脹2-5倍

數據膨脹的幾種原因:
  1. 每個對象都有一個對象頭(object header 對象類,指針等)佔16字節,比一般的int類型實際值都大
  2. 字符串一般會有額外40字節的開銷(存儲爲char,並預留一定的空間)而且內部使用utf16存儲,會每個字符佔兩個字節,所以一個10字節的字符串輕鬆佔用60字節
  3. 公共集合類,比如map.entry不僅有對象佔用還有指向下一對象的指針佔用
  4. 還有java的自動裝箱
內存管理:

spark內存主要分爲執行execution和存儲storage,在有必要情況下,執行會驅逐存儲從而佔用其內存,以下參數不建議改動

  1. spark.memory.fraction 默認0.6 表示60%用於計算,剩下的用於用書數據結構存儲等
  2. spark.memory.storageFraction 默認0.5 表示數據存儲佔用的內存比例
如何確認內存消耗

在spark的webui處的storage處查看rdd佔用的內存。

調整數據結構

減少內存的有效方式是,避免java類型帶來的開銷

  1. 設計java類型優先使用基本類型和數組,避免使用集合類如hashmap
  2. 避免使用包含很多小對象的嵌套結構
  3. 數字或枚舉替換string
  4. 當jvm小於32g 使用UseCompressedOops壓縮對象指針(8字節–>4字節)
序列化RDD儲存

減少內存的另一有效方法是序列化存儲rdd,但是要進行反序列化操作會導致耗時增加,所以建議使用kryo(比java序列化佔用更小)

垃圾回收優化

gc優化,首先是使用更小的數據結構,或者是序列化

  1. 設置gc打印參數 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps ,注意gc是記錄在work節點上的
  2. spark gc的目的是保證長時間存活的對象存儲在old區,短期對象存儲在young區,減少full gc
    • 查看gc日誌是否有大量的full gc
    • 如果日誌中有大量的minor gc,而很少的major gc ,可以通過-Xmn設置爲eden區的4/3倍
    • 如果old區接近滿,可以調低spark.memory.fraction減少緩存在內存中的數據量。或者減少young區的大小,即調整NewRatio參數,默認是2,即young:old=1:2,可以調到3或4,即old佔比3/4或4/5
    • 嘗試使用g1垃圾回收器,調整XX:G1HeapRegionSize
    • 可以在spark任務重指定 spark.executor.extraJavaOption 設置jvm相關參數

其他因素

  • 並行度 :spark任務並行度也很重要,1.有些算子本來就可以設置並行度 比如reduceByKey等 2.通過設置spark.default.parallesiem 一般建議每個cpu有2-3個任務

  • reduceTask的內存使用 :通常得到一個oom錯誤不是因爲rdd不適合內存,而是因爲執行shuffle類算子,比如sortByKey reduceByKey join groupByKey 等,每個人任務需要一個hashmap來存儲分組數據,最簡單的辦法是增加任務的並行度。減少每個task處理的數據量

  • 使用廣播變量broatcast可以減少序列化,以及spark任務的啓動開銷等

  • 數據本地化

    • process_local 同一jvm
    • node_local 同一機器
    • no_pref 沒有位置便好
    • rack_local 同一機架
    • any data 不同機架其他位置
數據本地化的兩個選擇:

  + 等到同一節點的任務釋放
  + 立即在其他節點啓動任務

spark 通常會等待同節點任務釋放,但是超時後會啓動任務到空閒cpu,數據拷貝,可以通過spark.locality設置數據本地化相關參數

spark 任務調度

spark資源分配最簡單的是靜態資源分配,應用程序可以佔用最大的資源並且佔有。一般有三種部署模式。
stand-alone,yarn,mesos

###動態資源分配
動態資源分配,可以根據工作負載動態調整資源,在任務不需要時回收,需要時重新申請。

  • 開啓動態資源 spark.dynamicAllocation.enable=true,spark.shuffle.service.enable=enable。shuffle service的目的是允許刪除程序但是不刪除他們寫入的文件。

資源分配策略

spark任務沒有確定的方法知道一個ecexutor在刪除時將來會有任務執行,或者一個新增的ecexutor時空閒的,所以需要啓發式來確定何時刪除和新增executor

申請策略:每隔spark.dynamicAllocation.schedulerBacklogTimeout(默認1s)會觸發輪詢請求executor,每次呈指數級增長 1,2,4,8

刪除策略:刪除策略比較簡單 超過了 spark.dynmicAlloaction.executorIdleTimeout就會被回收,一般如果還有待執行的任務時,不會有executor超時待刪除

spark executor執行完成shuffle 寫任務後,還需要充當下一讀數據任務的服務,所以假如此時executor被回收,任務需要重新計算。所以引入了external shuffle service 一個常駐的進程,用戶任務之間獲取數據文件。
任務執行完成後會保存緩存數據,默認情況下是不會刪除這些executor的,未來版本可以將其保存在堆外內存中。

任務內調度

spark 單個任務內部以FIFO調度任務,每個任務分爲stage,位於隊列頭部的任務優先開始執行,假如資源夠用則後續的任務也會立即執行

在spark 0.8之後可以配置調度策略爲fair ,即小任務可以立即獲得資源開始執行。

通過參數spark.scheduler.mode=fair 設置,也可以使用fair調度池

集羣模式概覽

spark應用程序作爲一個獨立的進程集允許在集羣上,sparkContext稱爲driver,作爲程序的協調器

注意幾點:

  • 每個spark application都有自己的executor,且相互之間進程隔離
  • spark 不依賴底層cluster manager ,不管是yarn mesos
  • spark driver需要接受來自executor的連接,所以driver對於executor必須是可連接的
  • spark driver最好和executor運行在一個局域網內

spark任務提交

spark-submit 可以提交所以的 spark應用。可以使用assembly打包,但是需要將spark和hadoop的依賴設置爲provided 因爲他們在運行時由集羣提供。
–supervise 可以在appmaster執行失敗時重新執行,yarn模式不生效

spark 源碼分析

spark-submit 執行返回的cmd爲

/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -cp /Users/liyuhuan/tools/spark/conf/:/Users/liyuhuan/tools/spark/jars/* -Xmx1g org.apache.spark.deploy.SparkSubmit --master local[2] --class org.apache.spark.examples.SparkPi ../examples/jars/spark-examples_2.11-2.1.0.jar 100
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章