【轉(zhuǎn)載】Spark調(diào)優(yōu)(數(shù)據(jù)序列化和內(nèi)存調(diào)優(yōu))

翻譯自Spark官網(wǎng)文檔:https://spark.apache.org/docs/2.1.0/tuning.html

前言

由于大多數(shù)Spark計(jì)算的內(nèi)存使用特性馅精,集群中的任何資源都可能成為Spark計(jì)算程序中的瓶頸:CPU,網(wǎng)絡(luò)帶寬或是內(nèi)存灼伤。大多數(shù)情況下,如果內(nèi)存可以容納數(shù)據(jù)量竿刁,那么瓶頸就會(huì)是網(wǎng)絡(luò)帶寬眼耀,但有時(shí),用戶(hù)也需要去做一點(diǎn)調(diào)優(yōu)的工作随常,例如以序列化的格式存儲(chǔ)RDD,來(lái)減少內(nèi)存使用萄涯。本文主要關(guān)注兩個(gè)主題:數(shù)據(jù)序列化绪氛,對(duì)網(wǎng)絡(luò)性能和內(nèi)存使用來(lái)說(shuō)很重要,和內(nèi)存調(diào)優(yōu)窃判。同時(shí)也會(huì)討論一些較小的主題钞楼。

一、數(shù)據(jù)序列化

序列化在分布式應(yīng)用中起到很重要的作用袄琳。那些會(huì)讓對(duì)象序列化過(guò)程緩慢,或是會(huì)消耗大量字節(jié)存儲(chǔ)的序列化格式會(huì)大大降低計(jì)算速率燃乍。通常這會(huì)用戶(hù)在優(yōu)化Spark應(yīng)用程序中的第一件事唆樊。Spark旨在在便利(允許您使用您的操作中的任何Java類(lèi)型)和性能之間實(shí)現(xiàn)平衡。它提供了下面兩種序列化庫(kù):

(1)Java serialization:Spark默認(rèn)使用Java的ObjectOutputStream框架來(lái)序列化對(duì)象刻蟹,可以對(duì)任何實(shí)現(xiàn)了java.io.Serializable的任何類(lèi)進(jìn)行序列化逗旁。用戶(hù)也可以通過(guò)繼承來(lái)實(shí)現(xiàn)更緊密的序列化性能控制。

(2)Kryo serialization:Spark也可以使用Kryo庫(kù)(version 2)來(lái)實(shí)現(xiàn)更快的對(duì)象序列化。Kryo比Java序列化更快片效、數(shù)據(jù)格式更緊湊红伦,但不支持所有的Serializable類(lèi)型。用戶(hù)如果希望使用Kryo來(lái)獲取更好的性能淀衣,需要先去注冊(cè)應(yīng)用程序中會(huì)使用到的類(lèi)昙读。

用戶(hù)可以在初始化任務(wù)時(shí)通過(guò)設(shè)定SparkConf中的conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")來(lái)切換序列化框架為Kryo。這里的序列化配置不僅可以對(duì)worker節(jié)點(diǎn)之間的shuffle數(shù)據(jù)起作用膨桥,還可以在將RDD序列化到disk上時(shí)起作用蛮浑。Kryo不是默認(rèn)序列化選擇的唯一原因它要求了用戶(hù)的注冊(cè)行為,但是我們建議在所有網(wǎng)絡(luò)密集型應(yīng)用程序中使用它只嚣。從Spark2.0.0開(kāi)始沮稚,我們?cè)趥鬏敽?jiǎn)單類(lèi)型或是字符串類(lèi)型的Shuffle RDD時(shí)會(huì)默認(rèn)使用Kryo序列化。

Spark自動(dòng)對(duì)許多在Twitter chill庫(kù)中的AllScalaRegistrar被覆蓋的常用的Scala類(lèi)注冊(cè)了Kryo册舞。
注冊(cè)用戶(hù)自身的類(lèi)到kryo時(shí)蕴掏,可以使用registerKryoClasses方法:

val conf = new SparkConf().setMaster(...).setAppName(...)
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
val sc = new SparkContext(conf)

Kryo的文檔https://github.com/EsotericSoftware/kryo描述了更多進(jìn)階的注冊(cè)選項(xiàng),例如增加用戶(hù)序列化代碼等等调鲸。
如果用戶(hù)的對(duì)象很大囚似,也需要去增加spark.kryoserializer.buffer配置項(xiàng)。這個(gè)值需要達(dá)到足以保存你將要序列化的最大的對(duì)象线得。
最后饶唤,如果你不注冊(cè)用戶(hù)類(lèi),kryo也可以工作贯钩,但是它將會(huì)存儲(chǔ)每個(gè)對(duì)象的全類(lèi)名募狂,會(huì)造成存儲(chǔ)空間的浪費(fèi)。

二角雷、內(nèi)存調(diào)優(yōu)

在對(duì)內(nèi)存的使用進(jìn)行調(diào)優(yōu)時(shí)有三個(gè)考慮點(diǎn):用戶(hù)對(duì)象的內(nèi)存使用量(用戶(hù)可能希望整個(gè)數(shù)據(jù)集都保存在內(nèi)存中)祸穷,訪(fǎng)問(wèn)這些對(duì)象的開(kāi)銷(xiāo)和垃圾回收的開(kāi)銷(xiāo)(如果用戶(hù)的對(duì)象周轉(zhuǎn)率很高)。

默認(rèn)情況下勺三,java對(duì)象的訪(fǎng)問(wèn)是很快的雷滚,但很容易就會(huì)消耗比字段中原始數(shù)據(jù)多2-5倍的空間。這是以下幾個(gè)原因?qū)е碌模?/p>

(1)每個(gè)不同的Java對(duì)象都有一個(gè)“object header”吗坚,這個(gè)頭部大概會(huì)占用16bytes的空間并且會(huì)包含指向類(lèi)的指針等信息祈远。對(duì)于一個(gè)數(shù)據(jù)量很小的對(duì)象(例如一個(gè)Int對(duì)象),它會(huì)比數(shù)據(jù)占用的空間更大商源。

(2)Java字符串比原始字符串?dāng)?shù)據(jù)多了大約40個(gè)字節(jié)的開(kāi)銷(xiāo)(因?yàn)樗鼈兪且訡hars數(shù)據(jù)的形式存儲(chǔ)的车份,并且保存了一些例如length的額外信息),并且由于字符串內(nèi)部的UTF-16編碼牡彻,會(huì)將它存儲(chǔ)為兩個(gè)bytes扫沼。所以一個(gè)有10個(gè)character的字符串會(huì)很容易消耗60bytes。

(3)常用的集合類(lèi),例如HashMap和LinkedList缎除,使用鏈?zhǔn)綌?shù)據(jù)結(jié)構(gòu)严就,它對(duì)于每個(gè)entry(例如Map.Entry)會(huì)有一個(gè)"wrapper"對(duì)象。這個(gè)對(duì)象不僅包含頭部信息器罐,還包含了一個(gè)指向列表中下一個(gè)對(duì)象的指針(通常會(huì)占用8bytes)梢为。

(4)原始類(lèi)型的集合通常將它們存儲(chǔ)為“boxed”對(duì)象,如java .lang. integer

本章會(huì)以Spark的內(nèi)存管理機(jī)制的概述開(kāi)始技矮,然后討論用戶(hù)能在應(yīng)用程序中采用的更有效的內(nèi)存策略抖誉。特別地,我們還會(huì)討論如何確定你的對(duì)象的內(nèi)存使用量衰倦,以及如何通過(guò)改變數(shù)據(jù)結(jié)構(gòu)或是在序列化格式中進(jìn)行排序來(lái)對(duì)內(nèi)存使用進(jìn)行改進(jìn)袒炉。最后我們會(huì)討論Spark的內(nèi)存調(diào)優(yōu)和java的垃圾回收器。

2.1 內(nèi)存管理概述

Spark的內(nèi)存使用基本上可以分為兩大類(lèi):執(zhí)行內(nèi)存和存儲(chǔ)內(nèi)存樊零。執(zhí)行內(nèi)存指的是在shuffle我磁,join,和aggregation計(jì)算中使用的內(nèi)存驻襟,存儲(chǔ)內(nèi)存指的是集群中緩存和傳播內(nèi)部數(shù)據(jù)使用的內(nèi)存夺艰。在Spark中,執(zhí)行和存儲(chǔ)共享一個(gè)統(tǒng)一的區(qū)域M沉衣。當(dāng)沒(méi)有執(zhí)行內(nèi)存使用時(shí)郁副,存儲(chǔ)可以獲得全部的可用內(nèi)存,反之亦然豌习。執(zhí)行在必要的時(shí)候可能會(huì)驅(qū)逐內(nèi)存存谎,但只有在總存儲(chǔ)內(nèi)存使用量地域某個(gè)閾值R時(shí)才會(huì)觸發(fā)。用另一句話(huà)來(lái)說(shuō)肥隆,R描述在統(tǒng)一內(nèi)存M中一定不會(huì)被驅(qū)逐的緩存block子集既荚。由于實(shí)現(xiàn)的復(fù)雜性,存儲(chǔ)不會(huì)進(jìn)行內(nèi)存驅(qū)逐栋艳。

這種設(shè)計(jì)方案確保了幾個(gè)令人滿(mǎn)意的特性恰聘。首先,不使用緩存的應(yīng)用可以使用全部?jī)?nèi)存來(lái)用于執(zhí)行吸占,從而消除不必要的磁盤(pán)溢出晴叨。其次,使用緩存的應(yīng)用程序可以保留最小的不受驅(qū)逐的數(shù)據(jù)庫(kù)存儲(chǔ)空間R旬昭。最后篙螟,這種方法為各種工作負(fù)載提供了合理的開(kāi)箱即用性能,不需要用戶(hù)了解內(nèi)存如何內(nèi)部劃分的專(zhuān)門(mén)知識(shí)问拘。

盡管有兩個(gè)相關(guān)的配置,但是通常用戶(hù)不需要對(duì)它們進(jìn)行調(diào)整,因?yàn)槟J(rèn)值適用于大多數(shù)工作負(fù)載:

spark.memory.fraction 代表整體JVM堆內(nèi)存中M的百分比(默認(rèn)0.6)骤坐。剩余的空間(40%)是為用戶(hù)數(shù)據(jù)結(jié)構(gòu)绪杏、Spark內(nèi)部metadata預(yù)留的,并在稀疏使用和異常大記錄的情況下避免OOM錯(cuò)誤纽绍。

spark.memory.storageFraction 代表M中R的百分比(默認(rèn)0.5)蕾久。R是M中提供給緩存數(shù)據(jù)塊避免受到執(zhí)行驅(qū)逐的存儲(chǔ)空間。

spark.memory.fraction的值應(yīng)該設(shè)置為可以適配JVM的老年代或終身代的使用拌夏。具體可以參考下面的GC章節(jié)僧著。

2.2 內(nèi)存消耗確定

評(píng)估數(shù)據(jù)集所需的內(nèi)存消耗的最好方法是創(chuàng)建一個(gè)RDD,放到內(nèi)存里障簿,并且通過(guò)web UI來(lái)查看存儲(chǔ)使用量盹愚。這個(gè)頁(yè)面會(huì)告訴你這個(gè)RDD占用了多少內(nèi)存。

估算某一個(gè)特定對(duì)象的內(nèi)存消耗站故,可以使用SizeEstimator的estimate方法皆怕,這對(duì)于嘗試不同的數(shù)據(jù)布局來(lái)減少內(nèi)存使用,以及確定一個(gè)廣播變量將占用每個(gè)執(zhí)行器堆的空間量是很有用的西篓。

2.3 數(shù)據(jù)結(jié)構(gòu)調(diào)優(yōu)

減少內(nèi)存消耗的首選方法是避免使用會(huì)增加開(kāi)銷(xiāo)的java特性愈腾,例如基于指針的數(shù)據(jù)結(jié)構(gòu)和包裝器對(duì)象。下面是集中解決方法:

將數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)為更傾向于數(shù)組結(jié)構(gòu)和基本類(lèi)型岂津,而不是標(biāo)準(zhǔn)的Java或是Scala集合類(lèi)(例如. HashMap)虱黄。fastutil庫(kù)提供了與java標(biāo)準(zhǔn)庫(kù)兼容的原始類(lèi)型的集合。

盡可能避免包含需要小對(duì)象和指針的嵌套結(jié)構(gòu)

考慮使用數(shù)字ID或是枚舉對(duì)象而不是字符串key

如果你的RAM小于32GB吮成,設(shè)置JVM參數(shù) -XX:+UseCompressedOops 來(lái)讓指針變?yōu)?個(gè)字節(jié)而不是8個(gè)字節(jié)橱乱。可以將這個(gè)配置加載spark-env.sh中

2.4 序列化RDD存儲(chǔ)

當(dāng)盡管進(jìn)行了調(diào)優(yōu)赁豆,但你的對(duì)象仍然太大仅醇,無(wú)法有效存儲(chǔ)時(shí),一個(gè)更簡(jiǎn)單的方法是使用序列化的格式來(lái)存儲(chǔ)它們以此來(lái)減少內(nèi)存的使用魔种,使用RDD persistance API來(lái)設(shè)置序列化的存儲(chǔ)級(jí)別析二,例如MEMORY_ONLY_SER。Spark將RDD的每一個(gè)分區(qū)作為一個(gè)大的字節(jié)數(shù)組進(jìn)行存儲(chǔ)节预。以序列化格式存儲(chǔ)數(shù)據(jù)的唯一缺點(diǎn)是訪(fǎng)問(wèn)速度較慢叶摄,因?yàn)椴坏貌辉谑褂弥蟹葱蛄谢恳粋€(gè)對(duì)象。如果您想以序列化的形式緩存數(shù)據(jù)安拟,那么我們強(qiáng)烈建議使用Kryo蛤吓,因?yàn)樗菾ava序列化(當(dāng)然也要比原始Java對(duì)象)小得多。

2.5 垃圾回收調(diào)優(yōu)

當(dāng)你的程序中存儲(chǔ)的RDD有大量的替換和變更時(shí)糠赦,JVM垃圾回收可能會(huì)造成問(wèn)題会傲。它在只讀取一次RDD并在其上運(yùn)行許多操作的程序中通常不會(huì)造成問(wèn)題锅棕。當(dāng)Java需要將舊對(duì)象驅(qū)逐出去來(lái)為新對(duì)象騰出空間時(shí),它需要跟蹤所有的Java對(duì)象來(lái)找到未引用的對(duì)象淌山。這里需要記住的要點(diǎn)是裸燎,垃圾收集的成本與Java對(duì)象的數(shù)量成正比,因此使用較少對(duì)象的數(shù)據(jù)結(jié)構(gòu)(例如使用int的數(shù)組而不是LinkedList)會(huì)極大地減少消耗泼疑。一個(gè)更好的方法是以序列化的形式持久化對(duì)象德绿,如上所述:每個(gè)RDD的分區(qū)只會(huì)有一個(gè)對(duì)象(一個(gè)字節(jié)數(shù)組)。在嘗試其他技術(shù)之前退渗,首先要嘗試的是使用序列化的緩存移稳。

由于任務(wù)的工作內(nèi)存(運(yùn)行任務(wù)所需的空間量)和在節(jié)點(diǎn)上緩存的RDDs之間的干擾, GC也可能是一個(gè)問(wèn)題会油。我們將討論如何控制分配給RDD緩存的空間以減輕這個(gè)問(wèn)題个粱。

2.5.1 測(cè)量GC的影響

GC調(diào)優(yōu)的第一步是收集GC發(fā)生頻率和GC時(shí)間的統(tǒng)計(jì)〕ィ可以通過(guò)增加 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 的Java選項(xiàng)來(lái)實(shí)現(xiàn)几蜻。http://spark.apache.org/docs/latest/configuration.html#Dynamically-Loading-Spark-Properties中詳細(xì)描述了將Java參數(shù)傳遞給Spark Job的方法。下次Spark應(yīng)用程序運(yùn)行時(shí)体斩,就可以看到Woker節(jié)點(diǎn)的log會(huì)打印出GC信息梭稚。注意這些log是在集群中的workder節(jié)點(diǎn),而不是driver程序中絮吵。

2.5.2 GC調(diào)優(yōu)

為了進(jìn)一步優(yōu)化垃圾收集弧烤,我們首先需要了解JVM中關(guān)于內(nèi)存管理的一些基本信息:

Java對(duì)內(nèi)存被分為兩個(gè)區(qū)域,新生代和老年代蹬敲。新生代是為了保存壽命較短的對(duì)象暇昂,而老年代是為了保持壽命更長(zhǎng)的對(duì)象。

新生代被進(jìn)一步劃分為三個(gè)區(qū)域: Eden伴嗡,Survivor1急波,Survivor2
垃圾收集過(guò)程的簡(jiǎn)化描述:當(dāng)Eden區(qū)使用占滿(mǎn)時(shí),一個(gè)minor GC會(huì)在Eden中發(fā)生瘪校,仍然存活的對(duì)象會(huì)從Eden和Survivor1區(qū)域中復(fù)制到Survivor2澄暮。如果一個(gè)對(duì)象存活的時(shí)間夠久或是Survivor2區(qū)域空間占滿(mǎn)時(shí),它會(huì)移動(dòng)到老年代阱扬。最后當(dāng)老年空間接近占滿(mǎn)時(shí)泣懊,會(huì)觸發(fā)full GC。

Spark中的GC調(diào)優(yōu)的目的是為了確保只有長(zhǎng)期存在RDD會(huì)存儲(chǔ)在老年代中麻惶,新生代有足夠大的空間來(lái)存儲(chǔ)短期對(duì)象馍刮。這有助于在任務(wù)執(zhí)行期間避免收集臨時(shí)對(duì)象造成的full GC。下面是一些可用步驟:

通過(guò)收集GC狀態(tài)來(lái)檢查是否有太多GC窃蹋。如果在一個(gè)任務(wù)完成之前觸發(fā)了好幾次full GC卡啰,意味著任務(wù)執(zhí)行的可用內(nèi)存不足静稻。

如果有許多minor GC但是沒(méi)有太多major GC,可以為Eden分配更多內(nèi)存碎乃℃⑷樱可以通過(guò)估計(jì)任務(wù)的來(lái)村來(lái)設(shè)置Eden的大小惠奸。如果Eden的大小被設(shè)定為E梅誓,可以通過(guò)-Xmn=4/3*E來(lái)設(shè)置新生代的大小。(4 / 3的比例是為了Survivor使用的空間)
在打印出來(lái)的GC狀態(tài)中佛南,如果老年代接近占滿(mǎn)梗掰,可以通過(guò)減低spark.memory.fraction來(lái)減少用于緩存的內(nèi)存。緩存較少的隊(duì)相比減慢任務(wù)執(zhí)行速率要好嗅回。另外及穗,也可以考慮減少新生代的大小。這意味著降低-Xmn的設(shè)置绵载」÷剑或者嘗試獲取JVM的NewRatio參數(shù),許多JVM默認(rèn)設(shè)置為2娃豹,意味著老年代占據(jù)了2/3的堆內(nèi)存焚虱。它應(yīng)該足夠大,一直未這個(gè)比例超過(guò)了spark.memory.fraction懂版、
通過(guò)設(shè)置-XX:+UseG1GC來(lái)使用G1GC垃圾回收器鹃栽。在某些情況,垃圾收集是一個(gè)瓶頸躯畴,它可以提高性能民鼓。注意,在堆內(nèi)存夠大時(shí)蓬抄,需要通過(guò)-XX:G1HeapRegionSize來(lái)增大G1區(qū)域大小丰嘉。

如果你的任務(wù)是從HDFS中讀取數(shù)據(jù),可以使用從HDFS讀取的數(shù)據(jù)塊的大小來(lái)估計(jì)任務(wù)所使用的內(nèi)存數(shù)量嚷缭。注意饮亏,解壓縮塊的大小通常是塊大小的2-3倍,因此峭状,如果我們希望獲得3-4個(gè)任務(wù)空間克滴,而HDFS的塊大小是128MB,我們可以估計(jì)Eden的大小為43128MB优床。

更改設(shè)置后持續(xù)監(jiān)視GC的頻率和時(shí)間
我們的經(jīng)驗(yàn)表明劝赔,GC調(diào)優(yōu)的效果取決于您的應(yīng)用程序和可用內(nèi)存的數(shù)量。在網(wǎng)上有更多的調(diào)優(yōu)選項(xiàng)胆敞,管理頻繁的GC發(fā)生的頻率可以幫助減少開(kāi)銷(xiāo)着帽。
執(zhí)行器的GC調(diào)整標(biāo)志可以通過(guò)設(shè)置作業(yè)配置中的"spark.executor.extraJavaOptions"來(lái)指定杂伟。

三、其他

3.1 并行級(jí)別

除非每一個(gè)操作的并行度都設(shè)置的足夠高仍翰,要不然集群不會(huì)被充分利用赫粥。Spark自動(dòng)根據(jù)文件的大小設(shè)定了運(yùn)行在其上的map任務(wù)的數(shù)量(也可以通過(guò)SparkContext.textFile參數(shù)來(lái)控制),并且對(duì)于分布式的reduce操作予借,例如groupBykey和reduceByKey越平,它會(huì)使用父RDD中最大的分區(qū)數(shù)量。你可以將并行度作為一個(gè)次級(jí)參數(shù)床底灵迫,或是設(shè)置在配置文件spark.default.parallelism來(lái)改變默認(rèn)配置秦叛。通常情況下,我們推薦為集群中的每個(gè)CPU分配2-3個(gè)任務(wù)瀑粥。

3.2 Reduce任務(wù)的內(nèi)存使用

有些時(shí)候挣跋,你會(huì)因?yàn)閠ask中的數(shù)據(jù)集,例如groupByKey狞换,太大而造成OutOfMemoryError避咆,而不是RDD和內(nèi)存不匹配。Spark的shuffle操作(sortByKey修噪,groupByKey查库,reduceByKey,join等等)會(huì)在每個(gè)任務(wù)中創(chuàng)建一個(gè)hash table來(lái)執(zhí)行g(shù)rouping操作割按,這個(gè)操作經(jīng)常會(huì)很大膨报。最簡(jiǎn)單的處理方案是增加并行度,讓每個(gè)任務(wù)獲取到的數(shù)據(jù)集更小适荣。Spark對(duì)于短于200ms的任務(wù)執(zhí)行的很好现柠,因?yàn)樗诙鄠€(gè)任務(wù)中重用一個(gè)executor JVM,任務(wù)的啟動(dòng)成本很低弛矛,因此够吩,你可以安全地將并行級(jí)別增加到您的集群中的核心數(shù)量。

3.3 廣播大變量

使用SparkContext中的廣播特性丈氓,你可以極大地減少序列化任務(wù)的大小周循,和集群中的啟動(dòng)任務(wù)開(kāi)銷(xiāo)。如果你的任務(wù)用到了driver中的一個(gè)大的對(duì)象(例如一個(gè)static lookup table)万俗,可以考慮將它變?yōu)閺V播變量湾笛。Spark將每個(gè)任務(wù)的序列化大小打印在主服務(wù)器上,因此您可以查看它來(lái)決定您的任務(wù)是否太大;一般來(lái)說(shuō)闰歪,大于20kb的任務(wù)很可能是值得優(yōu)化的

3.4 數(shù)據(jù)本地性

數(shù)據(jù)本地性對(duì)于Spark任務(wù)的性能有很大的影響嚎研。如果數(shù)據(jù)和操作的代碼在一起,那么計(jì)算往往很快库倘。但是由于代碼和數(shù)據(jù)是分離開(kāi)的临扮,它們中總會(huì)有一方要向另一方傳遞论矾。通常,將序列化的代碼從一個(gè)地方發(fā)送到另一個(gè)地方比傳輸數(shù)據(jù)塊要快杆勇,因?yàn)榇a的大小比數(shù)據(jù)要小得多贪壳。Spark構(gòu)建了它圍繞數(shù)據(jù)局部性原則的調(diào)度。

數(shù)據(jù)本地性是數(shù)據(jù)和處理它的代碼之間的距離蚜退。下面有基于數(shù)據(jù)當(dāng)前維值的幾種本地性設(shè)置闰靴。通過(guò)選取最短距離來(lái)達(dá)成最快的處理速度:

PROCESS_LOCAL 數(shù)據(jù)在運(yùn)行代碼的同一個(gè)JVM中。這是最優(yōu)選擇

NODE_LOCAL 數(shù)據(jù)在同一個(gè)節(jié)點(diǎn)上关霸。例如可能在同一個(gè)節(jié)點(diǎn)上的HDFS上传黄,或是在同一個(gè)節(jié)點(diǎn)上的另一個(gè)處理器中。這比PROCESS_LOCAL稍微慢一點(diǎn)队寇,因?yàn)檫@涉及到進(jìn)程間的數(shù)據(jù)通信

NO_PREF 數(shù)據(jù)可以從任何地方同樣快速地訪(fǎng)問(wèn),并且沒(méi)有本地偏好

RACK_LOCAL 數(shù)據(jù)位于相同的服務(wù)器機(jī)架上章姓。數(shù)據(jù)在同一個(gè)機(jī)架上的另一臺(tái)服務(wù)器上佳遣,所以需要通過(guò)網(wǎng)絡(luò)發(fā)送,通常需要通過(guò)一個(gè)網(wǎng)關(guān)

ANY 數(shù)據(jù)是在網(wǎng)絡(luò)上的其他地方凡伊,而不是在同一個(gè)機(jī)架上

Spark希望把所有的任務(wù)都安排在最合適的位置上零渐,但這并不會(huì)總是可行的。在沒(méi)有任何空閑執(zhí)行機(jī)的情況下系忙,Spark會(huì)切換到較低的局部性诵盼。有兩種選擇:a. 在同一個(gè)服務(wù)器上等待CPU空閑,再提交任務(wù) b. 立即在一個(gè)其他執(zhí)行機(jī)上開(kāi)始執(zhí)行任務(wù)银还,并將數(shù)據(jù)移動(dòng)過(guò)去

Spark通常情況下會(huì)等待CPU空閑风宁。一旦等待時(shí)間超時(shí),它會(huì)開(kāi)始移動(dòng)數(shù)據(jù)到較遠(yuǎn)的空閑CPU上蛹疯。每個(gè)級(jí)別之間的等待超時(shí)可以單獨(dú)配置戒财,也可以在一個(gè)參數(shù)中組合在一起。具體配置參考spark.locality捺弦。默認(rèn)配置通常效果較好饮寞,可以根據(jù)任務(wù)特性來(lái)修改這些配置。

四列吼、總結(jié)

本文是針對(duì)Spark應(yīng)用程序調(diào)優(yōu)中需要注意的主要問(wèn)題的一個(gè)簡(jiǎn)單指南幽崩,主要關(guān)注數(shù)據(jù)序列化和內(nèi)存調(diào)優(yōu)。對(duì)大多數(shù)應(yīng)用來(lái)說(shuō)寞钥,切換到Kryo序列化并persist序列化數(shù)據(jù)可以解決大多數(shù)性能問(wèn)題慌申。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市凑耻,隨后出現(xiàn)的幾起案子太示,更是在濱河造成了極大的恐慌柠贤,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件类缤,死亡現(xiàn)場(chǎng)離奇詭異臼勉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)餐弱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)宴霸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人膏蚓,你說(shuō)我怎么就攤上這事瓢谢。” “怎么了驮瞧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵氓扛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我论笔,道長(zhǎng)采郎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任狂魔,我火速辦了婚禮蒜埋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘最楷。我一直安慰自己整份,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布籽孙。 她就那樣靜靜地躺著烈评,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚯撩。 梳的紋絲不亂的頭發(fā)上础倍,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音胎挎,去河邊找鬼沟启。 笑死,一個(gè)胖子當(dāng)著我的面吹牛犹菇,可吹牛的內(nèi)容都是我干的德迹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼揭芍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼胳搞!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肌毅,失蹤者是張志新(化名)和其女友劉穎筷转,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體悬而,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呜舒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了笨奠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袭蝗。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖般婆,靈堂內(nèi)的尸體忽然破棺而出到腥,到底是詐尸還是另有隱情,我是刑警寧澤蔚袍,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布乡范,位于F島的核電站,受9級(jí)特大地震影響页响,放射性物質(zhì)發(fā)生泄漏创译。R本人自食惡果不足惜褐奴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望懂从。 院中可真熱鬧连舍,春花似錦没陡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至潜腻,卻和暖如春埃儿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背融涣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工童番, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人威鹿。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓剃斧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親忽你。 傳聞我的和親對(duì)象是個(gè)殘疾皇子幼东,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345