<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一次JVM GC引發(fā)的Spark調(diào)優(yōu)大全(建議收藏)

          共 14534字,需瀏覽 30分鐘

           ·

          2020-11-27 15:36

          一般在我們開發(fā)spark程序的時候,從代碼開發(fā)到上線以及后期的維護(hù)中,在整個過程中都需要涉及到調(diào)優(yōu)的問題,即一開始需要考慮如何把代碼寫的更簡潔高效調(diào)優(yōu)(即代碼優(yōu)化),待開發(fā)測試完成后,提交任務(wù)時綜合考量該任務(wù)所需的資源(這里涉及到資源調(diào)優(yōu)),上線后是否會出現(xiàn)數(shù)據(jù)傾斜問題(即傾斜調(diào)優(yōu)),以及是否出現(xiàn)頻繁GC問題(這里涉及到GC調(diào)優(yōu))。

          那么本篇通過反推的模式,即通過GC調(diào)優(yōu)進(jìn)行延伸擴(kuò)展,比如出現(xiàn)GC問題是不是可能出現(xiàn)了傾斜?如果沒有出現(xiàn)傾斜,是不是我們給的資源不足?如果資源充足的話,那么是不是我們代碼寫的有問題呢(比如頻繁創(chuàng)建對象等操作)?按照這樣一個思路展開來總結(jié)spark的調(diào)優(yōu)。

          JVM的堆、棧、方法區(qū)

          如上圖所示,JVM主要由類加載器系統(tǒng)、運(yùn)行時數(shù)據(jù)區(qū)、執(zhí)行引擎和本地接口等組成。

          其中運(yùn)行時數(shù)據(jù)區(qū)又由方法區(qū)、堆、Java棧、PC寄存器、本地方法棧組成。

          當(dāng)JVM加載一個class文件后,class中的參數(shù)、類型等信息會存儲到方法區(qū)中,程序運(yùn)行時所創(chuàng)建的對象存儲在堆中(堆中不放基本類型和對象引用,只存放對象本身)。當(dāng)每個新線程啟動時,會有自己的程序計數(shù)器(Program Counter Register)和棧,當(dāng)線程調(diào)用方法時,程序計數(shù)器表明下一條執(zhí)行的指令,同時線程棧會存儲線程的方法調(diào)用狀態(tài)(包括局部變量、被調(diào)用的參數(shù)、中間結(jié)果等)。本地方法調(diào)用存儲在獨立的本地方法棧中,或其他獨立的內(nèi)存區(qū)域中。

          棧區(qū)由棧楨組成,每個棧楨就是每個調(diào)用的方法的棧,當(dāng)方法調(diào)用結(jié)束后,JVM會彈棧,即拋棄此方法的棧楨。

          JVM內(nèi)存劃分

          上圖中的劃分是基于JDK7和JDK8,其中有一些變動(主要是永久代的移除)。

          JVM內(nèi)存從大體上劃分為三部分:年輕代、老年代、永久代(元空間)

          年輕代:所有新生成的對象都會先放到年輕代,年輕代又分為三個區(qū):Eden區(qū)、兩個Survivor,三者之間的比例為8:1:1。

          ??Eden區(qū):大部分對象會在該區(qū)生成,當(dāng)在Eden區(qū)申請空間失敗后,會觸發(fā)Scavenge GC,對Eden區(qū)進(jìn)行GC,清除非存活對象,并把還存活的對象復(fù)制到其中一個Survivor區(qū)中。這里可能會有一個問題,由于默認(rèn)情況下Eden:Survivor1:Survivor2的內(nèi)存占比是8:1:1,如果存活下來的對象是1.5,一個Survivor區(qū)域放不下,那么這個時候就會利用JVM的擔(dān)保機(jī)制,將多余的對象直接放入老年代,會出現(xiàn)老年代囤積一大堆短生命周期的,導(dǎo)致老年代頻繁溢滿,頻繁進(jìn)行Full GC去回收老年代中的對象

          ??Survivor區(qū):當(dāng)Eden區(qū)滿后,會把還存活的對象復(fù)制到其中一個S區(qū)中,且兩個S區(qū)之間沒有先后順序關(guān)系,同時根據(jù)程序需要Survivor區(qū)是可以配置多個的,這樣可以增加對象在年輕代存在的時間,減少被放到老年代的可能。JVM每次只會使用Eden和其中一塊Survivor區(qū)域來為對象服務(wù),所以無論什么時候總會有一塊Survivor區(qū)域是空閑的,也就是說年輕代實際可用的內(nèi)存空間為9/10的年輕代空間。

          老年代:在年輕代中經(jīng)歷了N次GC之后仍然存活的對象,就會被放到老年代中。該區(qū)域通常存放一些生命周期較長的對象。默認(rèn)情況下,年輕代和老年代的比值為1:2,即老年代占用堆空間大小的2/3,當(dāng)然這個值可以通過-XX:NewRation來調(diào)整

          持久代:主要存放靜態(tài)文件、Java類、方法等。在Java 8中該區(qū)域已經(jīng)被移除了,開始使用本地化的內(nèi)存來存放類的元數(shù)據(jù),也稱之元空間

          JVM GC

          JVM主要管理兩種類型的內(nèi)存:堆和非堆,簡單來說,堆就是Java代碼可及的內(nèi)存,是留給開發(fā)人員用的,非堆就是JVM留給自己用的。

          對于Java的內(nèi)存管理來說其實就是對象的管理,包括對象的分配和釋放。對于GC來說,當(dāng)我們創(chuàng)建對象的時候,GC就開始監(jiān)控這個對象地址、大小以及使用情況,通常GC采用有向圖的方式記錄管理堆中所有對象,通過這種方式來確定哪些對象是可達(dá)的,哪些對象是不可達(dá)的。具體的GC流程如下:

          1. 當(dāng)Eden滿了之后,一個小型的GC就會被觸發(fā)(Minor GC),Eden和Survivor1中幸存仍被使用的對象被復(fù)制到Survivor2。
          2. Survivor1和Survivor2區(qū)域進(jìn)行交換,當(dāng)一個對象生存的時間足夠長或者Survivor2滿了之后,就會被轉(zhuǎn)移到Old代
          3. 當(dāng)Old空間快滿的時候,這個時候會進(jìn)行Full GC

          一般以下幾種情況可能會導(dǎo)致Full GC:

          1. 當(dāng)Old空間被寫滿時
          2. System.GC()被顯式調(diào)用
          3. 上一次GC之后,Heap的各個區(qū)域分配策略動態(tài)變化

          以上簡單說明一下jvm相關(guān)知識點,其實spark GC的目的就是要確保老年代只保存長生命周期RDD,同時年輕代的空間又能夠保存短生命周期的對象,這樣就能避免啟動Full GC

          Spark對JVM的使用

          基于上篇Tungsten on spark 文章的整理,Executor對內(nèi)存的使用主要有以下幾個部分:

          1. RDD存儲。當(dāng)對RDD調(diào)用persist或Cache方法時,RDD的partitons會被存儲到內(nèi)存里,那么這塊內(nèi)存也就是Storage內(nèi)存。
          2. Shuffle操作。當(dāng)發(fā)生Shuffle時,需要緩沖區(qū)來存儲Shuffle的輸出和聚合的中間結(jié)果,該塊內(nèi)存稱之為Execution內(nèi)存。
          3. 用戶代碼。用戶編寫的代碼能夠使用的內(nèi)存空間,也就是其他內(nèi)存(用戶內(nèi)存)

          在統(tǒng)一內(nèi)存模式下,整個堆空間分為Spark Memory和User Memory,其中Spark Memory包括Storage Memory和Execution Memory,而且兩者之間可以互相借用空間。

          通過spark.memory.fraction參數(shù)來控制Spark Memory在整個堆空間所占的比例

          通過spark.memory.storageFraction來設(shè)置Storage Memory占Spark Memory的比例,如果Spark作業(yè)中有較多的RDD持久化操作,該參數(shù)值可以適當(dāng)調(diào)高,保證持久化的數(shù)據(jù)能夠容納在內(nèi)存中,避免內(nèi)存不夠緩存所有的數(shù)據(jù),只能寫入磁盤中,降低性能。如果Spark作業(yè)中Shuffle類操作比較多,持久化類操作比較少,那么可以適當(dāng)降低該參數(shù)值。

          這里給出一個實際的例子來說明一下spark是如何分配內(nèi)存的

          /usr/local/spark-current/bin/spark-submit?\
          --master?yarn?\
          --deploy-mode?client?\
          --executor-memory?1G?\
          --queue?root.default?\
          --class?my.Application?\
          --conf?spark.ui.port=4052?\
          --conf?spark.port.maxRetries=100?\
          --num-executors?2?\
          --jars?mongo-spark-connector_2.11-2.3.1.jar?\
          App.jar?20201118000000

          #
          ?這里配置兩個Executor,每個Executor內(nèi)存給1G

          如圖所示,spark申請到了兩個Executor,每個Executor得到的Storage Memory內(nèi)存分別為384.1MB(注意:這里Storage Memory其實就是Storage+Execution的總和內(nèi)存),這里有一個疑惑,我們分配的是每個Executor內(nèi)存為1G,為什么只得到384MB呢?這里給出具體的計算公式:

          1. 我們申請為1G內(nèi)存,但是真正拿到內(nèi)存會比這個少,這里涉及到一個Runtime.getRuntime.maxMemory 值的計算(在上篇文章中關(guān)于UnifiedMemoryManager源碼分析中提到過),Runtime.getRuntime.maxMemory對應(yīng)的值才是程序能夠使用的最大內(nèi)存,上面也提到了堆劃分了Eden,Survivor,Tenured區(qū)域,所以該值計算公式為:

            ExecutorMemory = ?Eden + 2 * Survivor + Tenured = 1GB ?= 1073741824 字節(jié)

            systemMemory = Runtime.getRuntime.maxMemory ?= Eden + Survivor + Tenured = 954437176.888888888888889 字節(jié)

            //org.apache.spark.memory.UnifiedMemoryManager(這里討論的還是動態(tài)內(nèi)存模型)
            private?def?getMaxMemory(conf:?SparkConf):?Long?=?{
            ??val?systemMemory?=?conf.getLong("spark.testing.memory",?Runtime.getRuntime.maxMemory)
            ??val?reservedMemory?=?conf.getLong("spark.testing.reservedMemory",
            ????????if?(conf.contains("spark.testing"))?0?else?RESERVED_SYSTEM_MEMORY_BYTES)
            ??val?usableMemory?=?systemMemory?-?reservedMemory
            ??val?memoryFraction?=?conf.getDouble("spark.memory.fraction",?0.6)
            ??
            ??//這里即獲取最大的內(nèi)存值
            ??(usableMemory?*?memoryFraction).toLong
            }
          2. 基于Spark的動態(tài)內(nèi)存模型設(shè)計,其中有300MB的預(yù)留內(nèi)存,因此剩余可用內(nèi)存為總申請得到的內(nèi)存-預(yù)留內(nèi)存

            reservedMemory = 300MB = 314572800字節(jié)

            usableMemory = systemMemory - reservedMemory = 954437176.888888888888889 - ?314572800 = 639864376.888888888888889字節(jié)

          3. Spark Web UI界面上雖然顯示的是Storage Memory,但其實是Execution+Storage內(nèi)存,即該部分占用60%比例

            Storage + Execution = usableMemory * 0.6 = 639864376.888888888888889 * 0.6 = 383918626.133333333333333 字節(jié)

          4. 通過第三步驟即可看出實際的內(nèi)存分配情況了,注意:web ui界面得到的結(jié)果計算是除于1000轉(zhuǎn)換得到的值。

          GC調(diào)優(yōu)步驟

          1. 統(tǒng)計一下GC啟動的頻率和GC使用的總時間,即在spark-submit提交的時候設(shè)置參數(shù)即可如圖所示,這里提高了spark.memory.fraction參數(shù)值,則每個Exectuor實際可用的內(nèi)存也隨之增加了.

            /usr/local/spark-current/bin/spark-submit?\
            --master?yarn?\
            --deploy-mode?client?\
            --executor-memory?1G?\
            --driver-memory?1G?\
            --queue?root.default?\
            --class?my.Application?\
            --conf?spark.ui.port=4052?\
            --conf?spark.port.maxRetries=100?\
            --num-executors?2?\
            --jars?mongo-spark-connector_2.11-2.3.1.jar?\
            --conf?"spark.executor.extraJavaOptions=-XX:+PrintGCDetails?-XX:+PrintGCTimeStamps"?\
            --conf?spark.memory.fraction=0.8?\
            App.jar

          如圖所示,出現(xiàn)了多次Full GC,首先考慮的是可能配置的Executor內(nèi)存較低,這個時候需要增加Executor Memory來調(diào)節(jié)。

          1. 檢查GC日志中是否有過于頻繁的GC。如果一個任務(wù)結(jié)束前,F(xiàn)ull GC執(zhí)行多次,說明老年代空間被占滿了,那么有可能是沒有分配足夠的內(nèi)存。

            1.調(diào)整executor的內(nèi)存,配置參數(shù)executor-memory
            2.調(diào)整老年代所占比例:配置-XX:NewRatio的比例值
            3.降低spark.memory.storageFraction減少用于緩存的空間
          2. 如果有太多Minor GC,但是Full GC不多,可以給Eden分配更多的內(nèi)存.

            1.比如Eden代的內(nèi)存需求量為E,可以設(shè)置Young代的內(nèi)存為-Xmn=4/3*E,設(shè)置該值也會導(dǎo)致Survivor區(qū)域擴(kuò)張
            2.調(diào)整Eden在年輕代所占的比例,配置-XX:SurvivorRatio的比例值
          3. 調(diào)整垃圾回收器,通常使用G1GC,即配置-XX:+UseG1GC。當(dāng)Executor的堆空間比較大時,可以提升G1 region size(-XX:G1HeapRegionSize)

            /usr/local/spark-current/bin/spark-submit?\
            --master?yarn?\
            --deploy-mode?client?\
            --executor-memory?1G?\
            --driver-memory?1G?\
            --queue?root.default?\
            --class?my.Application?\
            --conf?spark.ui.port=4052?\
            --conf?spark.port.maxRetries=100?\
            --num-executors?2?\
            --jars?mongo-spark-connector_2.11-2.3.1.jar?\
            --conf?"spark.executor.extraJavaOptions=-XX:+UseG1GC?-XX:G1HeapRegionSize=16M?-XX:+PrintGCDetails?-XX:+PrintGCTimeStamps"?\
            --conf?spark.memory.fraction=0.8?\
            App.jar
          4. 優(yōu)化代碼,盡量多使用array和string,并使用kyro序列,讓每個Partition都成為字節(jié)數(shù)組

          5. 結(jié)合實際的需求,調(diào)整緩存和shuffle計算所占的內(nèi)存比例,即當(dāng)代碼中出現(xiàn)shuffle類操作比較多,而不需要太多緩存的話,則可以適當(dāng)降低Storage Memory所占比例;當(dāng)緩存操作比較多,而Shuffle類操作比較少的話,可以適當(dāng)調(diào)低Execution Memory所占比例。主要是通過spark.storage.storageFraction來控制

          6. 開啟堆外內(nèi)存,設(shè)置堆外內(nèi)存大小,這里為了避免OOM

            spark.memory.offHeap.size=4G
            spark.memory.offHeap.enabled=true

          注意:這里需要說明一下spark.executor.memoryOverhead 和spark.memory.offHeap.size之間的區(qū)別

          spark.executor.memoryOverhead是屬于JVM堆外內(nèi)存,用于JVM自身的開銷、內(nèi)部的字符串還有一些本地開銷,spark不會對這塊內(nèi)存進(jìn)行管理。默認(rèn)大小為ExecutorMemory的10%,在spark2.4.5之前,該參數(shù)的值應(yīng)該包含spark.memory.offHeap.size的值。比如spark.memory.offHeap.size配置500M,spark.executor.memoryOverhead默認(rèn)為384M,那么memoryOverhead的值應(yīng)該為884M。

          //spark2.4.5之前的
          //?Executor?memory?in?MB.
          protected?val?executorMemory?=?sparkConf.get(EXECUTOR_MEMORY).toInt

          //?Additional?memory?overhead.
          protected?val?memoryOverhead:?Int?=?sparkConf.get(EXECUTOR_MEMORY_OVERHEAD).getOrElse(
          ??math.max((MEMORY_OVERHEAD_FACTOR?*?executorMemory).toInt,?MEMORY_OVERHEAD_MIN)).toInt
          protected?val?pysparkWorkerMemory:?Int?=?if?(sparkConf.get(IS_PYTHON_APP))?{
          ??sparkConf.get(PYSPARK_EXECUTOR_MEMORY).map(_.toInt).getOrElse(0)
          }?else?{
          ??0
          }

          //?Resource?capability?requested?for?each?executors
          private[yarn]?val?resource?=?Resource.newInstance(
          ??executorMemory?+?memoryOverhead?+?pysparkWorkerMemory,
          ??executorCores)

          //由于memoryOverHead的參數(shù)值理解起來比較困難,而且不易于用戶對每個特定的內(nèi)存區(qū)域進(jìn)行自定義配置,所以在Spark3.0之后進(jìn)行了拆分
          //spark3.0之后的資源申請更改為
          private[yarn]?val?resource:?Resource?=?{
          ????val?resource?=?Resource.newInstance(
          ??????executorMemory?+?executorOffHeapMemory?+?memoryOverhead?+?pysparkWorkerMemory,?executorCores)
          ????ResourceRequestHelper.setResourceRequests(executorResourceRequests,?resource)
          ????logDebug(s"Created?resource?capability:?$resource")
          ????resource
          ??}

          spark.memory.offHeap.size這個參數(shù)指定的內(nèi)存(廣義上是指所有堆外的),這部分內(nèi)存的申請和釋放是直接進(jìn)行的,不由JVM管理,所以這塊是沒有GC的。

          傾斜調(diào)優(yōu)

          傾斜部分的調(diào)優(yōu)可以閱讀下面兩篇文章,相對來說已經(jīng)比較全了

          Spark數(shù)據(jù)傾斜之騷操作解決方案

          數(shù)據(jù)開發(fā)必經(jīng)之路-數(shù)據(jù)傾斜

          開發(fā)調(diào)優(yōu)

          相信有很多讀者應(yīng)該非常熟悉以下這幾種使用姿勢了,這里就不再重復(fù)詳細(xì)說明了

          1. 避免創(chuàng)建重復(fù)的RDD

          2. 盡可能復(fù)用同一個RDD

          3. 對多次使用的RDD進(jìn)行持久化

          4. 盡量避免使用Shuffle算子

          5. 使用map-side預(yù)聚合的shuffle操作

          6. 使用高性能的算子

            6.1: 使用reduceByKey/aggregateByKey替代groupByKey

            6.2: 使用mapPartitions替代普通map

            6.3: 使用foreachPartitions替代foreach

            6.4: 使用filter之后進(jìn)行coalesce操作

            6.5: 使用repartitionAndSortWithinPartitions替代repartition與sort類操作

          7. 廣播大變量

            val?list1?=?...
            val?list1Broadcast?=?sc.broadcast(list1)
            rdd1.map(list1Broadcast...)
          8. 使用kryo優(yōu)化序列化性能

            //?創(chuàng)建SparkConf對象
            conf.set("spark.serializer",?"org.apache.spark.serializer.KryoSerializer")

            //?設(shè)置序列化器為KryoSerializer。
            conf.set("spark.serializer",?"org.apache.spark.serializer.KryoSerializer")

            //?注冊要序列化的自定義類型。
            conf.registerKryoClasses(Array(classOf[MyClass1],?classOf[MyClass2]))
          9. 優(yōu)化數(shù)據(jù)結(jié)構(gòu),盡量使用字符串代替對象,使用原始類型(如int,Long)代替字符串,使用數(shù)組代替集合類型

          資源參數(shù)調(diào)優(yōu)

          眾所周知,引起GC主要是內(nèi)存資源問題,一般情況下是不需要對GC進(jìn)行調(diào)優(yōu)的。當(dāng)出現(xiàn)GC問題時,那么就需要思考是哪個環(huán)節(jié)造成內(nèi)存緊張。首先想到的應(yīng)該是配置的內(nèi)存不足,直接加資源,這里整理了一些配置參數(shù),僅供讀者參考。

          應(yīng)用行為屬性名默認(rèn)值屬性描述生效版本
          driver行為spark.driver.cores1driver程序運(yùn)行需要的cpu內(nèi)核數(shù)1.3.0
          driver行為spark.driver.maxResultSize1G每個Spark action(如collect)所有分區(qū)的序列化結(jié)果的總大小限制。設(shè)置的值應(yīng)該不小于1m,0代表沒有限制。如果總大小超過這個限制,程序?qū)K止。大的限制值可能導(dǎo)致driver出現(xiàn)內(nèi)存溢出錯誤(依賴于spark.driver.memory和JVM中對象的內(nèi)存消耗)1.2.0
          driver行為spark.driver.memory1Gdriver進(jìn)程使用的內(nèi)存數(shù)1.1.1
          driver行為spark.driver.memoryOverheaddriverMemory * 0.10,with minimum of 384driver端分配的堆外內(nèi)存2.3.0
          driver行為spark.driver.extraClassPathNone附加到driver的classpath的額外的classpath實體1.0.0
          driver行為spark.driver.defaultJavaOptionsNone默認(rèn)傳遞給driver的JVM選項字符串。注意這個配置不能直接在代碼中使用SparkConf來設(shè)置,因為這個時候driver JVM已經(jīng)啟動了,可以在命令行通過--driver-java-options參數(shù)來設(shè)置3.0.0
          driver行為spark.driver.extraJavaOptionsNone傳遞給driver的JVM選項字符串。例如GC設(shè)置或者其它日志設(shè)置。注意,在這個選項中設(shè)置Spark屬性或者堆大小是不合法的。Spark屬性需要用--driver-class-path設(shè)置1.0.0
          driver行為spark.driver.extraLibraryPathNone指定啟動driver的JVM時用到的庫路徑1.0.0
          driver行為spark.driver.userClassPathFirstfalse當(dāng)在driver中加載類時,是否用戶添加的jar比Spark自己的jar優(yōu)先級高。這個屬性可以降低Spark依賴和用戶依賴的沖突,現(xiàn)在還是一個實驗性的特征1.3.0
          executor行為spark.executor.memory1G每個executor進(jìn)程使用的內(nèi)存數(shù)0.7.0
          executor行為spark.executor.memoryOverheadexecutorMemory * 0.10, with minimum of 384Executor JVM堆外內(nèi)存設(shè)置,用于解決JVM開銷,內(nèi)部字符串,其他本機(jī)開銷等問題2.3.0
          executor行為spark.executor.extraClassPathNone附加到executors的classpath的額外的classpath實體。這個設(shè)置存在的主要目的是Spark與舊版本的向后兼容問題。用戶一般不用設(shè)置這個選項1.0.0
          executor行為spark.executor.defaultJavaOptionsNone默認(rèn)的JVM選項,以附加到spark.executor.extraJavaOptions3.0.0
          executor行為spark.executor.extraJavaOptionsNone傳遞給executors的JVM選項字符串。例如GC設(shè)置或者其它日志設(shè)置。注意,在這個選項中設(shè)置Spark屬性或者堆大小是不合法的。Spark屬性需要用SparkConf對象或者spark-submit腳本用到的spark-defaults.conf文件設(shè)置。堆內(nèi)存可以通過spark.executor.memory設(shè)置1.0.0
          executor行為spark.executor.extraLibraryPathNone指定啟動executor的JVM時用到的庫路徑1.0.0
          executor行為spark.executor.userClassPathFirstfalse(實驗性)與spark.driver.userClassPathFirst相同的功能,但應(yīng)用于執(zhí)行程序?qū)嵗?1.3.0
          executor行為spark.executor.cores1每個executor使用的核數(shù)1.0.0
          executor行為spark.default.parallelism本地模式:機(jī)器核數(shù);Mesos:8;其他:max(executor的core,2)默認(rèn)并行度0.5.0
          shuffle行為spark.reducer.maxSizeInFlight48m從每個reduce中獲取的最大容量,該參數(shù)值如果過低時,會導(dǎo)致Shuffle過程中產(chǎn)生的數(shù)據(jù)溢出到磁盤1.4.0
          shuffle行為spark.reducer.maxReqsInFlightInt.MaxValue此配置限制了獲取塊的遠(yuǎn)程請求的數(shù)量2.0.0
          shuffle行為spark.reducer.maxBlocksInFlightPerAddressInt.MaxValue該配置限制了reduce任務(wù)從其他機(jī)器獲取遠(yuǎn)程塊的數(shù)量2.2.1
          shuffle行為spark.shuffle.compresstrue是否壓縮map操作的輸出文件0.6.0
          shuffle行為spark.shuffle.file.buffer32k每個shuffle文件輸出緩存的大小1.4.0
          shuffle行為spark.shuffle.io.maxRetries3(Netty only)自動重試次數(shù)1.2.0
          shuffle行為spark.shuffle.io.numConnectionsPerPeer1(Netty only)機(jī)器之間的連接復(fù)用1.2.1
          shuffle行為spark.shuffle.io.preferDirectBufstrue(Netty only)直接堆外內(nèi)存,用于減少隨機(jī)和高速緩存塊傳輸期間的GC1.2.0
          shuffle行為spark.shuffle.io.retryWait5s(Netty only)重試提取之間要等待多長時間;默認(rèn)情況下重試導(dǎo)致的最大延遲為15s1.2.1
          shuffle行為spark.shuffle.service.enabledfalse啟用外部shuffle服務(wù)1.2.0
          shuffle行為spark.shuffle.service.index.cache.size100m緩存條目限制為指定的內(nèi)存占用,以字節(jié)為單位2.3.0
          shuffle行為spark.shuffle.sort.bypassMergeThreshold200如果shuffle map task的數(shù)量小于這個閥值200,且不是聚合類的shuffle算子(比如reduceByKey),則不會進(jìn)行排序1.1.1
          shuffle行為spark.shuffle.spill.compresstrue在shuffle時,是否將spilling的數(shù)據(jù)壓縮。壓縮算法通過spark.io.compression.codec指定0.9.0
          shuffle行為spark.shuffle.accurateBlockThreshold100 * 1024 * 1024高于該閾值時,HighlyCompressedMapStatus中的混洗塊的大小將被準(zhǔn)確記錄。通過避免在獲取隨機(jī)塊時低估隨機(jī)塊的大小,有助于防止OOM2.2.1
          shuffle行為spark.shuffle.registration.timeout5000注冊到外部shuffle服務(wù)的超時時間2.3.0
          shuffle行為spark.shuffle.registration.maxAttempts3注冊到外部shuffle服務(wù)的重試次數(shù)2.3.0
          壓縮序列化spark.broadcast.compresstrue是否壓縮廣播變量0.6.0
          壓縮序列化spark.checkpoint.compressfalse是否開啟RDD壓縮checkpoint2.2.0
          壓縮序列化spark.io.compression.codeclz4RDD壓縮方式org.apache.spark.io.LZ4CompressionCodec, org.apache.spark.io.LZFCompressionCodec, org.apache.spark.io.SnappyCompressionCodec, and org.apache.spark.io.ZStdCompressionCodec.0.8.0
          壓縮序列化spark.io.compression.lz4.blockSize32kLZ4壓縮中使用的塊大小1.4.0
          壓縮序列化spark.io.compression.snappy.blockSize32kSnappy壓縮中使用的塊大小1.4.0
          壓縮序列化spark.kryo.classesToRegisterNone如果你用Kryo序列化,給定的用逗號分隔的自定義類名列表表示要注冊的類1.2.0
          壓縮序列化spark.kryo.registratorNone如果你用Kryo序列化,設(shè)置這個類去注冊你的自定義類。如果你需要用自定義的方式注冊你的類,那么這個屬性是有用的。否則spark.kryo.classesToRegister會更簡單。它應(yīng)該設(shè)置一個繼承自KryoRegistrator的類0.5.0
          壓縮序列化spark.kryo.registrationRequiredfalse是否需要注冊為Kyro可用1.1.0
          壓縮序列化spark.kryoserializer.buffer.max64mKryo序列化緩存允許的最大值1.4.0
          壓縮序列化spark.kryoserializer.buffer64kKyro序列化緩存的大小1.4.0
          壓縮序列化spark.rdd.compressFalse是否壓縮序列化的RDD分區(qū)0.6.0
          壓縮序列化spark.serializerorg.apache.spark.serializer.
          JavaSerializer
          序列化對象使用的類0.5.0
          壓縮序列化spark.serializer.objectStreamReset100當(dāng)用org.apache.spark.serializer.JavaSerializer序列化時,序列化器通過緩存對象防止寫多余的數(shù)據(jù),然而這會造成這些對象的垃圾回收停止。通過請求’reset’,你從序列化器中flush這些信息并允許收集老的數(shù)據(jù)。為了關(guān)閉這個周期性的reset,你可以將值設(shè)為-1。默認(rèn)情況下,每一百個對象reset一次1.0.0
          動態(tài)分配spark.dynamicAllocation.enabledfalse是否開啟動態(tài)分配1.2.0
          動態(tài)分配spark.dynamicAllocation.executorIdleTimeout60s當(dāng)某個executor空間超過該值時,則會remove掉該executor1.2.0
          動態(tài)分配spark.dynamicAllocation.cachedExecutorIdleTimeoutinfinity當(dāng)executor內(nèi)有緩存數(shù)據(jù)并且空閑了該值后,則remove掉該executor1.4.0
          動態(tài)分配spark.dynamicAllocation.initialExecutorsspark.dynamicAllocation.minExecutors初始executor數(shù)量,默認(rèn)和executor數(shù)量一樣1.3.0
          動態(tài)分配spark.dynamicAllocation.maxExecutorsinfinityexecutor上限,默認(rèn)無限制1.2.0
          動態(tài)分配spark.dynamicAllocation.minExecutors0executor下限,默認(rèn)是0個1.2.0
          動態(tài)分配spark.dynamicAllocation.executorAllocationRatio1默認(rèn)情況下,動態(tài)分配將要求足夠的執(zhí)行者根據(jù)要處理的任務(wù)數(shù)量最大化并行性。雖然這可以最大程度地減少作業(yè)的等待時間,但是對于小型任務(wù),此設(shè)置可能會由于執(zhí)行程序分配開銷而浪費(fèi)大量資源,因為某些執(zhí)行程序甚至可能無法執(zhí)行任何工作。此設(shè)置允許設(shè)置一個比率,該比率將用于減少執(zhí)行程序的數(shù)量。完全并行。默認(rèn)為1.0以提供最大的并行度。0.5將執(zhí)行者的目標(biāo)數(shù)量除以2由dynamicAllocation計算的執(zhí)行者的目標(biāo)數(shù)量仍然可以被spark.dynamicAllocation.minExecutors和spark.dynamicAllocation.maxExecutors設(shè)置覆蓋2.4.0
          動態(tài)分配spark.dynamicAllocation.schedulerBacklogTimeout1s如果啟用了動態(tài)分配,并且有待解決的任務(wù)積壓的時間超過了此期限,則將請求新的執(zhí)行者。1.2.0
          動態(tài)分配spark.dynamicAllocation.sustainedSchedulerBacklogTimeoutschedulerBacklogTimeout與spark.dynamicAllocation.schedulerBacklogTimeout相同,但僅用于后續(xù)執(zhí)行程序請求1.2.0
          動態(tài)分配spark.dynamicAllocation.shuffleTracking.enabledfalse實驗功能。為執(zhí)行程序啟用隨機(jī)文件跟蹤,從而無需外部隨機(jī)服務(wù)即可動態(tài)分配。此選項將嘗試保持為活動作業(yè)存儲隨機(jī)數(shù)據(jù)的執(zhí)行程序3.0.0
          動態(tài)分配spark.dynamicAllocation.shuffleTracking.timeoutinfinity啟用隨機(jī)跟蹤時,控制保存隨機(jī)數(shù)據(jù)的執(zhí)行程序的超時。默認(rèn)值意味著Spark將依靠垃圾回收中的shuffle來釋放執(zhí)行程序。如果由于某種原因垃圾回收無法足夠快地清理隨機(jī)數(shù)據(jù),則此選項可用于控制執(zhí)行者何時超時,即使它們正在存儲隨機(jī)數(shù)據(jù)。3.0.0


          --end--


          掃描下方二維碼
          添加好友,備注【交流
          可私聊交流,也可進(jìn)資源豐富學(xué)習(xí)群

          瀏覽 80
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天做天天添 | 内射视频免费看 | 97久久人国产精品婷婷 | 青青草视频免费观看 | 黄色无码毛片 |