spark程序調優總結

目的

關於spark程序優化總結,包括參數調優、RDD優化、算子優化等。對於處理大數據量的spark程序而言,如果做好調優,將會有比較明顯的效果。從個人而言,是鍛鍊提升自己的機會;從項目而言,是用最小的資源做最優的事情。下面是我在工作過程中遇到的調優記錄,可能不夠全面,不過學會了這些,一些簡單的調優還是沒什麼問題的。即使是菜鳥,一步步努力,不驕不躁,終會達到一個比較好的高度!與君共勉之!

環境

軟件 版本
spark 1.6

調優步驟

參數優化

屬性名 默認值 描述
spark.executor.instances 2 靜態分配的executor數。 如果同時使用spark.dynamicAllocation.enabledspark.executor.instances時,則動態分配將會被關閉,將會使用spark.executor.instances的值
spark.executor.memory 1g 每個executor進程使用的內存大小,格式與具有大小單位後綴(k,m,g,t)的JVM內存字符串相同(1024m,2g)
spark.executor.cores 1 每個executor使用的核心數
spark.executor.memoryOverhead executorMemory * 0.10, 最小爲384 除非另有說明,否則每個executor要分配的堆外內存量(MiB) 這是一個內存,可以解決諸如VM開銷,以及其他本機開銷等問題。這往往會隨着執行程序的大小而增加(通常爲6-10%)。 YARN和Kubernetes目前支持此選項。
spark.sql.autoBroadcastJoinThreshold 10485760 (10 MB) 配置該表在執行聯接時可以被廣播到所有工作程序節點的最大大小(以字節爲單位)。如果設置爲-1,則廣播將會失效。請注意,當前統計信息僅適用於已運行ANALYZE TABLE COMPUTE STATISTICS noscan命令的Hive Metastore
spark.shuffle.file.buffer 32k 每個隨機播放文件輸出流的內存緩衝區大小。這些緩衝區減少了在創建中間混排文件時進行的磁盤查找和系統調用的數量。如果內存比較充足,可以調大該值,減少shuffle write過程中溢寫磁盤文件的次數,減少磁盤IO次數,進而提升性能
spark.reducer.maxSizeInFlight 48m 從每個reduce任務中同時獲取的映射輸出的最大大小。由於每個輸出都需要我們創建一個緩衝區來接收它,因此這代表每個reduce任務固定的內存開銷,因此,請使其保持較小,除非有大量的內存。同理,如果內存較大,可以考慮調大該值,減少網絡消耗
spark.shuffle.io.maxRetries 3 如果將其設置爲非零值,則會自動重試由於與IO相關的異常而失敗的提取。這種重試邏輯有助於在長時間的GC暫停或瞬態網絡連接問題時穩定大數據量的shuffle。對於那些包含了特別耗時的shuffle操作的作業,建議增加重試最大次數,比如30次。

RDD優化

rdd複用

如果使用已有rdd進行轉換就可以得到想要的數據,就複用該rdd。

rdd持久化

當同個rdd被重複調用action算子的時候,每一次都會重新計算該算子的父rdd。對同一個RDD的重複計算是對資源的極大浪費,所以有必要進行資源的持久化。當內存無法將RDD的數據完整的進行存放的時候,可以考慮使用序列化的方式減小數據體積,將數據完整存儲在內存中。

廣播大變量

如果task在運行過程中,有調用外部變量的話,那每一個task在運行過程中,都會調用一份變量存儲在本地,造成內存的極大消耗。那麼內存被消耗了,就會導致本來可以被持久化的數據沒辦法持久化,只能存放到磁盤,導致磁盤IO變大,嚴重消耗資源。另一方面,內存逐漸被佔滿,當task要創建新變量的時候,內存不足,就會觸發GC。而GC會暫停工作線程,進而導致spark進程會暫停工作一行,從而嚴重影響spark性能。如果廣播了大變量,則每一個executor都只會存儲一份這樣的變量,每個task都會從本地的BlockManager獲取。

算子優化

mapPartitions

mapPartitionsmap 的不同是:mapPartitions 會直接抽取一個partition的數據進行處理,而map是一個個的進行處理。如果數據量不大、內存充足、網絡等待比較大,可以考慮用這個參數進行處理。

foreachPartition

這個和上面的 mapPartitions 差不多,都是對一個partition進行處理。這個操作適合和數據庫操作結合在一起。假如需要連接數據庫,如果用 foreach 會導致嚴重的數據庫連接數,消耗數據庫資源。而使用 foreachPartition 的話,則只會一個 partition 啓動一個數據庫連接。另外,如果數據量過大,會導致OOM。所以如果發生這種情況,可以先進行重新分區。

repartition

使用spark SQL的時候,會自動根據數據進行動態分區。如果處理過程中,算子的處理邏輯較爲複雜,並且數據量較大,而spark SQL設置的partition比較少,就會導致一個問題:不多的task會處理該數據量大的partition,而且處理邏輯還比較複雜,進而導致處理速度緩慢。所以可以在使用spark SQL,可以根據情況,適當地增大或者縮小該分區數量,從而調整處理並行度,進而加快處理速度。

存儲文件優化

如果是hivespark SQL結合使用的話,根據具體的情況使用對應的存儲文件格式。在我的實際項目中,有兩種壓縮方式,一種是對普通文本文件的lzo壓縮,一種是對parquetgzip壓縮如果是spark程序運行保存表,一般指定表存儲方式爲parquet文件,然後在保存過程中指定gzip壓縮。如果是hive腳本跑數,則指定爲普通文本文件,並使用lzo進行壓縮。
下圖是我做的測試數據,表是相同的表,只是命名不同。字段數據量大概爲20個左右。第一個表是沒有做壓縮的數據大小,爲69.8G;第二個表是做lzo壓縮方式,爲24.7G;第三個表是使用了parquet的gzip壓縮方式,爲12.8GB。一般lzo壓縮,可以壓縮到原來的三分之一,而parquet的gzip壓縮,根據數據的不同而呈現不同的壓縮比,我們的測試結果是可以壓縮到原來的百分之十八。另一方面, lzo壓縮,是對整個文本進行壓縮;而parquet文件是列式存儲,在實際應用中,我們一般是隻取表的幾列來進行運算,使用parquet存儲可以增加讀取效率。從下圖可以知道,parquet文件壓縮的文件,佔用的計算資源更少,結果輸出更快。

壓縮方式 存儲大小 運行時間 運算資源(mappers) 運算資源(reducers)
test_txt 無壓縮 69.8G 429.12s 277 1099
test_lzo lzo壓縮 24.7G 450.37s 101 396
test_d parquet文件gzip格式壓縮 12.8GB 364.04s 97 206

參考鏈接

Spark Docs

Spark SQL, DataFrames and Datasets Guide

Running Spark on YARN

Spark Configuration

隨緣求贊

如果我的文章對大家產生了幫忙,可以在文章底部點個贊或者收藏;
如果有好的討論,可以留言;
如果想繼續查看我以後的文章,可以點擊關注
可以掃描以下二維碼,關注我的公衆號:楓夜之求索閣,查看我最新的分享!
在這裏插入圖片描述
拜拜

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