《Spark性能調(diào)優(yōu)》要點:
本文介紹了Spark性能調(diào)優(yōu),希望對您有用。如果有疑問,可以聯(lián)系我們。
通常我們對一個系統(tǒng)進行性能優(yōu)化無怪乎兩個步調(diào)——性能監(jiān)控和參數(shù)調(diào)整,本文主要分享的也是這兩方面內(nèi)容.
性能監(jiān)控工具
【Spark監(jiān)控工具】
Spark提供了一些基本的Web監(jiān)控頁面,對于日常監(jiān)控十分有用.
1. Application Web UI
http://master:4040(默認(rèn)端口是4040,可以通過spark.ui.port修改)可獲得這些信息:(1)stages和tasks調(diào)度情況;(2)RDD大小及內(nèi)存使用;(3)系統(tǒng)環(huán)境信息;(4)正在執(zhí)行的executor信息.
2. history server
當(dāng)Spark應(yīng)用退出后,仍可以獲得歷史Spark應(yīng)用的stages和tasks執(zhí)行信息,便于分析程序不明原因掛掉的情況.配置辦法如下:
(1)$SPARK_HOME/conf/spark-env.sh
export SPARK_HISTORY_OPTS="-Dspark.history.retainedApplications=50
Dspark.history.fs.logDirectory=hdfs://hadoop000:8020/directory"
闡明:spark.history.retainedApplica-tions僅顯示最近50個應(yīng)用spark.history.fs.logDirectory:Spark History Server頁面只展示該路徑下的信息.
(2)$SPARK_HOME/conf/spark-defaults.conf
spark.eventLog.enabled true
spark.eventLog.dir hdfs://hadoop000:8020/directory #應(yīng)用在運行過程中所有的信息均記錄在該屬性指定的路徑下
3. spark.eventLog.compress true
(1)HistoryServer啟動
$SPARK_HOMR/bin/start-histrory-server.sh
(2)HistoryServer停止
$SPARK_HOMR/bin/stop-histrory-server.sh
4. ganglia
通過配置ganglia,可以分析集群的使用狀況和資源瓶頸,但是默認(rèn)情況下ganglia是未被打包的,必要在mvn編譯時添加-Pspark-ganglia-lgpl,并修改配置文件$SPARK_HOME/conf/metrics.properties.
5. Executor logs
Standalone模式:$SPARK_HOME/logs
YARN模式:在yarn-site.xml文件中配置了YARN日志的存放位置:yarn.nodemanager.log-dirs,或使用命令獲取yarn logs -applicationId.
【其他監(jiān)控工具】
1. Nmon(http://www.ibm.com/developerworks/aix/library/au-analyze_aix/)
Nmon 輸入:c:CPU n:網(wǎng)絡(luò) m:內(nèi)存 d:磁盤
2. Jmeter(http://jmeter. apache.org/)
通常使用Jmeter做系統(tǒng)性能參數(shù)的實時展示,JMeter的安裝非常簡單,從官方網(wǎng)站上下載,解壓之后即可使用.運行命令在%JMETER_HOME%/bin下,對于 Windows 用戶,直接使用jmeter.bat.
啟動jmeter:創(chuàng)建測試計劃,設(shè)置線程組設(shè)置循環(huán)次數(shù).
添加監(jiān)聽器:jp@gc - PerfMon Metrics Collector.
設(shè)置監(jiān)聽器:監(jiān)聽主機端口及監(jiān)聽內(nèi)容,例如CPU.
啟動監(jiān)聽:可以實時獲得節(jié)點的CPU狀態(tài)信息,從圖4可看出CPU已呈現(xiàn)瓶頸.
3. Jprofiler(http://www.ej-technologies.com/products/jprofiler/overview.html)
JProfiler是一個全功能的Java剖析工具(profiler),專用于分析J2SE和J2EE應(yīng)用程式.它把CPU、線程和內(nèi)存的剖析組合在一個強大的應(yīng)用中.JProfiler的GUI可以更方便地找到性能瓶頸、抓住內(nèi)存泄漏(memory leaks),并解決多線程的問題.例如分析哪個對象占用的內(nèi)存比較多;哪個辦法占用較大的CPU資源等;我們通常使用Jprofiler來監(jiān)控Spark應(yīng)用在local模式下運行時的性能瓶頸和內(nèi)存泄漏情況.
上述幾個工具可以直接通過提供的鏈接了解詳細的使用辦法.
Spark調(diào)優(yōu)
【Spark集群并行度】
在Spark集群環(huán)境下,只有足夠高的并行度才能使系統(tǒng)資源得到充分的利用,可以通過修改spark-env.sh來調(diào)整Executor的數(shù)量和使用資源,Standalone和YARN方式資源的調(diào)度管理是分歧的.
在Standalone模式下:
1. 每個節(jié)點使用的最大內(nèi)存數(shù):SPARK_WORKER_INSTANCES*SPARK_WORKER_MEMORY;
2. 每個節(jié)點的最大并發(fā)task數(shù):SPARK_WORKER_INSTANCES*SPARK_WORKER_CORES.
在YARN模式下:
1. 集群task并行度:SPARK_ EXECUTOR_INSTANCES* SPARK_EXECUTOR_CORES;
2. 集群內(nèi)存總量:(executor個數(shù)) * (SPARK_EXECUTOR_MEMORY+ spark.yarn.executor.memoryOverhead)+(SPARK_DRIVER_MEMORY+spark.yarn.driver.memoryOverhead).
重點強調(diào):Spark對Executor和Driver額外添加堆內(nèi)存大小,Executor端:由spark.yarn.executor.memoryOverhead設(shè)置,默認(rèn)值executorMemory * 0.07與384的最大值.Driver端:由spark.yarn.driver.memoryOverhead設(shè)置,默認(rèn)值driverMemory * 0.07與384的最大值.
通過調(diào)整上述參數(shù),可以提高集群并行度,讓系統(tǒng)同時執(zhí)行的任務(wù)更多,那么對于相同的任務(wù),并行度高了,可以減少輪詢次數(shù).舉例說明:如果一個stage有100task,并行度為50,那么執(zhí)行完這次任務(wù),必要輪詢兩次才能完成,如果并行度為100,那么一次就可以了.
但是在資源相同的情況,并行度高了,相應(yīng)的Executor內(nèi)存就會減少,所以必要根據(jù)實際實況協(xié)調(diào)內(nèi)存和core.此外,Spark能夠非常有效的支持短時間任務(wù)(例如:200ms),因為會對所有的任務(wù)復(fù)用JVM,這樣能減小任務(wù)啟動的消耗,Standalone模式下,core可以允許1-2倍于物理core的數(shù)量進行超配.
【Spark任務(wù)數(shù)量調(diào)整】
Spark的任務(wù)數(shù)由stage中的起始的所有RDD的partition之和數(shù)量決定,所以需要了解每個RDD的partition的計算辦法.以Spark應(yīng)用從HDFS讀取數(shù)據(jù)為例,HadoopRDD的partition切分辦法完全繼承于MapReduce中的FileInputFormat,具體的partition數(shù)量由HDFS的塊大小、mapred.min.split.size的大小、文件的壓縮方式等多個因素決定,詳情需要參見FileInputFormat的代碼.
【Spark內(nèi)存調(diào)優(yōu)】
內(nèi)存優(yōu)化有三個方面的考慮:對象所占用的內(nèi)存,拜訪對象的消耗以及垃圾回收所占用的開銷.
1. 對象所占內(nèi)存,優(yōu)化數(shù)據(jù)布局
Spark 默認(rèn)使用Java序列化對象,雖然Java對象的拜訪速度更快,但其占用的空間通常比其內(nèi)部的屬性數(shù)據(jù)大2-5倍.為了減少內(nèi)存的使用,減少Java序列化后的額外開銷,下面列舉一些Spark官網(wǎng)(http://spark.apache.org/docs/latest/tuning.html#tuning-data-structures)提供的方法.
(1)使用對象數(shù)組以及原始類型(primitive type)數(shù)組以替代Java或者Scala集合類(collection class).fastutil 庫為原始數(shù)據(jù)類型提供了非常便利的集合類,且兼容Java標(biāo)準(zhǔn)類庫.
(2)盡可能地避免采用含有指針的嵌套數(shù)據(jù)結(jié)構(gòu)來保留小對象.
(3)考慮采納數(shù)字ID或者枚舉類型以便替代String類型的主鍵.
(4)如果內(nèi)存少于32GB,設(shè)置JVM參數(shù)-XX:+UseCom-pressedOops以便將8字節(jié)指針修改成4字節(jié).與此同時,在Java 7或者更高版本,設(shè)置JVM參數(shù)-XX:+UseC-----ompressedStrings以便采納8比特來編碼每一個ASCII字符.
2. 內(nèi)存回收
(1)獲取內(nèi)存統(tǒng)計信息:優(yōu)化內(nèi)存前必要了解集群的內(nèi)存回收頻率、內(nèi)存回收耗費時間等信息,可以在spark-env.sh中設(shè)置SPARK_JAVA_OPTS=“-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps $ SPARK_JAVA_OPTS”來獲取每一次內(nèi)存回收的信息.
(2)優(yōu)化緩存大小:默認(rèn)情況Spark采用運行內(nèi)存(spark.executor.memory)的60%來進行RDD緩存.這注解在任務(wù)執(zhí)行期間,有40%的內(nèi)存可以用來進行對象創(chuàng)建.如果任務(wù)運行速度變慢且JVM頻繁進行內(nèi)存回收,或者內(nèi)存空間不足,那么降低緩存大小設(shè)置可以減少內(nèi)存消耗,可以降低spark.storage.memoryFraction的大小.
3. 頻繁GC或者OOM
針對這種情況,首先要確定現(xiàn)象是產(chǎn)生在Driver端還是在Executor端,然后在分別處理.
Driver端:通常由于計算過大的結(jié)果集被回收到Driver端導(dǎo)致,需要調(diào)大Driver端的內(nèi)存辦理,或者進一步減少結(jié)果集的數(shù)量.
Executor端:
(1)以外部數(shù)據(jù)作為輸入的Stage:這類Stage中出現(xiàn)GC通常是因為在Map側(cè)進行map-side-combine時,由于group過多引起的.解決辦法可以增加partition的數(shù)量(即task的數(shù)量)來減少每個task要處理的數(shù)據(jù),來減少GC的可能性.
(2)以shuffle作為輸入的Stage:這類Stage中出現(xiàn)GC的通常原因也是和shuffle有關(guān),常見原因是某一個或多個group的數(shù)據(jù)過多,也就是所謂的數(shù)據(jù)傾斜,最簡單的方法就是增加shuffle的task數(shù)量,比如在SparkSQL中設(shè)置SET spark.sql.shuffle.partitions=400,如果調(diào)大shuffle的task無法解決問題,說明你的數(shù)據(jù)傾斜很嚴(yán)重,某一個group的數(shù)據(jù)遠遠大于其他的group,需要你在業(yè)務(wù)邏輯上進行調(diào)整,預(yù)先針對較大的group做單獨處理.
【修改序列化】
使用Kryo序列化,因為Kryo序列化結(jié)果比Java標(biāo)準(zhǔn)序列化更小,更快速.具體辦法:spark-default.conf 里設(shè)置spark.serializer為org.apache.spark.serializer.KryoSerializer .
參考官方文檔(http://spark.apache.org/docs/latest/tuning.html#summary):對于大多數(shù)程序而言,采用Kryo框架以及序列化能夠辦理性能相關(guān)的大部分問題.
【Spark 磁盤調(diào)優(yōu)】
在集群環(huán)境下,如果數(shù)據(jù)分布不均勻,造成節(jié)點間任務(wù)分布不均勻,也會導(dǎo)致節(jié)點間源數(shù)據(jù)不必要的網(wǎng)絡(luò)傳輸,從而大大影響系統(tǒng)性能,那么對于磁盤調(diào)優(yōu)最好先將數(shù)據(jù)資源分布均勻.除此之外,還可以對源數(shù)據(jù)做必定的處理:
1. 在內(nèi)存允許范圍內(nèi),將頻繁拜訪的文件或數(shù)據(jù)置于內(nèi)存中;
2. 如果磁盤充裕,可以適當(dāng)增加源數(shù)據(jù)在HDFS上的備份數(shù)以減少網(wǎng)絡(luò)傳輸;
3. Spark支持多種文件格式及壓縮方式,根據(jù)不同的應(yīng)用環(huán)境進行合理的選擇.如果每次計算只必要其中的某幾列,可以使用列式文件格式,以減少磁盤I/O,常用的列式有parquet、rcfile.如果文件過大,將原文件壓縮可以減少磁盤I/O,例如:gzip、snappy、lzo.
【其他】
廣播變量(broadcast)
當(dāng)task中需要拜訪一個Driver端較大的數(shù)據(jù)時,可以通過使用SparkContext的廣播變量來減小每一個任務(wù)的大小以及在集群中啟動作業(yè)的消耗.參考官方文檔http://spark.apache.org/docs/latest/tuning.html#broadcasting-large-variables.
開啟推測機制
推測機制后,如果集群中,某一臺機器的幾個task特別慢,推測機制會將任務(wù)分配到其他機器執(zhí)行,最后Spark會選取最快的作為最閉幕果.
在spark-default.conf 中添加:spark.speculation true
推測機制與以下幾個參數(shù)有關(guān):
1. spark.speculation.interval 100:檢測周期,單位毫秒;
2. spark.speculation.quantile 0.75:完成task的百分比時啟動推測;
3. spark.speculation.multiplier 1.5:比其他的慢多少倍時啟動推測.
總結(jié)
Spark系統(tǒng)的性能調(diào)優(yōu)是一個很復(fù)雜的過程,必要對Spark以及Hadoop有足夠的知識儲備.從業(yè)務(wù)應(yīng)用平臺(Spark)、存儲(HDFS)、操作系統(tǒng)、硬件等多個層面都會對性能產(chǎn)生很大的影響.借助于多種性能監(jiān)控工具,我們可以很好地了解系統(tǒng)的性能表現(xiàn),并根據(jù)上面介紹的經(jīng)驗進行調(diào)整.
作者簡介:田毅,亞信科技大數(shù)據(jù)平臺部分研發(fā)經(jīng)理,Spark Contributor,北京Spark Meetup發(fā)起人,主要關(guān)注SparkSQL與Spark Streaming.
本文選自法式員電子版2015年3月A刊,該期更多文章請查看這里.2000年創(chuàng)刊至今所有文章目錄請查看法式員封面秀.歡迎訂閱法式員電子版(含iPad版、Android版、PDF版).
歡迎參與《Spark性能調(diào)優(yōu)》討論,分享您的想法,維易PHP學(xué)院為您提供專業(yè)教程。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/8700.html