麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 開發(fā) > 綜合 > 正文

那些年我們在spark SQL上踩過的坑

2024-07-21 02:53:19
字體:
供稿:網(wǎng)友

做了一年延云YDB的開發(fā),這一年在使用spark上真心踩了不少坑,總結(jié)一下,希望對大家有所幫助。

spark 內(nèi)存泄露

1.高并發(fā)情況下的內(nèi)存泄露的具體表現(xiàn)

很遺憾,spark的設(shè)計架構(gòu)并不是為了高并發(fā)請求而設(shè)計的,我們嘗試在網(wǎng)絡(luò)條件不好的集群下,進行100并發(fā)的查詢,在壓測3天后發(fā)現(xiàn)了內(nèi)存泄露。

a)在進行大量小SQL的壓測過程中發(fā)現(xiàn),有大量的activejob在spark ui上一直處于pending狀態(tài),且永遠不結(jié)束,如下圖所示

b)并且發(fā)現(xiàn)driver內(nèi)存爆滿

c)用內(nèi)存分析分析工具分析了下

2.高并發(fā)下AsynchronousListenerBus引起的WEB UI的內(nèi)存泄露

短時間內(nèi) SPARK 提交大量的SQL ,而且SQL里面存在大量的 union與join的情形,會創(chuàng)建大量的event對象,使得這里的 event數(shù)量超過10000個event ,一旦超過10000個event就開始丟棄 event,而這個event是用來回收 資源的,丟棄了 資源就無法回收了。 針對UI頁面的這個問題,我們將這個隊列長度的限制給取消了。

 

3.AsynchronousListenerBus本身引起的內(nèi)存泄露

抓包發(fā)現(xiàn)

 

這些event是通過post方法傳遞的,并寫入到隊列里

 

但是也是由一個單線程進行postToAll的

 

但是在高并發(fā)情況下,單線程的postToAll的速度沒有post的速度快,會導(dǎo)致隊列堆積的event越來越多,如果是持續(xù)性的高并發(fā)的SQL查詢,這里就會導(dǎo)致內(nèi)存泄露

 

接下來我們在分析下postToAll的方法里面,那個路徑是最慢的,導(dǎo)致事件處理最慢的邏輯是那個?

 

可能您都不敢相信,通過jstack抓取分析,程序大部分時間都阻塞在記錄日志上

 

可以通過禁用這個地方的log來提升event的速度

 

log4j.logger.org.apache.spark.scheduler=ERROR

 

 

 

4.高并發(fā)下的Cleaner的內(nèi)存泄露

       說道這里,Cleaner的設(shè)計應(yīng)該算是spark最糟糕的設(shè)計。spark的ContextCleaner是用于回收與清理已經(jīng)完成了的 廣播boradcast,shuffle數(shù)據(jù)的。但是高并發(fā)下,我們發(fā)現(xiàn)這個地方積累的數(shù)據(jù)會越來越多,最終導(dǎo)致driver內(nèi)存跑滿而掛掉。

l我們先看下,是如何觸發(fā)內(nèi)存回收的

      沒錯,就是通過System.gc() 回收的內(nèi)存,如果我們在jvm里配置了禁止執(zhí)行System.gc,這個邏輯就等于廢掉(而且有很多jvm的優(yōu)化參數(shù)一般都推薦配置禁止system.gc 參數(shù))

lclean過程

這是一個單線程的邏輯,而且每次清理都要協(xié)同很多機器一同清理,清理速度相對來說比較慢,但是SQL并發(fā)很大的時候,產(chǎn)生速度超過了清理速度,整個driver就會發(fā)生內(nèi)存泄露。而且brocadcast如果占用內(nèi)存太多,也會使用非常多的本地磁盤小文件,我們在測試中發(fā)現(xiàn),高持續(xù)性并發(fā)的情況下本地磁盤用于存儲blockmanager的目錄占據(jù)了我們60%的存儲空間。

 

我們再來分析下 clean里面,那個邏輯最慢

真正的瓶頸在于blockManagerMaster里面的removeBroadcast,因為這部分邏輯是需要跨越多臺機器的。

 

針對這種問題,

l我們在SQL層加了一個SQLWAITING邏輯,判斷了堆積長度,如果堆積長度超過了我們的設(shè)定值,我們這里將阻塞新的SQL的執(zhí)行。堆積長度可以通過更改conf目錄下的ya100_env_default.sh中的ydb.sql.waiting.queue.size的值來設(shè)置。

l建議集群的帶寬要大一些,萬兆網(wǎng)絡(luò)肯定會比千兆網(wǎng)絡(luò)的清理速度快很多。

l給集群休息的機會,不要一直持續(xù)性的高并發(fā),讓集群有間斷的機會。

l增大spark的線程池,可以調(diào)節(jié)conf下的spark-defaults.conf的如下值來改善。

 

 

5.線程池與threadlocal引起的內(nèi)存泄露

       發(fā)現(xiàn)spark,hive,lucene都非常鐘愛使用threadlocal來管理臨時的session對象,期待SQL執(zhí)行完畢后這些對象能夠自動釋放,但是與此同時spark又使用了線程池,線程池里的線程一直不結(jié)束,這些資源一直就不釋放,時間久了內(nèi)存就堆積起來了。

針對這個問題,延云修改了spark關(guān)鍵線程池的實現(xiàn),更改為每1個小時,強制更換線程池為新的線程池,舊的線程數(shù)能夠自動釋放。

 

6.文件泄露

      您會發(fā)現(xiàn),隨著請求的session變多,spark會在hdfs和本地磁盤創(chuàng)建海量的磁盤目錄,最終會因為本地磁盤與hdfs上的目錄過多,而導(dǎo)致文件系統(tǒng)和整個文件系統(tǒng)癱瘓。在YDB里面我們針對這種情況也做了處理。

 

7.deleteONExit內(nèi)存泄露

 

為什么會有這些對象在里面,我們看下源碼

 

8.JDO內(nèi)存泄露

多達10萬多個JDOPersistenceManager

 

 

 

9.listerner內(nèi)存泄露

通過debug工具監(jiān)控發(fā)現(xiàn),spark的listerner隨著時間的積累,通知(post)速度運來越慢

發(fā)現(xiàn)所有代碼都卡在了onpostevent上

 

jstack的結(jié)果如下

 

研究下了調(diào)用邏輯如下,發(fā)現(xiàn)是循環(huán)調(diào)用listerners,而且listerner都是空執(zhí)行才會產(chǎn)生上面的jstack截圖

 

通過內(nèi)存發(fā)現(xiàn)有30多萬個linterner在里面

 

發(fā)現(xiàn)都是大多數(shù)都是同一個listener,我們核對下該處源碼

 

最終定位問題

確系是這個地方的BUG ,每次創(chuàng)建JDBC連接的時候 ,spark就會增加一個listener, 時間久了,listener就會積累越來越多  針對這個問題 我簡單的修改了一行代碼,開始進入下一輪的壓測

 

 

 

二十二、spark源碼調(diào)優(yōu)

      測試發(fā)現(xiàn),即使只有1條記錄,使用 spark進行一次SQL查詢也會耗時1秒,對很多即席查詢來說1秒的等待,對用戶體驗非常不友好。針對這個問題,我們在spark與hive的細節(jié)代碼上進行了局部調(diào)優(yōu),調(diào)優(yōu)后,響應(yīng)時間由原先的1秒縮減到現(xiàn)在的200~300毫秒。

      

以下是我們改動過的地方

1.SessionState 的創(chuàng)建目錄 占用較多的時間

 

另外使用Hadoop namenode HA的同學(xué)會注意到,如果第一個namenode是standby狀態(tài),這個地方會更慢,就不止一秒,所以除了改動源碼外,如果使用namenode ha的同學(xué)一定要注意,將active狀態(tài)的node一定要放在前面。

2.HiveConf的初始化過程占用太多時間

頻繁的hiveConf初始化,需要讀取core-default.xml,hdfs-default.xml,yarn-default.xml

,maPReduce-default.xml,hive-default.xml等多個xml文件,而這些xml文件都是內(nèi)嵌在jar包內(nèi)的。

第一,解壓這些jar包需要耗費較多的時間,第二每次都對這些xml文件解析也耗費時間。

 

 

 

3.廣播broadcast傳遞的hadoop configuration序列化很耗時

lconfiguration的序列化,采用了壓縮的方式進行序列化,有全局鎖的問題

lconfiguration每次序列化,傳遞了太多了沒用的配置項了,1000多個配置項,占用60多Kb。我們剔除了不是必須傳輸?shù)呐渲庙椇螅s減到44個配置項,2kb的大小。

 

 

 

4.對spark廣播數(shù)據(jù)broadcast的Cleaner的改進

 

由于SPARK-3015 的BUG,spark的cleaner 目前為單線程回收模式。

大家留意spark源碼注釋

 

其中的單線程瓶頸點在于廣播數(shù)據(jù)的cleaner,由于要跨越很多臺機器,需要通過akka進行網(wǎng)絡(luò)交互。如果回收并發(fā)特別大,SPARK-3015 的bug報告會出現(xiàn)網(wǎng)絡(luò)擁堵,導(dǎo)致大量的 timeout出現(xiàn)。

為什么回收量特變大呢? 其實是因為cleaner 本質(zhì)是通過system.gc(),定期執(zhí)行的,默認積累30分鐘或者進行了gc后才觸發(fā)cleaner,這樣就會導(dǎo)致瞬間,大量的akka并發(fā)執(zhí)行,集中釋放,網(wǎng)絡(luò)不瞬間癱瘓才不怪呢。但是單線程回收意味著回收速度恒定,如果查詢并發(fā)很大,回收速度跟不上cleaner的速度,會導(dǎo)致cleaner積累很多,會導(dǎo)致進程OOM(YDB做了修改,會限制前臺查詢的并發(fā))。不論是OOM還是限制并發(fā)都不是我們希望看到的,所以針對高并發(fā)情況下,這種單線程的回收速度是滿足不了高并發(fā)的需求的。對于官方的這樣的做法,我們表示并不是一個完美的cleaner方案。并發(fā)回收一定要支持,只要解決akka的timeout問題即可。所以這個問題要仔細分析一下,akka為什么會timeout,是因為cleaner占據(jù)了太多的資源,那么我們是否可以控制下cleaner的并發(fā)呢?比如說使用4個并發(fā),而不是默認將全部的并發(fā)線程都給占滿呢?這樣及解決了cleaner的回收速度,也解決了akka的問題不是更好么?針對這個問題,我們最終還是選擇了修改spark的ContextCleaner對象,將廣播數(shù)據(jù)的回收 改成多線程的方式,但現(xiàn)在了線程的并發(fā)數(shù)量,從而解決了該問題。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 国产在线观看一区二区三区 | 久久免费视频一区二区三区 | 天天干天天碰 | 久久亚洲精品视频 | 久久网综合 | 欧美日韩在线影院 | 91精品国产综合久久男男 | 国产99精品 | 97人人草 | 国产一级做a爰片在线看 | av在线免费看片 | 久久亚洲线观看视频 | 国产免费久久久久 | 亚洲第一成人在线 | 欧洲成人综合网 | 龙的两根好大拔不出去h | 最近免费观看高清韩国日本大全 | 成人一级毛片 | 逼片| 久久久涩| 欧美精品欧美 | 欧美性猛交一区二区三区精品 | 高清视频91| 欧美三级欧美成人高清www | 久久精品一二三区 | 99爱福利视频在线观看 | av日韩一区二区三区 | 成人一级黄色片 | 最新av在线播放 | 亚洲第一成人在线观看 | 一级片a| 中文在线观看视频 | 韩国三级日本三级香港三级黄 | 国产视频软件在线 | 成人视屏在线 | xxxx69hd一hd72 | 国产一区二区三区视频在线观看 | 九一传媒在线观看 | 九九精品在线观看视频 | 亚洲一级成人 | 国产欧美精品一区二区三区四区 |