1. 程式人生 > >Spark 調優與除錯

Spark 調優與除錯

=======================================================================================使用SparkConf配置Spark對 Spark 進行效能調優,通常就是修改 Spark 應用的執行時配置選項。Spark 中最主要的配置機制是通過 SparkConf 類對 Spark 進行配置當創建出一個 SparkContext 時,就需要創建出一個 SparkConf 的例項SparkConf 例項包含使用者要過載的配置選項的鍵值對
除了 set() 之外,SparkConf 類也包含了一小部分工具方法,可以很方便地設定部分常用引數Spark 允許通過 spark-submit 工具動態設定配置項spark-submit 工具為常用的 Spark 配置項引數提供了專用的標記,還有一個通用標記--conf 來接收任意 Spark 配置項的值,spark-submit 也支援從檔案中讀取配置項的值方便複用這些配置預設情況下,spark-submit 指令碼會在 Spark 安裝目錄中找到 conf/spark-defaults.conf 檔案,嘗試讀取該檔案中以空格隔開的鍵值對資料也可以通過 spark-submit 的 --properties-File 標記,自定義該檔案的路徑幾乎所有的 Spark 配置都發生在 SparkConf 的建立過程中,但有一個重要的選項是個例外。你需要在 conf/spark-env.sh 中將環境變數 SPARK_LOCAL_DIRS
設定為用逗號隔開的儲存位置列表,來指定 Spark 用來混洗資料的本地儲存路徑。這需要在叢集模式下設定。這個配置項之所以和其他的 Spark 配置項不一樣,是因為它的值在不同的物理主機上可能會有區別==============================================================================================Spark執行的組成部分:作業、步驟 、任務每個RDD 維護了其與父節點之間關係的資訊比如,當你在 RDD 上呼叫 val b = a.map() 時,b 這個 RDD 就存下了對其父節點 a 的一個引用。這些引用使得 RDD 可以追蹤到其所有的祖先節點Spark 提供了 toDebugString() 方法來檢視 RDD 的譜系toDugString輸出的譜系圖使用不同縮排等級來展示 RDD 是否會在物理步驟中進行流水線執行例如,當計算 counts 時,儘管有很多級父 RDD,但從縮排來看總共只有兩級。這表明物理執行只需要兩個步驟歸納一下,Spark 執行時有下面所列的這些流程
  • 使用者程式碼定義RDD的有向無環圖
  • 行動操作把有向無環圖強制轉譯為物理執行計劃
    • Spark 排程器提交一個作業來計算所有必要的 RDD。
    • 這個作業會包含一個或多個步驟,
    • 一個步驟對應有向無環圖中的一個或多個 RDD,一個步驟對應多個 RDD 是因為發生了流水線執行
    • 每個步驟其實也就是一波並行執行的計算任務。
    • 每個任務都是在不同的資料分割槽上做同樣的事情
  • 任務於叢集中排程並執行
自動流水線執行優化RDD 不需要混洗(Shuffle)資料就可以從父節點計算出來時,排程器就會自動進行流水線執行訪問應用的4040網頁使用者介面,檢視程式執行期間執行了哪些步驟RDD譜系圖截短的三種情況:
  1. 流水線執行的優化,
  2. 當一個 RDD 已經快取在叢集記憶體或磁碟上時,Spark 的內部排程器也會自動截短 RDD 譜系圖

  3. 當 RDD 已經在之前的資料混洗中作為副產品物化出來時
  • 這種內部優化是基於 Spark 資料混洗操作的輸出均被寫入磁碟的特性,
================================================================================================查詢資訊查詢資訊的兩個地方:Spark 的網頁使用者介面以及驅動器程序和執行器程序生成的日誌檔案中。不過對於 YARN 叢集模式來說,應該通過 YARN 的資源管理器來訪問使用者介面。
使用者介面主要由四個不同的頁面組成
  • 作業頁面:步驟與任務的進度和指標
    • 本頁面經常用來評估一個作業的效能表現。
    • 我們可以著眼於組成作業的所有步驟,
    • 看看是不是有一些步驟特別慢,或是在多次運行同一個作業時響應時間差距很大
  • 儲存頁面:已快取的RDD的資訊
    • 這個頁面可以告訴我們到底各個 RDD 的哪些部分被快取了,
    • 以及在各種不同的儲存媒介(磁碟、記憶體等)中所快取的資料量。
  • 執行器頁面:應用中的執行器程序列表
    • 本頁面列出了應用中申請到的執行器例項
    • 本頁面的用處之一在於確認應用可以使用你所預期使用的全部資源量
    • 除錯問題時也最好先瀏覽這個頁面,因為錯誤的配置可能會導致啟動的執行器程序數量少於我們所預期的,顯然也就會影響實際效能。
    • 執行器頁面的另一個功能是使用執行緒轉存(Thread Dump)按鈕收集執行器程序的棧跟蹤資訊(該功能在 Spark 1.2 中引入)。
      • 在短時間內使用該功能對一個執行器程序進行多次取樣,你就可以發現“熱點”,也就是使用者程式碼中消耗代價比較大的程式碼段
  • 環境頁面:用來除錯Spark配置項
    • 本頁面枚舉了你的 Spark 應用所執行的環境中實際生效的配置項集合
資料傾斜是導致效能問題的常見原因之一。當看到少量的任務相對於其他任務需要花費大量時間的時候,一般就是發生了資料傾斜(即該分割槽內資料量過大?)============日誌會更詳細地記錄各種異常事件這些資料對於尋找錯誤原因很有用Spark 日誌檔案的預設具體位置取決於部署模式Spark 的日誌系統是基於廣泛使用的 Java 日誌庫 log4j 實現的,使用 log4j 的配置方式進行配置======================================================================關鍵效能考量=================並行度在物理執行期間,RDD 會被分為一系列的分割槽,每個分割槽都是整個資料的子集。當 Spark 排程並執行任務時,Spark 會為每個分割槽中的資料創建出一個任務輸入 RDD 一般會根據其底層的儲存系統選擇並行度。例如,從HDFS 上讀資料的輸入 RDD 會為資料在 HDFS 上的每個檔案區塊建立一個分割槽從資料混洗後的 RDD 派生下來的 RDD 則會採用與其父 RDD 相同的並行度評判並行度是否過高的標準包括任務是否是幾乎在瞬間(毫秒級)完成的(分割槽內資料很少)或者是否觀察到任務沒有讀寫任何資料(分割槽是空的)Spark 提供了兩種方法來對操作的並行度進行調優
  • 在資料混洗操作時,使用引數的方式為混洗後的 RDD 指定並行度
  • 對於任何已有的 RDD,可以進行重新分割槽來獲取更多或者更少的分割槽數
    • 重新分割槽操作通過 repartition() 實現,該操作會把 RDD 隨機打亂並分成設定的分割槽數目。
    • 如果你確定要減少 RDD 分割槽,可以使用coalesce() 操作。由於沒有打亂資料,該操作比 repartition() 更為高效
      • 例如行 filter() 操作篩選掉資料集中的絕大部分資料時,可以通過合併得到分割槽更少的 RDD 來提高應用效能
==========序列化格式序列化會在資料進行混洗操作時發生(IO)預設情況下,Spark 會使用 Java 內建的序列化庫使用第三方序列化庫 Kryo可以獲得了更好的效能(更短的序列化時間、更高的壓縮比)很多 JVM 都支援通過一個特別的選項來幫助除錯NotSerializableException情況:"-Dsun.io.serialization.extended DebugInfo=true”。你可 以 通 過 設 置 spark-submit 的 --driver-java-options 和 --executor-java-options 標 記來開啟這個選項。==========記憶體管理在各個執行器程序中,記憶體有以下所列幾種用途
  • RDD儲存
    • 當呼叫 RDD 的 persist() 或 cache() 方法時
    • Spark 會根據 spark.storage.memoryFraction 限制用來快取的記憶體佔整個 JVM 堆空間的比例大小。
    • 如果超出限制,使用LRU策略將舊的分割槽資料會被移出記憶體
  • 資料混洗與聚合的快取區
    • Spark 會嘗試根據 spark.shuffle.memoryFraction 限定這種快取區記憶體佔總記憶體的比例
  • 使用者程式碼
    • Spark 可以執行任意的使用者程式碼,所以使用者的函式可以自行申請大量記憶體。
    • 使用者程式碼可以訪問 JVM 堆空間中除分配給 RDD 儲存和資料混洗儲存以外的全部剩餘空間
在預設情況下,Spark 會使用 60%的空間來儲存 RDD,20% 儲存資料混洗操作產生的資料,剩下的 20% 留給使用者程式使用者可以自行調節這些選項來追求更好的效能表現除了調整記憶體各區域比例,我們還可以為一些工作負載改進快取行為的某些要素例如,有時以 MEMORY_AND_DISK 的儲存等級呼叫 persist() 方法,當RDD 分割槽的重算代價很大(比如從資料庫中讀取資料)時,會獲得更好的效果。。persist預設是MEMORY_ONLY對於預設快取策略的另一個改進是快取序列化後的物件而非直接快取這可以顯著減少 JVM 的垃圾回收時間,因為這種快取方式會把大量物件序列化為一個巨大的快取區物件垃圾回收的代價與堆裡的物件數目相關,而不是和資料的位元組數相關我們可以通過MEMORY_ONLY_SER 或者 MEMORY_AND_DISK_SER 的儲存等級來實現這一點。如果你需要以物件的形式快取大量資料(比如數 GB 的資料),或者是注意到了長時間的垃圾回收暫停,可以考慮配置這個選項============硬體供給影響叢集規模的主要引數包括執行器節點總數,(典型的CPU、記憶體、硬碟三大件的效能和容量)分配給每個執行器節點的記憶體大小、每個執行器節點佔用的核心數、以及用來儲存臨時資料的本地磁碟數量執行器節點的記憶體
  • 都可以通過 spark.executor.memory 配置項或者spark-submit 的 --executor-memory 標記來設定。
執行器節點的數目以及每個執行器程序的核心數的配置選項則取決於各種部署模式
  • 在 YARN 模式下,你可以通過 spark.executor.cores 或 --executor-cores 標 記 來 設 置 執 行 器 節 點 的 核 心 數, 通 過 --numexecutors 設定執行器節點的總數。
在 YARN 模式下,由於 YARN 提供了自己的指定臨時資料儲存目錄的機制,Spark 的本地磁碟配置項會直接從 YARN 的配置中讀取。雙倍的資源通常能使應用的執行時間減半。切記,“越多越好”的原則在設定執行器節點記憶體時並不一定適用。
  • 使用巨大的堆空間可能會導致垃圾回收的長時間暫停,從而嚴重影響 Spark 作業的吞吐量
  • YARN 本身就已經支援在同一個物理主機上執行多個較小的執行器例項
  • 還可以用序列化的格式儲存資料(參見 8.4.3 節)來減輕垃圾回收帶來的影響。