您好,登錄后才能下訂單哦!
這篇文章主要介紹了Hive on Spark如何調(diào)優(yōu),具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
之前在Hive on Spark
跑TPCx-BB
測試時,100g的數(shù)據(jù)量要跑十幾個小時,一看CPU和內(nèi)存的監(jiān)控,發(fā)現(xiàn) POWER_TEST
階段(依次執(zhí)行30個查詢)CPU只用了百分之十幾,也就是沒有把整個集群的性能利用起來,導(dǎo)致跑得很慢。因此,如何調(diào)整參數(shù),使整個集群發(fā)揮最大性能顯得尤為重要。
詳細(xì)原理見上圖。我們使用spark-submit提交一個Spark作業(yè)之后,這個作業(yè)就會啟動一個對應(yīng)的Driver進程。根據(jù)你使用的部署模式(deploy-mode)不同,Driver進程可能在本地啟動,也可能在集群中某個工作節(jié)點上啟動。Driver進程本身會根據(jù)我們設(shè)置的參數(shù),占有一定數(shù)量的內(nèi)存和CPU core。而Driver進程要做的第一件事情,就是向集群管理器(可以是Spark Standalone集群,也可以是其他的資源管理集群,美團?大眾點評使用的是YARN作為資源管理集群)申請運行Spark作業(yè)需要使用的資源,這里的資源指的就是Executor進程。YARN集群管理器會根據(jù)我們?yōu)镾park作業(yè)設(shè)置的資源參數(shù),在各個工作節(jié)點上,啟動一定數(shù)量的Executor進程,每個Executor進程都占有一定數(shù)量的內(nèi)存和CPU core。
Spark是根據(jù)shuffle類算子來進行stage的劃分。如果我們的代碼中執(zhí)行了某個shuffle類算子(比如reduceByKey、join等),那么就會在該算子處,劃分出一個stage界限來。可以大致理解為,shuffle算子執(zhí)行之前的代碼會被劃分為一個stage,shuffle算子執(zhí)行以及之后的代碼會被劃分為下一個stage。因此一個stage剛開始執(zhí)行的時候,它的每個task可能都會從上一個stage的task所在的節(jié)點,去通過網(wǎng)絡(luò)傳輸拉取需要自己處理的所有key,然后對拉取到的所有相同的key使用我們自己編寫的算子函數(shù)執(zhí)行聚合操作(比如reduceByKey()算子接收的函數(shù))。這個過程就是shuffle。
task的執(zhí)行速度是跟每個Executor進程的CPU core數(shù)量有直接關(guān)系的。一個CPU core同一時間只能執(zhí)行一個線程。而每個Executor進程上分配到的多個task,都是以每個task一條線程的方式,多線程并發(fā)運行的。如果CPU core數(shù)量比較充足,而且分配到的task數(shù)量比較合理,那么通常來說,可以比較快速和高效地執(zhí)行完這些task線程。
以上就是Spark作業(yè)的基本運行原理的說明,大家可以結(jié)合上圖來理解。理解作業(yè)基本原理,是我們進行資源參數(shù)調(diào)優(yōu)的基本前提。
了解完了Spark作業(yè)運行的基本原理之后,對資源相關(guān)的參數(shù)就容易理解了。所謂的Spark資源參數(shù)調(diào)優(yōu),其實主要就是對Spark運行過程中各個使用資源的地方,通過調(diào)節(jié)各種參數(shù),來優(yōu)化資源使用的效率,從而提升Spark作業(yè)的執(zhí)行性能。以下參數(shù)就是Spark中主要的資源參數(shù),每個參數(shù)都對應(yīng)著作業(yè)運行原理中的某個部分。
num-executors/spark.executor.instances
參數(shù)說明:該參數(shù)用于設(shè)置Spark作業(yè)總共要用多少個Executor進程來執(zhí)行。Driver在向YARN集群管理器申請資源時,YARN集群管理器會盡可能按照你的設(shè)置來在集群的各個工作節(jié)點上,啟動相應(yīng)數(shù)量的Executor進程。這個參數(shù)非常之重要,如果不設(shè)置的話,默認(rèn)只會給你啟動少量的Executor進程,此時你的Spark作業(yè)的運行速度是非常慢的。
參數(shù)調(diào)優(yōu)建議:每個Spark作業(yè)的運行一般設(shè)置50~100個左右的Executor進程比較合適,設(shè)置太少或太多的Executor進程都不好。設(shè)置的太少,無法充分利用集群資源;設(shè)置的太多的話,大部分隊列可能無法給予充分的資源。
executor-memory/spark.executor.memory
參數(shù)說明:該參數(shù)用于設(shè)置每個Executor進程的內(nèi)存。Executor內(nèi)存的大小,很多時候直接決定了Spark作業(yè)的性能,而且跟常見的JVM OOM異常,也有直接的關(guān)聯(lián)。
參數(shù)調(diào)優(yōu)建議:每個Executor進程的內(nèi)存設(shè)置4G8G較為合適。但是這只是一個參考值,具體的設(shè)置還是得根據(jù)不同部門的資源隊列來定??梢钥纯醋约簣F隊的資源隊列的最大內(nèi)存限制是多少,num-executors乘以executor-memory,是不能超過隊列的最大內(nèi)存量的。此外,如果你是跟團隊里其他人共享這個資源隊列,那么申請的內(nèi)存量最好不要超過資源隊列最大總內(nèi)存的1/31/2,避免你自己的Spark作業(yè)占用了隊列所有的資源,導(dǎo)致別的同學(xué)的作業(yè)無法運行。
executor-cores/spark.executor.cores
參數(shù)說明:該參數(shù)用于設(shè)置每個Executor進程的CPU core數(shù)量。這個參數(shù)決定了每個Executor進程并行執(zhí)行task線程的能力。因為每個CPU core同一時間只能執(zhí)行一個task線程,因此每個Executor進程的CPU core數(shù)量越多,越能夠快速地執(zhí)行完分配給自己的所有task線程。
參數(shù)調(diào)優(yōu)建議:Executor的CPU core數(shù)量設(shè)置為2~4個較為合適。同樣得根據(jù)不同部門的資源隊列來定,可以看看自己的資源隊列的最大CPU core限制是多少,再依據(jù)設(shè)置的Executor數(shù)量,來決定每個Executor進程可以分配到幾個CPU core。同樣建議,如果是跟他人共享這個隊列,那么num-executors * executor-cores不要超過隊列總CPU core的1/3~1/2左右比較合適,也是避免影響其他同學(xué)的作業(yè)運行。
driver-memory
參數(shù)說明:該參數(shù)用于設(shè)置Driver進程的內(nèi)存。
參數(shù)調(diào)優(yōu)建議:Driver的內(nèi)存通常來說不設(shè)置,或者設(shè)置1G左右應(yīng)該就夠了。唯一需要注意的一點是,如果需要使用collect算子將RDD的數(shù)據(jù)全部拉取到Driver上進行處理,那么必須確保Driver的內(nèi)存足夠大,否則會出現(xiàn)OOM內(nèi)存溢出的問題。
spark.default.parallelism
參數(shù)說明:該參數(shù)用于設(shè)置每個stage的默認(rèn)task數(shù)量。這個參數(shù)極為重要,如果不設(shè)置可能會直接影響你的Spark作業(yè)性能。
參數(shù)調(diào)優(yōu)建議:Spark作業(yè)的默認(rèn)task數(shù)量為500~1000個較為合適。很多同學(xué)常犯的一個錯誤就是不去設(shè)置這個參數(shù),那么此時就會導(dǎo)致Spark自己根據(jù)底層HDFS的block數(shù)量來設(shè)置task的數(shù)量,默認(rèn)是一個HDFS block對應(yīng)一個task。通常來說,Spark默認(rèn)設(shè)置的數(shù)量是偏少的(比如就幾十個task),如果task數(shù)量偏少的話,就會導(dǎo)致你前面設(shè)置好的Executor的參數(shù)都前功盡棄。試想一下,無論你的Executor進程有多少個,內(nèi)存和CPU有多大,但是task只有1個或者10個,那么90%的Executor進程可能根本就沒有task執(zhí)行,也就是白白浪費了資源!因此Spark官網(wǎng)建議的設(shè)置原則是,設(shè)置該參數(shù)為num-executors * executor-cores的2~3倍較為合適,比如Executor的總CPU core數(shù)量為300個,那么設(shè)置1000個task是可以的,此時可以充分地利用Spark集群的資源。
spark.storage.memoryFraction
參數(shù)說明:該參數(shù)用于設(shè)置RDD持久化數(shù)據(jù)在Executor內(nèi)存中能占的比例,默認(rèn)是0.6。也就是說,默認(rèn)Executor 60%的內(nèi)存,可以用來保存持久化的RDD數(shù)據(jù)。根據(jù)你選擇的不同的持久化策略,如果內(nèi)存不夠時,可能數(shù)據(jù)就不會持久化,或者數(shù)據(jù)會寫入磁盤。
參數(shù)調(diào)優(yōu)建議:如果Spark作業(yè)中,有較多的RDD持久化操作,該參數(shù)的值可以適當(dāng)提高一些,保證持久化的數(shù)據(jù)能夠容納在內(nèi)存中。避免內(nèi)存不夠緩存所有的數(shù)據(jù),導(dǎo)致數(shù)據(jù)只能寫入磁盤中,降低了性能。但是如果Spark作業(yè)中的shuffle類操作比較多,而持久化操作比較少,那么這個參數(shù)的值適當(dāng)降低一些比較合適。此外,如果發(fā)現(xiàn)作業(yè)由于頻繁的gc導(dǎo)致運行緩慢(通過spark web ui可以觀察到作業(yè)的gc耗時),意味著task執(zhí)行用戶代碼的內(nèi)存不夠用,那么同樣建議調(diào)低這個參數(shù)的值。
spark.shuffle.memoryFraction
參數(shù)說明:該參數(shù)用于設(shè)置shuffle過程中一個task拉取到上個stage的task的輸出后,進行聚合操作時能夠使用的Executor內(nèi)存的比例,默認(rèn)是0.2。也就是說,Executor默認(rèn)只有20%的內(nèi)存用來進行該操作。shuffle操作在進行聚合時,如果發(fā)現(xiàn)使用的內(nèi)存超出了這個20%的限制,那么多余的數(shù)據(jù)就會溢寫到磁盤文件中去,此時就會極大地降低性能。
參數(shù)調(diào)優(yōu)建議:如果Spark作業(yè)中的RDD持久化操作較少,shuffle操作較多時,建議降低持久化操作的內(nèi)存占比,提高shuffle操作的內(nèi)存占比比例,避免shuffle過程中數(shù)據(jù)過多時內(nèi)存不夠用,必須溢寫到磁盤上,降低了性能。此外,如果發(fā)現(xiàn)作業(yè)由于頻繁的gc導(dǎo)致運行緩慢,意味著task執(zhí)行用戶代碼的內(nèi)存不夠用,那么同樣建議調(diào)低這個參數(shù)的值。
可以看出:
隨著每個executor占用的CPU core數(shù)增加,q04查詢的時間顯著下降,q03也下降,但幅度沒那么大。
本次調(diào)優(yōu)只設(shè)置了spark.executor.memory
和spark.executor.cores
兩個參數(shù),沒有涉及到spark.executor.instances
參數(shù),而默認(rèn)的spark.executor.instances
為2,也就是每個作業(yè)只用到2個executor,因此還沒將性能發(fā)揮到最佳。
接下來采用100g的數(shù)據(jù)量,并且增加spark.executor.instances
參數(shù)的設(shè)置。
可以看出:
調(diào)優(yōu)前后查詢時間有了很大的飛躍;
增加spark.executor.instances
設(shè)置項指定每個作業(yè)占用的executor個數(shù)后性能又有很大提升(通過監(jiān)控我們發(fā)現(xiàn)此時CPU利用率平均有好幾十,甚至可以高到百分之九十幾);
至此,我們終于將整個集群性能充分發(fā)揮出來,達到目的。
最后一列配置項是根據(jù)美團技術(shù)團隊博客的建議設(shè)置的,可以看出性能相比我們之前自己的設(shè)置還是有一定提升的,至少該博客里建議的設(shè)置是比較通用的,因此之后我們都采取最后一列的設(shè)置來跑TPCx-BB
測試。
最后來張大圖展示調(diào)優(yōu)前和調(diào)優(yōu)后跑100g數(shù)據(jù)的對比:
可以看出:
絕大多數(shù)查詢調(diào)優(yōu)前后查詢時間有了極大的飛躍;
但是像q01/q04/q14...這幾個查詢,可能因為查詢涉及到的表比較小,調(diào)優(yōu)前時間就很短,因此調(diào)優(yōu)后也看不出很多差別,如果想看到大的差別,可能需要提高數(shù)據(jù)量,比如1T,3T;
q10和q18調(diào)優(yōu)前后時間都較長,而且調(diào)優(yōu)后性能沒有提升,需要再深入探索下是什么原因。
最后,用調(diào)優(yōu)后的集群,分別跑10g、30g、100g的數(shù)據(jù),結(jié)果如下:
10g、30g、100g.jpg.png
可以看出:
隨著數(shù)據(jù)量增大,很多查詢時間并沒有明顯增加,可能是因為集群性能太強,而且數(shù)據(jù)量還不夠大,可以增大數(shù)據(jù)量繼續(xù)觀察
對于q10、q18和q30,隨著數(shù)據(jù)量增大,時間明顯增大,需再深入分析
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Hive on Spark如何調(diào)優(yōu)”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。