精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Spark內(nèi)存調(diào)優(yōu),你會嗎?

存儲 存儲軟件 Spark
Spark 作為一個基于內(nèi)存的分布式計算引擎,其內(nèi)存管理模塊在整個系統(tǒng)中扮演著非常重要的角色。理解 Spark 內(nèi)存管理的基本原理,有助于更好地開發(fā) Spark 應(yīng)用程序和進行性能調(diào)優(yōu)。

 一、概述

Spark 作為一個基于內(nèi)存的分布式計算引擎,其內(nèi)存管理模塊在整個系統(tǒng)中扮演著非常重要的角色。理解 Spark 內(nèi)存管理的基本原理,有助于更好地開發(fā) Spark 應(yīng)用程序和進行性能調(diào)優(yōu)。本文旨在梳理出 Spark 內(nèi)存管理的脈絡(luò),拋磚引玉,引出讀者對這個話題的深入探討。本文中闡述的原理基于 Spark 2.1 版本,閱讀本文需要讀者有一定的 Spark 和 Java 基礎(chǔ),了解 RDD、Shuffle、JVM 等相關(guān)概念。

[[270926]]

在執(zhí)行 Spark 的應(yīng)用程序時,Spark 集群會啟動 Driver 和 Executor 兩種 JVM 進程,前者為主控進程,負責(zé)創(chuàng)建 Spark 上下文,提交 Spark 作業(yè)(Job),并將作業(yè)轉(zhuǎn)化為計算任務(wù)(Task),在各個 Executor 進程間協(xié)調(diào)任務(wù)的調(diào)度,后者負責(zé)在工作節(jié)點上執(zhí)行具體的計算任務(wù),并將結(jié)果返回給 Driver,同時為需要持久化的 RDD 提供存儲功能[1]。由于 Driver 的內(nèi)存管理相對來說較為簡單,本文主要對 Executor 的內(nèi)存管理進行分析,下文中的 Spark 內(nèi)存均特指 Executor 的內(nèi)存。

二、堆內(nèi)和堆外內(nèi)存規(guī)劃

作為一個 JVM 進程,Executor 的內(nèi)存管理建立在 JVM 的內(nèi)存管理之上,Spark 對 JVM 的堆內(nèi)(On-heap)空間進行了更為詳細的分配,以充分利用內(nèi)存。同時,Spark 引入了堆外(Off-heap)內(nèi)存,使之可以直接在工作節(jié)點的系統(tǒng)內(nèi)存中開辟空間,進一步優(yōu)化了內(nèi)存的使用。 

Spark內(nèi)存調(diào)優(yōu)

圖 1 . 堆內(nèi)和堆外內(nèi)存示意圖

2.1 堆內(nèi)內(nèi)存

堆內(nèi)內(nèi)存的大小,由 Spark 應(yīng)用程序啟動時的 –executor-memory 或 spark.executor.memory 參數(shù)配置。Executor 內(nèi)運行的并發(fā)任務(wù)共享 JVM 堆內(nèi)內(nèi)存,這些任務(wù)在緩存 RDD 數(shù)據(jù)和廣播(Broadcast)數(shù)據(jù)時占用的內(nèi)存被規(guī)劃為存儲(Storage)內(nèi)存,而這些任務(wù)在執(zhí)行 Shuffle 時占用的內(nèi)存被規(guī)劃為執(zhí)行(Execution)內(nèi)存,剩余的部分不做特殊規(guī)劃,那些 Spark 內(nèi)部的對象實例,或者用戶定義的 Spark 應(yīng)用程序中的對象實例,均占用剩余的空間。不同的管理模式下,這三部分占用的空間大小各不相同。

Spark 對堆內(nèi)內(nèi)存的管理是一種邏輯上的"規(guī)劃式"的管理,因為對象實例占用內(nèi)存的申請和釋放都由 JVM 完成,Spark 只能在申請后和釋放前記錄這些內(nèi)存,我們來看其具體流程:

申請內(nèi)存:

  1. Spark 在代碼中 new 一個對象實例
  2. JVM 從堆內(nèi)內(nèi)存分配空間,創(chuàng)建對象并返回對象引用
  3. Spark 保存該對象的引用,記錄該對象占用的內(nèi)存

釋放內(nèi)存:

Spark 記錄該對象釋放的內(nèi)存,刪除該對象的引用

等待 JVM 的垃圾回收機制釋放該對象占用的堆內(nèi)內(nèi)存

我們知道,JVM 的對象可以以序列化的方式存儲,序列化的過程是將對象轉(zhuǎn)換為二進制字節(jié)流,本質(zhì)上可以理解為將非連續(xù)空間的鏈式存儲轉(zhuǎn)化為連續(xù)空間或塊存儲,在訪問時則需要進行序列化的逆過程——反序列化,將字節(jié)流轉(zhuǎn)化為對象,序列化的方式可以節(jié)省存儲空間,但增加了存儲和讀取時候的計算開銷。

對于 Spark 中序列化的對象,由于是字節(jié)流的形式,其占用的內(nèi)存大小可直接計算,而對于非序列化的對象,其占用的內(nèi)存是通過周期性地采樣近似估算而得,即并不是每次新增的數(shù)據(jù)項都會計算一次占用的內(nèi)存大小,這種方法降低了時間開銷但是有可能誤差較大,導(dǎo)致某一時刻的實際內(nèi)存有可能遠遠超出預(yù)期。此外,在被 Spark 標(biāo)記為釋放的對象實例,很有可能在實際上并沒有被 JVM 回收,導(dǎo)致實際可用的內(nèi)存小于 Spark 記錄的可用內(nèi)存。所以 Spark 并不能準確記錄實際可用的堆內(nèi)內(nèi)存,從而也就無法完全避免內(nèi)存溢出(OOM, Out of Memory)的異常。

雖然不能精準控制堆內(nèi)內(nèi)存的申請和釋放,但 Spark 通過對存儲內(nèi)存和執(zhí)行內(nèi)存各自獨立的規(guī)劃管理,可以決定是否要在存儲內(nèi)存里緩存新的 RDD,以及是否為新的任務(wù)分配執(zhí)行內(nèi)存,在一定程度上可以提升內(nèi)存的利用率,減少異常的出現(xiàn)。

2.2 堆外內(nèi)存

為了進一步優(yōu)化內(nèi)存的使用以及提高 Shuffle 時排序的效率,Spark 引入了堆外(Off-heap)內(nèi)存,使之可以直接在工作節(jié)點的系統(tǒng)內(nèi)存中開辟空間,存儲經(jīng)過序列化的二進制數(shù)據(jù)。利用 JDK Unsafe API(從 Spark 2.0 開始,在管理堆外的存儲內(nèi)存時不再基于 Tachyon,而是與堆外的執(zhí)行內(nèi)存一樣,基于 JDK Unsafe API 實現(xiàn)[3]),Spark 可以直接操作系統(tǒng)堆外內(nèi)存,減少了不必要的內(nèi)存開銷,以及頻繁的 GC 掃描和回收,提升了處理性能。堆外內(nèi)存可以被精確地申請和釋放,而且序列化的數(shù)據(jù)占用的空間可以被精確計算,所以相比堆內(nèi)內(nèi)存來說降低了管理的難度,也降低了誤差。

在默認情況下堆外內(nèi)存并不啟用,可通過配置 spark.memory.offHeap.enabled 參數(shù)啟用,并由 spark.memory.offHeap.size 參數(shù)設(shè)定堆外空間的大小。除了沒有 other 空間,堆外內(nèi)存與堆內(nèi)內(nèi)存的劃分方式相同,所有運行中的并發(fā)任務(wù)共享存儲內(nèi)存和執(zhí)行內(nèi)存。

2.3 內(nèi)存管理接口

Spark 為存儲內(nèi)存和執(zhí)行內(nèi)存的管理提供了統(tǒng)一的接口——MemoryManager,同一個 Executor 內(nèi)的任務(wù)都調(diào)用這個接口的方法來申請或釋放內(nèi)存:

清單 1 . 內(nèi)存管理接口的主要方法

  1. //申請存儲內(nèi)存def acquireStorageMemory(blockId: BlockId, numBytes: Long, memoryMode: MemoryMode): Boolean//申請展開內(nèi)存def acquireUnrollMemory(blockId: BlockId, numBytes: Long, memoryMode: MemoryMode): Boolean//申請執(zhí)行內(nèi)存def acquireExecutionMemory(numBytes: Long, taskAttemptId: Long, memoryMode: MemoryMode): Long//釋放存儲內(nèi)存def releaseStorageMemory(numBytes: Long, memoryMode: MemoryMode): Unit//釋放執(zhí)行內(nèi)存def releaseExecutionMemory(numBytes: Long, taskAttemptId: Long, memoryMode: MemoryMode): Unit//釋放展開內(nèi)存def releaseUnrollMemory(numBytes: Long, memoryMode: MemoryMode): Unit 

我們看到,在調(diào)用這些方法時都需要指定其內(nèi)存模式(MemoryMode),這個參數(shù)決定了是在堆內(nèi)還是堆外完成這次操作。

MemoryManager 的具體實現(xiàn)上,Spark 1.6 之后默認為統(tǒng)一管理(Unified Memory Manager)方式,1.6 之前采用的靜態(tài)管理(Static Memory Manager)方式仍被保留,可通過配置 spark.memory.useLegacyMode 參數(shù)啟用。兩種方式的區(qū)別在于對空間分配的方式,下面的第 3 小節(jié)會分別對這兩種方式進行介紹。

三、內(nèi)存空間分配

3.1 靜態(tài)內(nèi)存管理

在 Spark 最初采用的靜態(tài)內(nèi)存管理機制下,存儲內(nèi)存、執(zhí)行內(nèi)存和其他內(nèi)存的大小在 Spark 應(yīng)用程序運行期間均為固定的,但用戶可以應(yīng)用程序啟動前進行配置,堆內(nèi)內(nèi)存的分配如圖所示: 

Spark內(nèi)存調(diào)優(yōu)

圖 2 . 靜態(tài)內(nèi)存管理圖示——堆內(nèi)

可以看到,可用的堆內(nèi)內(nèi)存的大小需要按照下面的方式計算:

清單 2 . 可用堆內(nèi)內(nèi)存空間

  1. 可用的存儲內(nèi)存 = systemMaxMemory * spark.storage.memoryFraction * spark.storage.safetyFraction可用的執(zhí)行內(nèi)存 = systemMaxMemory * spark.shuffle.memoryFraction * spark.shuffle.safetyFraction 

其中 systemMaxMemory 取決于當(dāng)前 JVM 堆內(nèi)內(nèi)存的大小,***可用的執(zhí)行內(nèi)存或者存儲內(nèi)存要在此基礎(chǔ)上與各自的 memoryFraction 參數(shù)和 safetyFraction 參數(shù)相乘得出。上述計算公式中的兩個 safetyFraction 參數(shù),其意義在于在邏輯上預(yù)留出 1-safetyFraction 這么一塊保險區(qū)域,降低因?qū)嶋H內(nèi)存超出當(dāng)前預(yù)設(shè)范圍而導(dǎo)致 OOM 的風(fēng)險(上文提到,對于非序列化對象的內(nèi)存采樣估算會產(chǎn)生誤差)。值得注意的是,這個預(yù)留的保險區(qū)域僅僅是一種邏輯上的規(guī)劃,在具體使用時 Spark 并沒有區(qū)別對待,和"其它內(nèi)存"一樣交給了 JVM 去管理。

堆外的空間分配較為簡單,只有存儲內(nèi)存和執(zhí)行內(nèi)存,如圖 3 所示。可用的執(zhí)行內(nèi)存和存儲內(nèi)存占用的空間大小直接由參數(shù) spark.memory.storageFraction 決定,由于堆外內(nèi)存占用的空間可以被精確計算,所以無需再設(shè)定保險區(qū)域。 

Spark內(nèi)存調(diào)優(yōu)

圖 3 . 靜態(tài)內(nèi)存管理圖示——堆外

靜態(tài)內(nèi)存管理機制實現(xiàn)起來較為簡單,但如果用戶不熟悉 Spark 的存儲機制,或沒有根據(jù)具體的數(shù)據(jù)規(guī)模和計算任務(wù)或做相應(yīng)的配置,很容易造成"一半海水,一半火焰"的局面,即存儲內(nèi)存和執(zhí)行內(nèi)存中的一方剩余大量的空間,而另一方卻早早被占滿,不得不淘汰或移出舊的內(nèi)容以存儲新的內(nèi)容。由于新的內(nèi)存管理機制的出現(xiàn),這種方式目前已經(jīng)很少有開發(fā)者使用,出于兼容舊版本的應(yīng)用程序的目的,Spark 仍然保留了它的實現(xiàn)。

3.2 統(tǒng)一內(nèi)存管理

Spark 1.6 之后引入的統(tǒng)一內(nèi)存管理機制,與靜態(tài)內(nèi)存管理的區(qū)別在于存儲內(nèi)存和執(zhí)行內(nèi)存共享同一塊空間,可以動態(tài)占用對方的空閑區(qū)域,如圖 4 和圖 5 所示

Spark內(nèi)存調(diào)優(yōu)

圖 4 . 統(tǒng)一內(nèi)存管理圖示——堆內(nèi) 

Spark內(nèi)存調(diào)優(yōu)

圖 5 . 統(tǒng)一內(nèi)存管理圖示——堆外

其中最重要的優(yōu)化在于動態(tài)占用機制,其規(guī)則如下:

設(shè)定基本的存儲內(nèi)存和執(zhí)行內(nèi)存區(qū)域(spark.storage.storageFraction 參數(shù)),該設(shè)定確定了雙方各自擁有的空間的范圍

雙方的空間都不足時,則存儲到硬盤;若己方空間不足而對方空余時,可借用對方的空間;(存儲空間不足是指不足以放下一個完整的 Block)

執(zhí)行內(nèi)存的空間被對方占用后,可讓對方將占用的部分轉(zhuǎn)存到硬盤,然后"歸還"借用的空間

存儲內(nèi)存的空間被對方占用后,無法讓對方"歸還",因為需要考慮 Shuffle 過程中的很多因素,實現(xiàn)起來較為復(fù)雜[4]

Spark內(nèi)存調(diào)優(yōu)

圖 6 . 動態(tài)占用機制圖示

憑借統(tǒng)一內(nèi)存管理機制,Spark 在一定程度上提高了堆內(nèi)和堆外內(nèi)存資源的利用率,降低了開發(fā)者維護 Spark 內(nèi)存的難度,但并不意味著開發(fā)者可以高枕無憂。譬如,所以如果存儲內(nèi)存的空間太大或者說緩存的數(shù)據(jù)過多,反而會導(dǎo)致頻繁的全量垃圾回收,降低任務(wù)執(zhí)行時的性能,因為緩存的 RDD 數(shù)據(jù)通常都是長期駐留內(nèi)存的 [5] 。所以要想充分發(fā)揮 Spark 的性能,需要開發(fā)者進一步了解存儲內(nèi)存和執(zhí)行內(nèi)存各自的管理方式和實現(xiàn)原理。

四、存儲內(nèi)存管理

4.1 RDD 的持久化機制

彈性分布式數(shù)據(jù)集(RDD)作為 Spark 最根本的數(shù)據(jù)抽象,是只讀的分區(qū)記錄(Partition)的集合,只能基于在穩(wěn)定物理存儲中的數(shù)據(jù)集上創(chuàng)建,或者在其他已有的 RDD 上執(zhí)行轉(zhuǎn)換(Transformation)操作產(chǎn)生一個新的 RDD。轉(zhuǎn)換后的 RDD 與原始的 RDD 之間產(chǎn)生的依賴關(guān)系,構(gòu)成了血統(tǒng)(Lineage)。憑借血統(tǒng),Spark 保證了每一個 RDD 都可以被重新恢復(fù)。但 RDD 的所有轉(zhuǎn)換都是惰性的,即只有當(dāng)一個返回結(jié)果給 Driver 的行動(Action)發(fā)生時,Spark 才會創(chuàng)建任務(wù)讀取 RDD,然后真正觸發(fā)轉(zhuǎn)換的執(zhí)行。

Task 在啟動之初讀取一個分區(qū)時,會先判斷這個分區(qū)是否已經(jīng)被持久化,如果沒有則需要檢查 Checkpoint 或按照血統(tǒng)重新計算。所以如果一個 RDD 上要執(zhí)行多次行動,可以在***次行動中使用 persist 或 cache 方法,在內(nèi)存或磁盤中持久化或緩存這個 RDD,從而在后面的行動時提升計算速度。事實上,cache 方法是使用默認的 MEMORY_ONLY 的存儲級別將 RDD 持久化到內(nèi)存,故緩存是一種特殊的持久化。 堆內(nèi)和堆外存儲內(nèi)存的設(shè)計,便可以對緩存 RDD 時使用的內(nèi)存做統(tǒng)一的規(guī)劃和管 理 (存儲內(nèi)存的其他應(yīng)用場景,如緩存 broadcast 數(shù)據(jù),暫時不在本文的討論范圍之內(nèi))。

RDD 的持久化由 Spark 的 Storage 模塊 [7] 負責(zé),實現(xiàn)了 RDD 與物理存儲的解耦合。Storage 模塊負責(zé)管理 Spark 在計算過程中產(chǎn)生的數(shù)據(jù),將那些在內(nèi)存或磁盤、在本地或遠程存取數(shù)據(jù)的功能封裝了起來。在具體實現(xiàn)時 Driver 端和 Executor 端的 Storage 模塊構(gòu)成了主從式的架構(gòu),即 Driver 端的 BlockManager 為 Master,Executor 端的 BlockManager 為 Slave。Storage 模塊在邏輯上以 Block 為基本存儲單位,RDD 的每個 Partition 經(jīng)過處理后唯一對應(yīng)一個 Block(BlockId 的格式為 rdd_RDD-ID_PARTITION-ID )。Master 負責(zé)整個 Spark 應(yīng)用程序的 Block 的元數(shù)據(jù)信息的管理和維護,而 Slave 需要將 Block 的更新等狀態(tài)上報到 Master,同時接收 Master 的命令,例如新增或刪除一個 RDD。

Spark內(nèi)存調(diào)優(yōu)

圖 7 . Storage 模塊示意圖

在對 RDD 持久化時,Spark 規(guī)定了 MEMORY_ONLY、MEMORY_AND_DISK 等 7 種不同的存儲級別,而存儲級別是以下 5 個變量的組合:

清單 3 . 存儲級別

  1. class StorageLevel private(private var _useDisk: Boolean, //磁盤private var _useMemory: Boolean, //這里其實是指堆內(nèi)內(nèi)存private var _useOffHeap: Boolean, //堆外內(nèi)存private var _deserialized: Boolean, //是否為非序列化private var _replication: Int = 1 //副本個數(shù)) 

通過對數(shù)據(jù)結(jié)構(gòu)的分析,可以看出存儲級別從三個維度定義了 RDD 的 Partition(同時也就是 Block)的存儲方式:

存儲位置:磁盤/堆內(nèi)內(nèi)存/堆外內(nèi)存。如 MEMORY_AND_DISK 是同時在磁盤和堆內(nèi)內(nèi)存上存儲,實現(xiàn)了冗余備份。OFF_HEAP 則是只在堆外內(nèi)存存儲,目前選擇堆外內(nèi)存時不能同時存儲到其他位置。

存儲形式:Block 緩存到存儲內(nèi)存后,是否為非序列化的形式。如 MEMORY_ONLY 是非序列化方式存儲,OFF_HEAP 是序列化方式存儲。

副本數(shù)量:大于 1 時需要遠程冗余備份到其他節(jié)點。如 DISK_ONLY_2 需要遠程備份 1 個副本。

4.2 RDD 緩存的過程

RDD 在緩存到存儲內(nèi)存之前,Partition 中的數(shù)據(jù)一般以迭代器(Iterator)的數(shù)據(jù)結(jié)構(gòu)來訪問,這是 Scala 語言中一種遍歷數(shù)據(jù)集合的方法。通過 Iterator 可以獲取分區(qū)中每一條序列化或者非序列化的數(shù)據(jù)項(Record),這些 Record 的對象實例在邏輯上占用了 JVM 堆內(nèi)內(nèi)存的 other 部分的空間,同一 Partition 的不同 Record 的空間并不連續(xù)。

RDD 在緩存到存儲內(nèi)存之后,Partition 被轉(zhuǎn)換成 Block,Record 在堆內(nèi)或堆外存儲內(nèi)存中占用一塊連續(xù)的空間。將Partition由不連續(xù)的存儲空間轉(zhuǎn)換為連續(xù)存儲空間的過程,Spark稱之為"展開"(Unroll)。Block 有序列化和非序列化兩種存儲格式,具體以哪種方式取決于該 RDD 的存儲級別。非序列化的 Block 以一種 DeserializedMemoryEntry 的數(shù)據(jù)結(jié)構(gòu)定義,用一個數(shù)組存儲所有的對象實例,序列化的 Block 則以 SerializedMemoryEntry的數(shù)據(jù)結(jié)構(gòu)定義,用字節(jié)緩沖區(qū)(ByteBuffer)來存儲二進制數(shù)據(jù)。每個 Executor 的 Storage 模塊用一個鏈式 Map 結(jié)構(gòu)(LinkedHashMap)來管理堆內(nèi)和堆外存儲內(nèi)存中所有的 Block 對象的實例[6],對這個 LinkedHashMap 新增和刪除間接記錄了內(nèi)存的申請和釋放。

因為不能保證存儲空間可以一次容納 Iterator 中的所有數(shù)據(jù),當(dāng)前的計算任務(wù)在 Unroll 時要向 MemoryManager 申請足夠的 Unroll 空間來臨時占位,空間不足則 Unroll 失敗,空間足夠時可以繼續(xù)進行。對于序列化的 Partition,其所需的 Unroll 空間可以直接累加計算,一次申請。而非序列化的 Partition 則要在遍歷 Record 的過程中依次申請,即每讀取一條 Record,采樣估算其所需的 Unroll 空間并進行申請,空間不足時可以中斷,釋放已占用的 Unroll 空間。如果最終 Unroll 成功,當(dāng)前 Partition 所占用的 Unroll 空間被轉(zhuǎn)換為正常的緩存 RDD 的存儲空間,如下圖 8 所示。

Spark內(nèi)存調(diào)優(yōu)

圖 8. Spark Unroll 示意圖

在圖 3 和圖 5 中可以看到,在靜態(tài)內(nèi)存管理時,Spark 在存儲內(nèi)存中專門劃分了一塊 Unroll 空間,其大小是固定的,統(tǒng)一內(nèi)存管理時則沒有對 Unroll 空間進行特別區(qū)分,當(dāng)存儲空間不足時會根據(jù)動態(tài)占用機制進行處理。

4.3 淘汰和落盤

由于同一個 Executor 的所有的計算任務(wù)共享有限的存儲內(nèi)存空間,當(dāng)有新的 Block 需要緩存但是剩余空間不足且無法動態(tài)占用時,就要對 LinkedHashMap 中的舊 Block 進行淘汰(Eviction),而被淘汰的 Block 如果其存儲級別中同時包含存儲到磁盤的要求,則要對其進行落盤(Drop),否則直接刪除該 Block。

存儲內(nèi)存的淘汰規(guī)則為:

被淘汰的舊 Block 要與新 Block 的 MemoryMode 相同,即同屬于堆外或堆內(nèi)內(nèi)存

新舊 Block 不能屬于同一個 RDD,避免循環(huán)淘汰

舊 Block 所屬 RDD 不能處于被讀狀態(tài),避免引發(fā)一致性問題

遍歷 LinkedHashMap 中 Block,按照最近最少使用(LRU)的順序淘汰,直到滿足新 Block 所需的空間。其中 LRU 是 LinkedHashMap 的特性。

落盤的流程則比較簡單,如果其存儲級別符合_useDisk 為 true 的條件,再根據(jù)其_deserialized 判斷是否是非序列化的形式,若是則對其進行序列化,***將數(shù)據(jù)存儲到磁盤,在 Storage 模塊中更新其信息。

五、 執(zhí)行內(nèi)存管理

5.1 多任務(wù)間內(nèi)存分配

Executor 內(nèi)運行的任務(wù)同樣共享執(zhí)行內(nèi)存,Spark 用一個 HashMap 結(jié)構(gòu)保存了任務(wù)到內(nèi)存耗費的映射。每個任務(wù)可占用的執(zhí)行內(nèi)存大小的范圍為 1/2N ~ 1/N,其中 N 為當(dāng)前 Executor 內(nèi)正在運行的任務(wù)的個數(shù)。每個任務(wù)在啟動之時,要向 MemoryManager 請求申請最少為 1/2N 的執(zhí)行內(nèi)存,如果不能被滿足要求則該任務(wù)被阻塞,直到有其他任務(wù)釋放了足夠的執(zhí)行內(nèi)存,該任務(wù)才可以被喚醒。

5.2 Shuffle 的內(nèi)存占用

執(zhí)行內(nèi)存主要用來存儲任務(wù)在執(zhí)行 Shuffle 時占用的內(nèi)存,Shuffle 是按照一定規(guī)則對 RDD 數(shù)據(jù)重新分區(qū)的過程,我們來看 Shuffle 的 Write 和 Read 兩階段對執(zhí)行內(nèi)存的使用:

  • Shuffle Write

若在 map 端選擇普通的排序方式,會采用 ExternalSorter 進行外排,在內(nèi)存中存儲數(shù)據(jù)時主要占用堆內(nèi)執(zhí)行空間。

若在 map 端選擇 Tungsten 的排序方式,則采用 ShuffleExternalSorter 直接對以序列化形式存儲的數(shù)據(jù)排序,在內(nèi)存中存儲數(shù)據(jù)時可以占用堆外或堆內(nèi)執(zhí)行空間,取決于用戶是否開啟了堆外內(nèi)存以及堆外執(zhí)行內(nèi)存是否足夠。

  • Shuffle Read

在對 reduce 端的數(shù)據(jù)進行聚合時,要將數(shù)據(jù)交給 Aggregator 處理,在內(nèi)存中存儲數(shù)據(jù)時占用堆內(nèi)執(zhí)行空間。

如果需要進行最終結(jié)果排序,則要將再次將數(shù)據(jù)交給 ExternalSorter 處理,占用堆內(nèi)執(zhí)行空間。

在 ExternalSorter 和 Aggregator 中,Spark 會使用一種叫 AppendOnlyMap 的哈希表在堆內(nèi)執(zhí)行內(nèi)存中存儲數(shù)據(jù),但在 Shuffle 過程中所有數(shù)據(jù)并不能都保存到該哈希表中,當(dāng)這個哈希表占用的內(nèi)存會進行周期性地采樣估算,當(dāng)其大到一定程度,無法再從 MemoryManager 申請到新的執(zhí)行內(nèi)存時,Spark 就會將其全部內(nèi)容存儲到磁盤文件中,這個過程被稱為溢存(Spill),溢存到磁盤的文件***會被歸并(Merge)。

Shuffle Write 階段中用到的 Tungsten 是 Databricks 公司提出的對 Spark 優(yōu)化內(nèi)存和 CPU 使用的計劃[9],解決了一些 JVM 在性能上的限制和弊端。Spark 會根據(jù) Shuffle 的情況來自動選擇是否采用 Tungsten 排序。Tungsten 采用的頁式內(nèi)存管理機制建立在 MemoryManager 之上,即 Tungsten 對執(zhí)行內(nèi)存的使用進行了一步的抽象,這樣在 Shuffle 過程中無需關(guān)心數(shù)據(jù)具體存儲在堆內(nèi)還是堆外。每個內(nèi)存頁用一個 MemoryBlock 來定義,并用 Object obj 和 long offset 這兩個變量統(tǒng)一標(biāo)識一個內(nèi)存頁在系統(tǒng)內(nèi)存中的地址。堆內(nèi)的 MemoryBlock 是以 long 型數(shù)組的形式分配的內(nèi)存,其 obj 的值為是這個數(shù)組的對象引用,offset 是 long 型數(shù)組的在 JVM 中的初始偏移地址,兩者配合使用可以定位這個數(shù)組在堆內(nèi)的絕對地址;堆外的 MemoryBlock 是直接申請到的內(nèi)存塊,其 obj 為 null,offset 是這個內(nèi)存塊在系統(tǒng)內(nèi)存中的 64 位絕對地址。Spark 用 MemoryBlock 巧妙地將堆內(nèi)和堆外內(nèi)存頁統(tǒng)一抽象封裝,并用頁表(pageTable)管理每個 Task 申請到的內(nèi)存頁。

Tungsten 頁式管理下的所有內(nèi)存用 64 位的邏輯地址表示,由頁號和頁內(nèi)偏移量組成:

頁號:占 13 位,唯一標(biāo)識一個內(nèi)存頁,Spark 在申請內(nèi)存頁之前要先申請空閑頁號。

頁內(nèi)偏移量:占 51 位,是在使用內(nèi)存頁存儲數(shù)據(jù)時,數(shù)據(jù)在頁內(nèi)的偏移地址。

有了統(tǒng)一的尋址方式,Spark 可以用 64 位邏輯地址的指針定位到堆內(nèi)或堆外的內(nèi)存,整個 Shuffle Write 排序的過程只需要對指針進行排序,并且無需反序列化,整個過程非常高效,對于內(nèi)存訪問效率和 CPU 使用效率帶來了明顯的提升。

Spark 的存儲內(nèi)存和執(zhí)行內(nèi)存有著截然不同的管理方式:對于存儲內(nèi)存來說,Spark 用一個 LinkedHashMap 來集中管理所有的 Block,Block 由需要緩存的 RDD 的 Partition 轉(zhuǎn)化而成;而對于執(zhí)行內(nèi)存,Spark 用 AppendOnlyMap 來存儲 Shuffle 過程中的數(shù)據(jù),在 Tungsten 排序中甚至抽象成為頁式內(nèi)存管理,開辟了全新的 JVM 內(nèi)存管理機制。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2021-12-26 00:03:25

Spark性能調(diào)優(yōu)

2023-05-29 07:43:32

JVM內(nèi)存調(diào)優(yōu)

2021-03-04 08:39:21

SparkRDD調(diào)優(yōu)

2010-09-26 10:53:00

JVM內(nèi)存調(diào)優(yōu)設(shè)置

2018-07-18 12:12:20

Spark大數(shù)據(jù)代碼

2020-11-09 07:34:49

JVM性能監(jiān)控

2014-12-19 11:07:40

Java

2010-09-25 15:52:27

JVM內(nèi)存JVM

2017-10-20 13:41:11

Spark集群代碼

2017-07-07 11:01:04

Spark性能調(diào)優(yōu)

2023-06-05 09:17:50

SQLAlchemy關(guān)系型數(shù)據(jù)庫

2022-09-20 14:11:37

JVM調(diào)優(yōu)命令

2012-01-10 14:35:08

JavaJVM

2023-02-10 09:28:23

優(yōu)化工具

2021-08-26 05:00:44

生產(chǎn)環(huán)境內(nèi)存

2018-08-24 07:17:41

Spark大數(shù)據(jù)調(diào)優(yōu)

2020-08-10 17:49:25

JVM內(nèi)存溢出

2017-07-21 08:55:13

TomcatJVM容器

2010-05-27 17:10:03

MySQL數(shù)據(jù)庫內(nèi)存

2023-10-18 08:01:27

Java虛擬機
點贊
收藏

51CTO技術(shù)棧公眾號

精品综合久久88少妇激情| 性xxxx视频| 欧美xxx在线观看| 欧美va在线播放| 国产freexxxx性播放麻豆| xxxx18国产| 在线国产精品一区| 精品中文字幕久久久久久| 国产精品入口免费软件| 久草免费在线观看| 成人性色生活片免费看爆迷你毛片| 日韩在线观看高清| 91免费视频污| 日本黄色免费在线| 国产精品天干天干在观线| 国产在线看一区| 91精品啪在线观看国产60岁| 第九区2中文字幕| 五十路在线视频| 视频一区二区欧美| 中文字幕亚洲第一| 少妇献身老头系列| 深夜国产在线播放| 国产亚洲短视频| 91精品久久久久久蜜桃| 可以免费在线观看的av| 日韩精品电影| 亚洲福利视频二区| 国产探花在线看| 在线黄色网页| 国产日产精品一区| 成人在线视频网址| 亚洲婷婷久久综合| 狠狠色丁香久久综合频道 | 草草影院在线| 国产mv日韩mv欧美| 国产97在线亚洲| 欧美精品一区二区蜜桃| 狠狠综合久久av一区二区蜜桃| 欧美一区二区日韩| 日韩中文字幕免费在线| 欧美韩日亚洲| 国产精品乱码人人做人人爱| 国产日本一区二区三区| 国产日韩免费视频| 麻豆91小视频| 国产国语刺激对白av不卡| 国产精品23p| 我不卡神马影院| 一本一本久久a久久精品牛牛影视| 佐佐木明希电影| 国产精品麻豆| 欧美日高清视频| 免费在线观看的毛片| 三级中文字幕在线观看| 一区二区高清视频在线观看| 欧美日韩在线免费观看视频| 国产一区二区影视| 久久久夜色精品亚洲| 91色视频在线观看| 亚洲毛片一区二区三区| 99视频+国产日韩欧美| 色综合五月天导航| 动漫性做爰视频| 午夜影院欧美| 久久精品久久久久久国产 免费| 亚洲天堂岛国片| 久操成人av| 亚洲经典中文字幕| 国产精品一级黄片| 青青视频一区二区| 亚洲精选中文字幕| 无码一区二区三区在线| 国产欧美日韩精品一区二区三区| 精品五月天久久| 波多野结衣影院| 奇米影视777在线欧美电影观看| 亚洲成人999| 先锋资源av在线| 偷窥自拍亚洲色图精选| 亚洲毛片在线免费观看| 欧美性猛交xxxx乱| 日本一区二区免费高清| 日韩小视频在线观看| 侵犯稚嫩小箩莉h文系列小说| 国产高清欧美| 中文字幕亚洲二区| 久久成人小视频| 亚洲欧美在线专区| 久久久久免费视频| 日本在线视频中文字幕| 午夜亚洲视频| 国产精品亚洲激情| 国产女18毛片多18精品| 成人听书哪个软件好| 精品蜜桃传媒| 成人高清免费在线播放| 国产精品美女久久久久久| 国产日韩视频在线播放| caoporn-草棚在线视频最| 福利精品视频在线| 欧美婷婷精品激情| 伊色综合久久之综合久久| 日韩av在线免播放器| 久久丫精品忘忧草西安产品| 91精品精品| 97国产精品免费视频| www.久久网| 高清国产午夜精品久久久久久| 激情视频一区二区| 婷婷免费在线视频| 亚洲第一主播视频| 亚洲综合欧美在线| 国产精品香蕉| 在线观看视频99| 久久网中文字幕| 青青草国产成人99久久| 成人永久免费| 超碰免费在线| 亚洲一区精品在线| 久久婷五月综合| 波多野结衣欧美| 中文字幕免费国产精品| 国产在线视频你懂的| 青青国产91久久久久久| 国产在线一区二| 国产在线高清视频| 日韩欧美视频一区二区三区| 夜夜爽久久精品91| jvid福利在线一区二区| 97精品视频在线播放| 一级做a爰片久久毛片16| 不卡的看片网站| 亚洲国产精品影视| 手机看片久久| 欧美一级免费大片| 又色又爽的视频| 国语对白精品一区二区| 成人精品福利视频| 九九热视频在线观看| 亚洲1区2区3区视频| 天堂网成人在线| 日韩精品一区二区久久| 97视频在线免费观看| 国产亲伦免费视频播放| 国产三级精品在线| 免费在线观看亚洲视频| 成功精品影院| 久精品免费视频| 国产又粗又猛又色又| 成人免费视频视频| 国产高清不卡无码视频| 91麻豆精品一二三区在线| 在线观看日韩欧美| 午夜一区二区三区四区| 久久亚洲精品国产精品紫薇| 黄色www网站| 国产女人18毛片水真多18精品| 欧美成年人在线观看| 91麻豆国产视频| 国产精品视频九色porn| 亚洲中文字幕久久精品无码喷水| 亚洲va久久久噜噜噜久久| 操91在线视频| www五月婷婷| 亚洲免费成人av| 下面一进一出好爽视频| 亚洲精品一区二区在线看| 国产一区二中文字幕在线看 | 蜜臀精品一区二区三区在线观看| 欧洲精品亚洲精品| 国产精品亚洲d| 国产亚洲精品一区二区| 无码人妻丰满熟妇精品| 国产无一区二区| a在线观看免费视频| 久久电影院7| 亚洲一区二区三区在线视频| 中文字幕有码在线观看| 精品欧美乱码久久久久久 | 欧美性猛交xxxx| 永久免费成人代码| 久久66热re国产| 国产免费一区二区视频| 久久爱www成人| 国产精品免费久久久久久| 黄色片免费在线| 欧美三级欧美一级| 日本黄色片免费观看| 国产91精品在线观看| 久草资源站在线观看| 欧美精选一区二区三区| 国产精品第一区| а天堂中文在线官网| 精品国产乱码久久久久久蜜臀| 久久精品欧美一区二区| 久久亚洲精品小早川怜子| 四季av一区二区三区| 欧美激情视频一区二区三区在线播放 | 亚洲一级片网站| 欧美精品黄色| 久久精品午夜一区二区福利| 国产精品第一| 久久久久国色av免费观看性色| 网站黄在线观看| 欧美日韩日日夜夜| 国产亚洲欧美久久久久| 国产喂奶挤奶一区二区三区| 人妻巨大乳一二三区| 激情欧美国产欧美| 亚洲欧洲国产精品久久| 大奶在线精品| 国产成人精品免费视频| 日本视频在线播放| 亚洲精品国产品国语在线| 中文字幕永久在线观看| 亚洲国产精品影院| 激情无码人妻又粗又大| 丰满白嫩尤物一区二区| 天堂网在线免费观看| 在线视频日韩| 国产福利片一区二区| 国产99精品一区| 粉嫩高清一区二区三区精品视频| 日韩一级二级| 91精品国产高清自在线| 成人免费视屏| 中文字幕不卡在线视频极品| 色哟哟国产精品色哟哟| 6080午夜不卡| 国产无遮挡呻吟娇喘视频| 亚洲一区二区三区四区在线观看| 五月天婷婷丁香网| 国产亚洲欧美激情| 黑森林av导航| 国产成人自拍网| 成人日韩在线视频| 七七婷婷婷婷精品国产| 日韩av黄色网址| 亚洲美女一区| av网站手机在线观看| 在线中文字幕亚洲| 中文字幕欧美人与畜| 日本久久综合| 日韩激情久久| 国产免费av一区二区三区| 免费av在线一区二区| 国偷自产av一区二区三区| 国产精品视频永久免费播放 | 久久蜜桃一区二区| 玖玖爱在线精品视频| 国产成人精品免费在线| 国产又粗又长又爽又黄的视频| 另类的小说在线视频另类成人小视频在线 | 亚洲天堂精品视频| a级黄色免费视频| 国产精品每日更新| 99久久精品免费视频| 国产日产欧产精品推荐色| 国产精品久久免费观看| 久久精品亚洲麻豆av一区二区| theav精尽人亡av| 91免费国产在线观看| 欧美国产成人精品| 国产人妻精品午夜福利免费| 成人丝袜高跟foot| 成人免费看aa片| 中文字幕av不卡| www.5588.com毛片| 亚洲一区二区三区影院| 欧美一区二区激情视频| 欧美三级日韩三级国产三级| 国产草草影院ccyycom| 亚洲国产毛片完整版| 国产三区四区在线观看| 爱福利视频一区| 欧美女同一区| 欧美在线观看网站| 成人在线观看免费播放| 亚洲综合av影视| 乱亲女h秽乱长久久久| 午夜一区二区三区| 欧美三区视频| 日本精品www| 国产在线视视频有精品| 亚洲精品第二页| 中文文精品字幕一区二区| 国产性生活网站| 欧美性感一类影片在线播放| 99久久夜色精品国产亚洲| 日韩高清欧美高清| 男人天堂久久久| 午夜免费日韩视频| 四虎成人精品一区二区免费网站| 91精品入口蜜桃| 精品欧美久久| 亚洲色成人www永久在线观看| 日韩在线a电影| 亚洲麻豆一区二区三区| 中文字幕免费不卡在线| 国产精彩视频在线观看| 欧美久久久影院| 欧洲一区av| 欧美大片免费看| 久久av影院| 国产精品福利视频| 水蜜桃精品av一区二区| 男人操女人免费软件| 国产电影一区二区三区| 日日操免费视频| 欧美日韩性视频| 亚洲成人777777| 久久深夜福利免费观看| 精品日韩视频| 久久久久久高清| 国产精品啊啊啊| 福利片一区二区三区| 久久精品一区二区三区不卡| 日韩精品乱码久久久久久| 日韩精品一区二区三区四区| avav免费在线观看| 日韩美女视频在线观看| 久久久久观看| 丁香六月激情婷婷| 国产宾馆实践打屁股91| www欧美com| 欧美精品第1页| av在线电影免费观看| 国产97在线|日韩| 欧美黑人巨大videos精品| 久久这里只有精品8| 韩国v欧美v日本v亚洲v| 成年人视频软件| 欧美午夜精品理论片a级按摩| 亚洲色图欧美视频| 91精品国产91| 免费萌白酱国产一区二区三区| 日韩人妻无码精品久久久不卡| 国产丶欧美丶日本不卡视频| 加勒比av在线播放| 粉嫩高潮美女一区二区三区| 国产99在线 | 亚洲| 色狠狠桃花综合| 九一国产在线| 国产精品久久久久久久久| 欧美理论在线播放| 成年人在线看片| 26uuu色噜噜精品一区二区| 1级黄色大片儿| 亚洲精品720p| 中文一区一区三区高中清不卡免费| 精品免费国产| 国产精品久久久亚洲一区| 成人手机在线免费视频| 午夜精品福利一区二区三区蜜桃| 少妇av一区二区| 91av在线免费观看视频| 中文字幕av一区二区三区人| 少妇高清精品毛片在线视频| 国产日韩v精品一区二区| 中文字幕一区二区久久人妻| 最新91在线视频| www.欧美| 超碰成人免费在线| 91麻豆免费看| 在线观看视频二区| 欧美成人国产va精品日本一级| 免费观看亚洲视频大全| 亚洲 欧美 综合 另类 中字| 久久午夜免费电影| 一级片视频免费| 欧美国产日韩免费| 亚洲美女15p| 视色视频在线观看| 一区二区高清免费观看影视大全| 天堂网2014av| 国产精品免费视频xxxx| 亚洲综合激情在线| 中文字幕一区二区人妻电影丶| 色婷婷综合五月| 国产在线观看免费麻豆| 精品免费日产一区一区三区免费| 老司机午夜精品视频在线观看| 日本爱爱小视频| 欧美mv日韩mv亚洲| 电影一区二区三区| 亚洲最新免费视频| bt欧美亚洲午夜电影天堂| 中文字幕一区2区3区| 久久久久久久久中文字幕| 狠狠做深爱婷婷综合一区| 亚洲妇女无套内射精| 91成人在线观看喷潮| 99视频免费在线观看| 欧美连裤袜在线视频| 激情综合色丁香一区二区| 久久不卡免费视频| 理论片在线不卡免费观看| 国产伦精品一区二区三区千人斩| 中文字幕第六页|