spark統(tǒng)一內(nèi)存管理模型

參考:https://www.iteblog.com/archives/2342.html
spark新的內(nèi)存管理框架(1.6以上)上使用兩個參數(shù)來控制spark.memory.fraction和spark.memory.storageFraction。
spark.storage.memoryFraction spark.shuffle.memoryFraction不再使用

在spark1.6之前采用的是靜態(tài)內(nèi)存模型,1.6之后采用的是統(tǒng)一內(nèi)存模型

概述

統(tǒng)一內(nèi)存管理模塊包括了堆內(nèi)內(nèi)存(On-heap Memory)和堆外內(nèi)存(Off-heap Memory)兩大區(qū)域
對于堆內(nèi)內(nèi)存

  • System Memory = executor-memory = (Eden + FROM +TO) = execution-memory + storage-memory + user-memory + reserver-memory
  • spark-memory = execution-memory + storage-memory
  • reserver-memory固定大小為200M
  • user-meomry = (SystemMemory-200m)* (1-spark.memory.fraction)
  • spark-meomry = (SystemMemory-200m)*spark.memory.fraction
  • storage-memory = spark-memory * spark.memory.storageFraction
    -execution-memory = spark-memory * (1-spark.memory.storageFraction)

On-heap Memory 堆內(nèi)內(nèi)存

默認(rèn)情況下笆豁,Spark 僅僅使用了堆內(nèi)內(nèi)存。Executor 端的堆內(nèi)內(nèi)存區(qū)域大致可以分為以下四大塊:

  • Execution 內(nèi)存:主要用于存放 Shuffle锅移、Join、Sort淌喻、Aggregation 等計(jì)算過程中的臨時數(shù)據(jù)
  • Storage 內(nèi)存:主要用于存儲 spark 的 cache 數(shù)據(jù)跃赚,例如RDD的緩存、unroll數(shù)據(jù)膏蚓;
  • 用戶內(nèi)存(User Memory):主要用于存儲 RDD 轉(zhuǎn)換操作所需要的數(shù)據(jù),例如 RDD 依賴等信息畸写。
  • 預(yù)留內(nèi)存(Reserved Memory):系統(tǒng)預(yù)留內(nèi)存驮瞧,會用來存儲Spark內(nèi)部對象。

systemMemory = Runtime.getRuntime.maxMemory枯芬,其實(shí)就是通過參數(shù) spark.executor.memory 或 --executor-memory 配置的论笔。
reservedMemory 在 Spark 2.2.1 中是寫死的,其值等于 300MB千所,這個值是不能修改的(如果在測試環(huán)境下狂魔,我們可以通過 spark.testing.reservedMemory 參數(shù)進(jìn)行修改);
usableMemory = systemMemory - reservedMemory淫痰,這個就是 Spark 可用內(nèi)存

Off-heap Memory 堆外內(nèi)存

java的unsafe相關(guān)的api使用的是堆外內(nèi)存
這種模式不在 JVM 內(nèi)申請內(nèi)存最楷,而是調(diào)用 Java 的 unsafe 相關(guān) API 進(jìn)行諸如 C 語言里面的 malloc() 直接向操作系統(tǒng)申請內(nèi)存,由于這種方式不進(jìn)過 JVM 內(nèi)存管理待错,所以可以避免頻繁的 GC籽孙,這種內(nèi)存申請的缺點(diǎn)是必須自己編寫內(nèi)存申請和釋放的邏輯
默認(rèn)情況下,堆外內(nèi)存是關(guān)閉的朗鸠,我們可以通過 spark.memory.offHeap.enabled 參數(shù)啟用,并且通過 spark.memory.offHeap.size 設(shè)置堆外內(nèi)存大小础倍,單位為字節(jié)烛占。如果堆外內(nèi)存被啟用,那么 Executor 內(nèi)將同時存在堆內(nèi)和堆外內(nèi)存沟启,兩者的使用互補(bǔ)影響忆家,這個時候 Executor 中的 Execution 內(nèi)存是堆內(nèi)的 Execution 內(nèi)存和堆外的 Execution 內(nèi)存之和,同理德迹,Storage 內(nèi)存也一樣芽卿。相比堆內(nèi)內(nèi)存,堆外內(nèi)存只區(qū)分 Execution 內(nèi)存和 Storage 內(nèi)存

Execution 內(nèi)存和 Storage 內(nèi)存動態(tài)調(diào)整

具體的實(shí)現(xiàn)邏輯如下:
程序提交的時候我們都會設(shè)定基本的 Execution 內(nèi)存和 Storage 內(nèi)存區(qū)域(通過 spark.memory.storageFraction 參數(shù)設(shè)置)胳搞;
在程序運(yùn)行時卸例,如果雙方的空間都不足時称杨,則存儲到硬盤;將內(nèi)存中的塊存儲到磁盤的策略是按照 LRU 規(guī)則進(jìn)行的筷转。若己方空間不足而對方空余時姑原,可借用對方的空間;(存儲空間不足是指不足以放下一個完整的 Block)
Execution 內(nèi)存的空間被對方占用后,可讓對方將占用的部分轉(zhuǎn)存到硬盤呜舒,然后"歸還"借用的空間
Storage 內(nèi)存的空間被對方占用后锭汛,目前的實(shí)現(xiàn)是無法讓對方"歸還",因?yàn)樾枰紤] Shuffle 過程中的很多因素袭蝗,實(shí)現(xiàn)起來較為復(fù)雜唤殴;而且 Shuffle 過程產(chǎn)生的文件在后面一定會被使用到,而 Cache 在內(nèi)存的數(shù)據(jù)不一定在后面使用到腥。
注意朵逝,上面說的借用對方的內(nèi)存需要借用方和被借用方的內(nèi)存類型都一樣,都是堆內(nèi)內(nèi)存或者都是堆外內(nèi)存左电,不存在堆內(nèi)內(nèi)存不夠去借用堆外內(nèi)存的空間廉侧。

一個示例

現(xiàn)在我們提交的 Spark 作業(yè)關(guān)于內(nèi)存的配置如下:
--executor-memory 18g
由于沒有設(shè)置 spark.memory.fraction 和 spark.memory.storageFraction 參數(shù)
上圖很清楚地看到 Storage Memory 的可用內(nèi)存是 10.1GB,這個數(shù)是咋來的呢篓足?根據(jù)前面的規(guī)則段誊,我們可以得出以下的計(jì)算:
systemMemory = spark.executor.memory
reservedMemory = 300MB
usableMemory = systemMemory - reservedMemory
StorageMemory= usableMemory * spark.memory.fraction * spark.memory.storageFraction
如果我們把數(shù)據(jù)代進(jìn)去,得出以下的結(jié)果:
systemMemory = 18Gb = 19327352832 字節(jié)
reservedMemory = 300MB = 300 * 1024 * 1024 = 314572800
usableMemory = systemMemory - reservedMemory = 19327352832 - 314572800 = 19012780032
StorageMemory= usableMemory * spark.memory.fraction * spark.memory.storageFraction
= 19012780032 * 0.6 * 0.5 = 5703834009.6 = 5.312109375GB
不對啊栈拖,和上面的 10.1GB 對不上啊连舍。為什么呢?這是因?yàn)?Spark UI 上面顯示的 Storage Memory 可用內(nèi)存其實(shí)等于 Execution 內(nèi)存和 Storage 內(nèi)存之和涩哟,也就是 usableMemory * spark.memory.fraction:
StorageMemory= usableMemory * spark.memory.fraction
= 19012780032 * 0.6 = 11407668019.2 = 10.62421GB
還是不對索赏,這是因?yàn)槲覀冸m然設(shè)置了 --executor-memory 18g,但是 Spark 的 Executor 端通過 Runtime.getRuntime.maxMemory 拿到的內(nèi)存其實(shí)沒這么大贴彼,只有 17179869184 字節(jié)潜腻,所以 systemMemory = 17179869184,然后計(jì)算的數(shù)據(jù)如下:
systemMemory = 17179869184 字節(jié)
reservedMemory = 300MB = 300 * 1024 * 1024 = 314572800
usableMemory = systemMemory - reservedMemory = 17179869184 - 314572800 = 16865296384
StorageMemory= usableMemory * spark.memory.fraction
= 16865296384 * 0.6 = 9.42421875 GB
我們通過將上面的 16865296384 * 0.6 字節(jié)除于 1024 * 1024 * 1024 轉(zhuǎn)換成 9.42421875 GB器仗,和 UI 上顯示的還是對不上融涣,這是因?yàn)?Spark UI 是通過除于 1000 * 1000 * 1000 將字節(jié)轉(zhuǎn)換成 GB,如下:
systemMemory = 17179869184 字節(jié)
reservedMemory = 300MB = 300 * 1024 * 1024 = 314572800
usableMemory = systemMemory - reservedMemory = 17179869184 - 314572800 = 16865296384
StorageMemory= usableMemory * spark.memory.fraction
= 16865296384 * 0.6 字節(jié) = 16865296384 * 0.6 / (1000 * 1000 * 1000) = 10.1GB

我們設(shè)置了 --executor-memory 18g精钮,但是 Spark 的 Executor 端通過 Runtime.getRuntime.maxMemory 拿到的內(nèi)存其實(shí)沒這么大威鹿,只有 17179869184 字節(jié),這個數(shù)據(jù)是怎么計(jì)算的轨香?
Runtime.getRuntime.maxMemory 是程序能夠使用的最大內(nèi)存忽你,其值會比實(shí)際配置的執(zhí)行器內(nèi)存的值小。這是因?yàn)閮?nèi)存分配池的堆部分分為 Eden臂容,Survivor 和 Tenured 三部分空間科雳,而這里面一共包含了兩個 Survivor 區(qū)域根蟹,而這兩個 Survivor 區(qū)域在任何時候我們只能用到其中一個,所以我們可以使用下面的公式進(jìn)行描述:

ExecutorMemory = Eden + 2 * Survivor + Tenured
Runtime.getRuntime.maxMemory =  Eden + Survivor + Tenured
上面的 17179869184 字節(jié)可能因?yàn)槟愕?GC 配置不一樣得到的數(shù)據(jù)不一樣炸渡,但是上面的計(jì)算公式是一樣的

使用了堆外內(nèi)存

用了堆內(nèi)和堆外內(nèi)存
現(xiàn)在如果我們啟用了堆外內(nèi)存娜亿,情況咋樣呢?我們的內(nèi)存相關(guān)配置如下:
spark.executor.memory 18g
spark.memory.offHeap.enabled true
spark.memory.offHeap.size 10737418240
其實(shí) Spark UI 上面顯示的 Storage Memory 可用內(nèi)存等于堆內(nèi)內(nèi)存和堆外內(nèi)存之和蚌堵,計(jì)算公式如下:
堆內(nèi)
systemMemory = 17179869184 字節(jié)
reservedMemory = 300MB = 300 * 1024 * 1024 = 314572800
usableMemory = systemMemory - reservedMemory = 17179869184 - 314572800 = 16865296384
totalOnHeapStorageMemory = usableMemory * spark.memory.fraction
= 16865296384 * 0.6 = 10119177830

堆外
totalOffHeapStorageMemory = spark.memory.offHeap.size = 10737418240

StorageMemory = totalOnHeapStorageMemory + totalOffHeapStorageMemory
= (10119177830 + 10737418240) 字節(jié)
= (20856596070 / (1000 * 1000 * 1000)) GB
= 20.9 GB

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末买决,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吼畏,更是在濱河造成了極大的恐慌督赤,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泻蚊,死亡現(xiàn)場離奇詭異躲舌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)性雄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門没卸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秒旋,你說我怎么就攤上這事约计。” “怎么了迁筛?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵煤蚌,是天一觀的道長。 經(jīng)常有香客問我细卧,道長尉桩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任贪庙,我火速辦了婚禮蜘犁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘止邮。我一直安慰自己这橙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布农尖。 她就那樣靜靜地躺著析恋,像睡著了一般良哲。 火紅的嫁衣襯著肌膚如雪盛卡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天筑凫,我揣著相機(jī)與錄音滑沧,去河邊找鬼并村。 笑死,一個胖子當(dāng)著我的面吹牛滓技,可吹牛的內(nèi)容都是我干的哩牍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼令漂,長吁一口氣:“原來是場噩夢啊……” “哼膝昆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叠必,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤荚孵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后纬朝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體收叶,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年共苛,在試婚紗的時候發(fā)現(xiàn)自己被綠了判没。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡隅茎,死狀恐怖澄峰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情患膛,我是刑警寧澤摊阀,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站踪蹬,受9級特大地震影響胞此,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跃捣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一漱牵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧疚漆,春花似錦酣胀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至丸升,卻和暖如春铆农,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狡耻。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工墩剖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猴凹,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓岭皂,卻偏偏與公主長得像郊霎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子爷绘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 主要對 Executor 的內(nèi)存管理進(jìn)行分析书劝,下文中的 Spark 內(nèi)存均特指 Executor 的內(nèi)存 堆內(nèi)內(nèi)存...
    博弈史密斯閱讀 5,269評論 0 1
  • 內(nèi)容目錄 JVM 內(nèi)存使用架構(gòu)剖析 Spark 1.6.x以前版本內(nèi)存管理 Spark on Yarn 計(jì)算內(nèi)存使...
    熊_看不見閱讀 1,318評論 0 2
  • Spark 作為一個基于內(nèi)存的分布式計(jì)算引擎,其內(nèi)存管理模塊在整個系統(tǒng)中扮演著非常重要的角色土至。理解 Spark 內(nèi)...
    Alukar閱讀 1,015評論 0 7
  • Spark 作為一個以擅長內(nèi)存計(jì)算為優(yōu)勢的計(jì)算引擎庄撮,內(nèi)存管理方案是其非常重要的模塊; Spark的內(nèi)存可以大體歸為...
    達(dá)微閱讀 287評論 0 0
  • 今天下午毙籽,又有朋友在微信群里發(fā)起一個微信投票的鏈接洞斯,希望我們能為一名醫(yī)生投票,競選優(yōu)秀醫(yī)師坑赡,并一并發(fā)了紅包烙如。 自從...
    大學(xué)生Andrew閱讀 1,901評論 0 2