《《Spark 官方文檔》Spark調(diào)優(yōu)》要點(diǎn):
本文介紹了《Spark 官方文檔》Spark調(diào)優(yōu),希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
Spark調(diào)優(yōu)
由于大部分Spark計(jì)算都是在內(nèi)存中完成的,所以Spark程序的瓶頸可能由集群中任意一種資源導(dǎo)致,如:CPU、網(wǎng)絡(luò)帶寬、或者內(nèi)存等.最常見(jiàn)的情況是,數(shù)據(jù)能裝進(jìn)內(nèi)存,而瓶頸是網(wǎng)絡(luò)帶寬;當(dāng)然,有時(shí)候我們也需要做一些優(yōu)化調(diào)整來(lái)減少內(nèi)存占用,例如將RDD以序列化格式保存( storing RDDs in serialized form ).本文將主要涵蓋兩個(gè)主題:1.數(shù)據(jù)序列化(這對(duì)于優(yōu)化網(wǎng)絡(luò)性能極為重要);2.減少內(nèi)存占用以及內(nèi)存調(diào)優(yōu).同時(shí),我們也會(huì)提及其他幾個(gè)比較小的主題.
數(shù)據(jù)序列化
序列化在任何一種分布式應(yīng)用性能優(yōu)化時(shí)都扮演幾位重要的角色.如果序列化格式序列化過(guò)程緩慢,或者需要占用字節(jié)很多,都會(huì)大大拖慢整體的計(jì)算效率.通常,序列化都是Spark應(yīng)用優(yōu)化時(shí)首先需要關(guān)注的地方.Spark著眼于要達(dá)到便利性(允許你在計(jì)算過(guò)程中使用任何Java類型)和性能的一個(gè)平衡.Spark主要提供了兩個(gè)序列化庫(kù):
Java serialization : 默認(rèn)情況,Spark使用Java自帶的ObjectOutputStream 框架來(lái)序列化對(duì)象,這樣任何實(shí)現(xiàn)了 java.io.Serializable 接口的對(duì)象,都能被序列化.同時(shí),你還可以通過(guò)擴(kuò)展 java.io.Externalizable 來(lái)控制序列化性能.Java序列化很靈活但性能較差,同時(shí)序列化后占用的字節(jié)數(shù)也較多.
Kryo serialization : Spark還可以使用Kryo 庫(kù)(版本2)提供更高效的序列化格式.Kryo的序列化速度和字節(jié)占用都比Java序列化好很多(通常是10倍左右),但Kryo不支持所有實(shí)現(xiàn)了 Serializable 接口的類型,它需要你在程序中 register 需要序列化的類型,以得到最佳性能.
要切換到使用 Kryo,你可以在 SparkConf 初始化的時(shí)候調(diào)用 conf.set(“spark.serializer”, “org.apache.spark.serializer.KryoSerializer”).這個(gè)設(shè)置不僅控制各個(gè)worker節(jié)點(diǎn)之間的混洗數(shù)據(jù)序列化格式,同時(shí)還控制RDD存到磁盤上的序列化格式.目前,Kryo不是默認(rèn)的序列化格式,因?yàn)樗枰阍谑褂们白?cè)需要序列化的類型,不過(guò)我們還是建議在對(duì)網(wǎng)絡(luò)敏感的應(yīng)用場(chǎng)景下使用Kryo.
Spark對(duì)一些常用的Scala核心類型(包括在 Twitter chill 庫(kù)的AllScalaRegistrar中)自動(dòng)使用Kryo序列化格式.
如果你的自定義類型需要使用Kryo序列化,可以用 registerKryoClasses 辦法先注冊(cè):
val conf = new SparkConf.setMaster(...).setAppName(...)
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
val sc = new SparkContext(conf)
Kryo的文檔( Kryo documentation )中有詳細(xì)描述了更多的高級(jí)選項(xiàng),如:自定義序列化代碼等.
如果你的對(duì)象很大,你可能需要增大 spark.kryoserializer.buffer 配置項(xiàng)( config).其值至少需要大于最大對(duì)象的序列化長(zhǎng)度.
最后,如果你不注冊(cè)需要序列化的自定義類型,Kryo也能工作,不過(guò)每一個(gè)對(duì)象實(shí)例的序列化結(jié)果都會(huì)包含一份完整的類名,這有點(diǎn)浪費(fèi)空間.
內(nèi)存調(diào)優(yōu)
內(nèi)存占用調(diào)優(yōu)主要需要考慮3點(diǎn):1.數(shù)據(jù)占用的總內(nèi)存(你多半會(huì)希望整個(gè)數(shù)據(jù)集都能裝進(jìn)內(nèi)存吧);2.拜訪數(shù)據(jù)集中每個(gè)對(duì)象的開銷;3.垃圾回收的開銷(如果你的數(shù)據(jù)集中對(duì)象周轉(zhuǎn)速度很快的話).
一般,Java對(duì)象的拜訪時(shí)很快的,但同時(shí)Java對(duì)象會(huì)比原始數(shù)據(jù)(僅包含各個(gè)字段值)占用的空間多2~5倍.主要原因有:
每個(gè)Java對(duì)象都有一個(gè)對(duì)象頭(object header),對(duì)象頭大約占用16字節(jié),其中包含像其對(duì)應(yīng)class的指針這樣的信息.對(duì)于一些包含較少數(shù)據(jù)的對(duì)象(比如只包含一個(gè)Int字段),這個(gè)對(duì)象頭可能比對(duì)象數(shù)據(jù)本身還大.
Java字符串(String)有大約40子節(jié)點(diǎn)額外開銷(Java String以Char數(shù)據(jù)的形式保存原始數(shù)據(jù),所以需要一些額外的字段,如數(shù)組長(zhǎng)度等),并且每個(gè)字符都以兩字節(jié)的UTF-16編碼在內(nèi)部保存.因此,10個(gè)字符的String很容易就占了60字節(jié).
一些常見(jiàn)的集合類,如 HashMap、LinkedList,使用的是鏈表類數(shù)據(jù)結(jié)構(gòu),因此它們對(duì)每項(xiàng)數(shù)據(jù)都有一個(gè)包裝器.這些包裝器對(duì)象不僅其自身就有“對(duì)象頭”,同時(shí)還有指向下一個(gè)包裝器對(duì)象的鏈表指針(通常為8字節(jié)).
原始類型的集合通常也是以“裝箱”的形式包裝成對(duì)象(如:java.lang.Integer).
本節(jié)只是Spark內(nèi)存管理的一個(gè)概要,下面我們會(huì)更詳細(xì)地討論各種Spark內(nèi)存調(diào)優(yōu)的具體策略.特別地,我們會(huì)討論如何評(píng)估數(shù)據(jù)的內(nèi)存使用量,以及如何改進(jìn) – 要么改變你的數(shù)據(jù)結(jié)構(gòu),要么以某種序列化格式存儲(chǔ)數(shù)據(jù).最后,我們還會(huì)討論如何調(diào)整Spark的緩存大小,以及如何調(diào)優(yōu)Java的垃圾回收器.
內(nèi)存管理概覽
Spark中內(nèi)存主要用于兩類目的:執(zhí)行計(jì)算和數(shù)據(jù)存儲(chǔ).執(zhí)行計(jì)算的內(nèi)存主要用于混洗(Shuffle)、關(guān)聯(lián)(join)、排序(sort)以及聚合(aggregation),而數(shù)據(jù)存儲(chǔ)的內(nèi)存主要用于緩存和集群內(nèi)部數(shù)據(jù)傳播.Spark中執(zhí)行計(jì)算和數(shù)據(jù)存儲(chǔ)都是共享同一個(gè)內(nèi)存區(qū)域(M).如果執(zhí)行計(jì)算沒(méi)有占用內(nèi)存,那么數(shù)據(jù)存儲(chǔ)可以申請(qǐng)占用所有可用的內(nèi)存,反之亦然.執(zhí)行計(jì)算可能會(huì)搶占數(shù)據(jù)存儲(chǔ)使用的內(nèi)存,并將存儲(chǔ)于內(nèi)存的數(shù)據(jù)逐出內(nèi)存,直到數(shù)據(jù)存儲(chǔ)占用的內(nèi)存比例降低到一個(gè)指定的比例(R).換句話說(shuō),R是M基礎(chǔ)上的一個(gè)子區(qū)域,這個(gè)區(qū)域的內(nèi)存數(shù)據(jù)永遠(yuǎn)不會(huì)被逐出內(nèi)存.然而,數(shù)據(jù)存儲(chǔ)不會(huì)搶占執(zhí)行計(jì)算的內(nèi)存(否則實(shí)現(xiàn)太復(fù)雜了).
這樣設(shè)計(jì)主要有這么幾個(gè)需要考慮的點(diǎn).首先,不需要緩存數(shù)據(jù)的應(yīng)用可以把整個(gè)空間用來(lái)執(zhí)行計(jì)算,從而避免頻繁地把數(shù)據(jù)吐到磁盤上.其次,需要緩存數(shù)據(jù)的應(yīng)用能夠有一個(gè)數(shù)據(jù)存儲(chǔ)比例(R)的最低保證,也避免這部分緩存數(shù)據(jù)被全部逐出內(nèi)存.最后,這個(gè)實(shí)現(xiàn)方式能夠在默認(rèn)情況下,為大多數(shù)使用場(chǎng)景提供合理的性能,而不需要專家級(jí)用戶來(lái)設(shè)置內(nèi)存使用如何劃分.
雖然有兩個(gè)內(nèi)存劃分相關(guān)的配置參數(shù),但一般來(lái)說(shuō),用戶不需要設(shè)置,因?yàn)槟J(rèn)值已經(jīng)能夠適用于絕大部分的使用場(chǎng)景:
spark.memory.fraction 表示上面M的大小,其值為相對(duì)于JVM堆內(nèi)存的比例(默認(rèn)0.75).剩余的25%是為其他用戶數(shù)據(jù)結(jié)構(gòu)、Spark內(nèi)部元數(shù)據(jù)以及避免OOM錯(cuò)誤的平安預(yù)留空間(大量稀疏數(shù)據(jù)和異常大的數(shù)據(jù)記錄).
spark.memory.storageFraction 表示上面R的大小,其值為相對(duì)于M的一個(gè)比例(默認(rèn)0.5).R是M中專門用于緩存數(shù)據(jù)塊,且這部分?jǐn)?shù)據(jù)塊永遠(yuǎn)不會(huì)因執(zhí)行計(jì)算任務(wù)而逐出內(nèi)存.
評(píng)估內(nèi)存消耗
確定一個(gè)數(shù)據(jù)集占用內(nèi)存總量最好的方法就是,創(chuàng)建一個(gè)RDD,并緩存到內(nèi)存中,然后再到web UI上”Storage”頁(yè)面查看.頁(yè)面上會(huì)展示這個(gè)RDD總共占用了多少內(nèi)存.
要評(píng)估一個(gè)特定對(duì)象的內(nèi)存占用量,可以用 SizeEstimator.estimate 辦法.這個(gè)辦法對(duì)試驗(yàn)?zāi)姆N數(shù)據(jù)結(jié)構(gòu)能夠裁剪內(nèi)存占用量比較有用,同時(shí),也可以幫助用戶了解廣播變量在每個(gè)執(zhí)行器堆上占用的內(nèi)存量.
數(shù)據(jù)結(jié)構(gòu)調(diào)優(yōu)
減少內(nèi)存消耗的首要辦法就是避免過(guò)多的Java封裝(減少對(duì)象頭和額外輔助字段),比如基于指針的數(shù)據(jù)結(jié)構(gòu)和包裝對(duì)象等.以下有幾條建議:
設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)的時(shí)候,優(yōu)先使用對(duì)象數(shù)組和原生類型,減少對(duì)復(fù)雜集合類型(如:HashMap)的使用. fastutil 提供了一些很方便的原聲類型集合,同時(shí)兼容Java標(biāo)準(zhǔn)庫(kù).
盡可能避免嵌套大量的小對(duì)象和指針.
對(duì)應(yīng)鍵值應(yīng)盡量使用數(shù)值型或枚舉型,而不是字符串型.
如果內(nèi)存小于32GB,可以設(shè)置JVM標(biāo)志參數(shù) -XX:+UseCompressdOops 將指針設(shè)為4字節(jié)而不是8字節(jié).你可以在 spark-env.sh 中設(shè)置這個(gè)參數(shù).
序列化RDD存儲(chǔ)
如果經(jīng)過(guò)上面的調(diào)整后,存儲(chǔ)的數(shù)據(jù)對(duì)象還是太大,那么你可以試試將這些對(duì)象以序列化格式存儲(chǔ),所需要做的只是通過(guò) RDD persistence API 設(shè)置好存儲(chǔ)級(jí)別,如:MEMORY_ONLY_SER.Spark會(huì)將RDD的每個(gè)分區(qū)以一個(gè)巨大的字節(jié)數(shù)組形式存儲(chǔ)起來(lái).以序列化格式存儲(chǔ)的唯一缺點(diǎn)就是拜訪數(shù)據(jù)會(huì)變慢一點(diǎn),因?yàn)镾park需要反序列化每個(gè)被拜訪的對(duì)象.如果你需要序列化緩存數(shù)據(jù),我們強(qiáng)烈建議你使用Kryo(using Kryo ),和Java序列化相比,Kryo能大大減少序列化對(duì)象占用的空間(當(dāng)然也比原始Java對(duì)象小很多).
垃圾回收調(diào)優(yōu)
JVM的垃圾回收在某些情況下可能會(huì)造成瓶頸,比如,你的RDD存儲(chǔ)經(jīng)常需要“換入換出”(新RDD搶占了老RDD內(nèi)存,不過(guò)如果你的程序沒(méi)有這種情況的話那JVM垃圾回收一般不是問(wèn)題,比如,你的RDD只是載入一次,后續(xù)只是在這一個(gè)RDD上做操作).當(dāng)Java需要把老對(duì)象逐出內(nèi)存的時(shí)候,JVM需要跟蹤所有的Java對(duì)象,并找出那些對(duì)象已經(jīng)沒(méi)有用了.概括起來(lái)就是,垃圾回收的開銷和對(duì)象個(gè)數(shù)成正比,所以減少對(duì)象的個(gè)數(shù)(比如用 Int數(shù)組取代 LinkedList),就能大大減少垃圾回收的開銷.當(dāng)然,一個(gè)更好的辦法就如前面所說(shuō)的,以序列化形式存儲(chǔ)數(shù)據(jù),這時(shí)每個(gè)RDD分區(qū)都只包含有一個(gè)對(duì)象了(一個(gè)巨大的字節(jié)數(shù)組).在嘗試其他技術(shù)方案前,首先可以試試用序列化RDD的方式( serialized caching )評(píng)估一下GC是不是一個(gè)瓶頸.
如果你的作業(yè)中各個(gè)任務(wù)需要的工作內(nèi)存和節(jié)點(diǎn)上存儲(chǔ)的RDD緩存占用的內(nèi)存產(chǎn)生沖突,那么GC很可能會(huì)出現(xiàn)問(wèn)題.下面我們將討論一下如何控制好RDD緩存使用的內(nèi)存空間,以減少這種沖突.
衡量GC的影響
GC調(diào)優(yōu)的第一步是統(tǒng)計(jì)一下,垃圾回收啟動(dòng)的頻率以及GC所使用的總時(shí)間.給JVM設(shè)置一下這幾個(gè)參數(shù)(參考Spark配置指南 – configuration guide ,查看Spark作業(yè)中的Java選項(xiàng)參數(shù)):-verbose:gc -XX:+PrintGCDetails,就可以在后續(xù)Spark作業(yè)的worker日志中看到每次GC花費(fèi)的時(shí)間.注意,這些日志是在集群worker節(jié)點(diǎn)上(在各節(jié)點(diǎn)的工作目錄下stdout文件中),而不是你的驅(qū)動(dòng)器所在節(jié)點(diǎn).
高級(jí)GC調(diào)優(yōu)
為了進(jìn)一步調(diào)優(yōu)GC,我們就需要對(duì)JVM內(nèi)存管理有一個(gè)基本的了解:
Java堆內(nèi)存可分配的空間有兩個(gè)區(qū)域:新生代(Young generation)和老生代(Old generation).新生代用以保存生存周期短的對(duì)象,而老生代則是保存生存周期長(zhǎng)的對(duì)象.
新生代區(qū)域被進(jìn)一步劃分為三個(gè)子區(qū)域:Eden,Survivor1,Survivor2.
簡(jiǎn)要描述一下垃圾回收的過(guò)程:如果Eden區(qū)滿了,則啟動(dòng)一輪minor GC回收Eden中的對(duì)象,生存下來(lái)(沒(méi)有被回收掉)的Eden中的對(duì)象和Survivor1區(qū)中的對(duì)象一并復(fù)制到Survivor2中.兩個(gè)Survivor區(qū)域是互相切換使用的(就是說(shuō),下次從Eden和Survivor2中復(fù)制到Survivor1中).如果某個(gè)對(duì)象的年齡(每次GC所有生存下來(lái)的對(duì)象長(zhǎng)一歲)超過(guò)某個(gè)閾值,或者Survivor2(下次是Survivor1)區(qū)域滿了,則將對(duì)象移到老生代(Old區(qū)).最終如果老生代也滿了,就會(huì)啟動(dòng)full GC.
Spark GC調(diào)優(yōu)的目標(biāo)就是確保老生代(Old generation )只保存長(zhǎng)生命周期RDD,而同時(shí)新生代(Young generation )的空間又能足夠保存短生命周期的對(duì)象.這樣就能在任務(wù)執(zhí)行期間,避免啟動(dòng)full GC.以下是GC調(diào)優(yōu)的主要步驟:
從GC的統(tǒng)計(jì)日志中觀察GC是否啟動(dòng)太多.如果某個(gè)任務(wù)結(jié)束前,多次啟動(dòng)了full GC,則意味著用以執(zhí)行該任務(wù)的內(nèi)存不夠.
如果GC統(tǒng)計(jì)信息中顯示,老生代內(nèi)存空間已經(jīng)接近存滿,可以通過(guò)降低 spark.memory.storageFraction 來(lái)減少RDD緩存占用的內(nèi)存;減少緩存對(duì)象總比任務(wù)執(zhí)行緩慢要強(qiáng)!
如果major GC比較少,但minor GC很多的話,可以多分配一些Eden內(nèi)存.你可以把Eden的大小設(shè)為高于各個(gè)任務(wù)執(zhí)行所需的工作內(nèi)存.如果要把Eden大小設(shè)為E,則可以這樣設(shè)置新生代區(qū)域大小:-Xmn=4/3*E.(放大4/3倍,主要是為了給Survivor區(qū)域保留空間)
舉例來(lái)說(shuō),如果你的任務(wù)會(huì)從HDFS上讀取數(shù)據(jù),那么單個(gè)任務(wù)的內(nèi)存需求可以用其所讀取的HDFS數(shù)據(jù)塊的大小來(lái)評(píng)估.需要特別注意的是,解壓后的HDFS塊是解壓前的2~3倍大.所以如果我們希望保留3~4個(gè)任務(wù)并行的工作內(nèi)存,并且HDFS塊大小為64MB,那么可以評(píng)估Eden的大小應(yīng)該設(shè)為 4*3*64MB.
最后,再觀察一下垃圾回收的啟動(dòng)頻率和總耗時(shí)有沒(méi)有什么變化.
我們的很多經(jīng)驗(yàn)表明,GC調(diào)優(yōu)的效果和你的程序代碼以及可用的總內(nèi)存相關(guān).網(wǎng)上還有不少調(diào)優(yōu)的選項(xiàng)說(shuō)明( many more tuning options ),但總體來(lái)說(shuō),就是控制好full GC的啟動(dòng)頻率,就能有效減少垃圾回收開銷.
其他注意事項(xiàng)
并行度
一般來(lái)說(shuō)集群并不會(huì)滿負(fù)荷運(yùn)轉(zhuǎn),除非你吧每個(gè)操作的并行度都設(shè)得足夠大.Spark會(huì)自動(dòng)根據(jù)對(duì)應(yīng)的輸入文件大小來(lái)設(shè)置“map”類算子的并行度(當(dāng)然你可以通過(guò)一個(gè)SparkContext.textFile等函數(shù)的可選參數(shù)來(lái)控制并行度),而對(duì)于想 groupByKey 或reduceByKey這類 “reduce” 算子,會(huì)使用其各父RDD分區(qū)數(shù)的最大值.你可以將并行度作為構(gòu)建RDD第二個(gè)參數(shù)(參考 spark.PairRDDFunctions ),或者設(shè)置 spark.default.parallelism 這個(gè)默認(rèn)值.一般來(lái)說(shuō),評(píng)估并行度的時(shí)候,我們建議2~3個(gè)任務(wù)共享一個(gè)CPU.
Reduce任務(wù)的內(nèi)存占用
如果RDD比內(nèi)存要大,有時(shí)候你可能收到一個(gè)OutOfMemoryError,但其實(shí)這是因?yàn)槟愕娜蝿?wù)集中的某個(gè)任務(wù)太大了,如reduce任務(wù)groupByKey.Spark的混洗(Shuffle)算子(sortByKey,groupByKey,reduceByKey,join等)會(huì)在每個(gè)任務(wù)中構(gòu)建一個(gè)哈希表,以便在任務(wù)中對(duì)數(shù)據(jù)分組,這個(gè)哈希表有時(shí)會(huì)很大.最簡(jiǎn)單的修復(fù)方法就是增大并行度,以減小單個(gè)任務(wù)的輸入集.Spark對(duì)于200ms以內(nèi)的短任務(wù)支持非常好,因?yàn)镾park可以跨任務(wù)復(fù)用執(zhí)行器JVM,任務(wù)的啟動(dòng)開銷很小,因此把并行度增加到比集群中總CPU核數(shù)還多是沒(méi)有任何問(wèn)題的.
廣播大變量
使用SparkContext中的廣播變量相關(guān)功能( broadcast functionality )能大大減少每個(gè)任務(wù)本身序列化的大小,以及集群中啟動(dòng)作業(yè)的開銷.如果你的Spark任務(wù)正在使用驅(qū)動(dòng)器(driver)程序中定義的巨大對(duì)象(比如:靜態(tài)查詢表),請(qǐng)考慮使用廣播變量替代之.Spark會(huì)在master上將各個(gè)任務(wù)的序列化后大小打印出來(lái),所以你可以檢查一下各個(gè)任務(wù)是否過(guò)大;通常來(lái)說(shuō),大于20KB的任務(wù)就值得優(yōu)化一下.
數(shù)據(jù)本地性
數(shù)據(jù)本地性對(duì)Spark作業(yè)往往會(huì)有較大的影響.如果代碼和其所操作的數(shù)據(jù)在統(tǒng)一節(jié)點(diǎn)上,那么計(jì)算速度肯定會(huì)更快一些.但如果二者不在一起,那必然需要挪動(dòng)其中之一.一般來(lái)說(shuō),挪動(dòng)序列化好的代碼肯定比挪動(dòng)一大堆數(shù)據(jù)要快.Spark就是基于這個(gè)一般性原則來(lái)構(gòu)建數(shù)據(jù)本地性的調(diào)度.
數(shù)據(jù)本地性是指代碼和其所處理的數(shù)據(jù)的距離.基于數(shù)據(jù)當(dāng)前的位置,數(shù)據(jù)本地性可以劃分成以下幾個(gè)層次(按從近到遠(yuǎn)排序):
PROCESS_LOCAL 數(shù)據(jù)和運(yùn)行的代碼處于同一個(gè)JVM進(jìn)程內(nèi).
NODE_LOCAL 數(shù)據(jù)和代碼處于同一節(jié)點(diǎn).例如,數(shù)據(jù)處于HDFS上某個(gè)節(jié)點(diǎn),而對(duì)應(yīng)的執(zhí)行器(executor)也在同一個(gè)機(jī)器節(jié)點(diǎn)上.這會(huì)比PROCESS_LOCAL稍微慢一些,因?yàn)閿?shù)據(jù)需要跨進(jìn)程傳遞.
NO_PREF 數(shù)據(jù)在任何地方處理都一樣,沒(méi)有本地性偏好.
RACK_LOCAL 數(shù)據(jù)和代碼處于同一個(gè)機(jī)架上的不同機(jī)器.這時(shí),數(shù)據(jù)和代碼處于不同機(jī)器上,需要通過(guò)網(wǎng)絡(luò)傳遞,但還是在同一個(gè)機(jī)架上,一般也就通過(guò)一個(gè)交換機(jī)傳輸即可.
ANY 數(shù)據(jù)在網(wǎng)絡(luò)中其他未知,即數(shù)據(jù)和代碼不在同一個(gè)機(jī)架上.
Spark傾向于讓所有任務(wù)都具有最佳的數(shù)據(jù)本地性,但這并非總是可行的.某些情況下,可能會(huì)出現(xiàn)一些空閑的執(zhí)行器(executor)沒(méi)有待處理的數(shù)據(jù),那么Spark可能就會(huì)犧牲一些數(shù)據(jù)本地性.有兩種可能的選項(xiàng):a)等待已經(jīng)有任務(wù)的CPU,待其釋放后立即在同一臺(tái)機(jī)器上啟動(dòng)一個(gè)任務(wù);b)立即在其他節(jié)點(diǎn)上啟動(dòng)新任務(wù),并把所需要的數(shù)據(jù)復(fù)制過(guò)去.
而通常,Spark會(huì)等待一小會(huì),看看是否有CPU會(huì)被釋放出來(lái).一旦等待超時(shí),則立即在其他節(jié)點(diǎn)上啟動(dòng)并將所需的數(shù)據(jù)復(fù)制過(guò)去.數(shù)據(jù)本地性各個(gè)級(jí)別之間的回落超時(shí)可以單獨(dú)配置,也可以在統(tǒng)一參數(shù)內(nèi)一起設(shè)定;詳細(xì)請(qǐng)參考 configuration page 中的 spark.locality 相關(guān)參數(shù).如果你的任務(wù)執(zhí)行時(shí)間比較長(zhǎng)并且數(shù)據(jù)本地性很差,你就應(yīng)該試試調(diào)大這幾個(gè)參數(shù),不過(guò)默認(rèn)值一般都能適用于大多數(shù)場(chǎng)景了.
總結(jié)
本文是一個(gè)簡(jiǎn)短的Spark調(diào)優(yōu)指南,列舉了Spark應(yīng)用調(diào)優(yōu)一些比較重要的考慮點(diǎn) – 最重要的就是,數(shù)據(jù)序列化和內(nèi)存調(diào)優(yōu).對(duì)于絕大多數(shù)應(yīng)用來(lái)說(shuō),用Kryo格式序列化數(shù)據(jù)能夠辦理大多數(shù)的性能問(wèn)題.如果您有其他關(guān)于性能調(diào)優(yōu)最佳實(shí)踐的問(wèn)題,歡迎郵件咨詢( Spark mailing list ).
《《Spark 官方文檔》Spark調(diào)優(yōu)》是否對(duì)您有啟發(fā),歡迎查看更多與《《Spark 官方文檔》Spark調(diào)優(yōu)》相關(guān)教程,學(xué)精學(xué)透。維易PHP學(xué)院為您提供精彩教程。
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.snjht.com/jiaocheng/7850.html