search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

如何處理大數據性能問題?

下一代開源大數據框架如spark和Flink的目標是達到大規模并行處理資料庫如Netezza那樣的性能和良好的用戶體驗
由於所有主流的大數據框架(Hadoop,spark,Flink)使用JVM,所有他們都有著兩個JVM限制:
1、Java對象消耗的內存遠大於對象中所有屬性的大小
2、Major GC 的停頓會使得性能下降,尤其是當你嘗試緩存更多的數據(Java對象)以便後期對數據進行純內存處理
所有Flink,Spark,Hadoop為高性能引入的工程技術主要目的就是為了儘可能的減少這兩方面的影響.本文將為你展示這些技術。
在所有性能改進的之外,Alexey Grishchenko所寫的如下blog給了我們一個清晰的提醒,雖然基於Java的大數據框架在性能方面已經有很大提升,但是要追上大規模并行處理系統的性能還有很長一段路要走
性能的80/20原則
不是所有操作所需要的開銷都是一樣的,極少數的操作產生了很高的性能開銷,許多大數據框架常用操作組合是:
1、壓縮vs不壓縮-這直接影響到數據被讀出和寫入的速率,不同的壓縮方式/演算法消耗的cpu資源差異很大
2、排序-大數據處理基本都會有"reduce"操作,而排序在map-reduce處理方式中則是"reduce"階段的關鍵。由於"join"操作會依賴於"reduce",所以對key的排序也會關係到"join"的操作上
3、清洗-"reduce"階段第二個最重要的操作就是清洗了,清洗操作也是關聯操作的關鍵
4、關聯-只有map階段的job通常有很好的性能.但當有reduce階段的時候性能會變成一個需要考慮的重要因素。一個reduce操作包含了關聯,在只有map階段的任務中可以使用廣播關聯,但廣播關聯通常在關聯的一端數據量足夠小的時候才用,這個很小的數據集被廣播到所有節點,由一個hashmap的數據結構來維護同時由關聯鍵來索引。另外一端大一點的數據集通過使用關聯鍵在這個內存中的hashmap中查找相應的記錄。當只有map階段時,即使兩端數據集都比較大也可以按照關聯鍵來排序,Pig框架就是充分利用了這一點,被稱為"merge-joins"技術,它會把兩邊的數據集都在lock-step中遍歷,然後在map階段中關聯起來(這裡實際上有一個預先索引的過程)。當然有關聯鍵進行自然排序對數據集是很少見的,在關聯大數據集的時候reduce操作還是必不可少的。
搞定上面的這些問題是使得大數據處理效率變得更快的關鍵。
性能約束和JVM特徵
就像前面提到的,Java在性能方面引入的兩個約束因素:
1、Java對象的存儲開銷不容小覷
2、使用大量生存周期很短的對象會使得吞吐量性能下降,因為大量的時間會花在Major GC上
只在JVM堆棧上操作處理大數據很容易導致內存溢出錯誤,這會使得JVM進程被殺死退出(不像其他錯誤可以被處理).這是大數據應用中最常見的一個性能問題.
比如,在一個有許多記錄但是只有少數鍵值對能夠發生關聯的不均衡數據集中,當所有的鍵值都保存在內存中時reduce操作會失敗
從索引技術可以避免在reduce階段時把所有的鍵值放到內存中,圖像應用就是屬於這類應用中的一種.
這就是大數據框架在使用內存時小心謹慎的重要原因了,比如磁碟溢出技術.這雖然會影響性能,但是會使得框架足夠健壯來處理不同的負載.
比如,Pig框架會把數據保存在磁碟上,DataBag介面的實現及其廣泛的應用在Pig中,當tuples的數量達到一個預先定義的值時會把數據刷到磁碟上(默認是20000)
JVM 存儲開銷
在Java堆棧中一個典型的對象存儲由如下組成-
1.對象頭-只有幾個位元組用作維護信息.Hotspot 版本的VM使用8個位元組來表示一個普通對象的頭,另外再使用4個位元組來表示數組對象的長度
2.原始類型-原始類型也需要位元組來存儲.比如boolean類型需要1個位元組,char需要兩個位元組,int需要4個。
3.引用類型存儲-引用類型佔用4個位元組
4.空佔位符-每個對象存放時總位元組數是8的倍數,所有這中間總是有空的佔位符
如圖1所示,一個Java類對象的實例包含了一個原始類型boolean實例所佔用的8個位元組用作頭,另外一個位元組表示boolean實例本身,剩餘7個位元組就會被空佔位符填滿。

圖1:一個只有一個boolean實例變數的java類在內存中的佔用情況
這個例子證實了一個普通java對象很大的存儲開銷,並且隨著如hashmap 和list這樣複雜對象變得非常大
JVM 存儲開銷影響序列化和反序列化
在大數據範圍內發生如下情形時你肯定需要序列化和反序列化:
1、Mapper輸出結果到本地磁碟
2、Mappers從本地磁碟讀出數據來做map端的排序
3、Reducers從mapper 節點上獲取排序和清洗好的結果
在上面的每種情形中,實際的數據量都比原始位元組表示的要多很多
Java 對象的存儲開銷影響到內存如何有效的使用分級緩存。即使所有你想要的數據在內存中,L1/L2/L3級別的緩存也不可能大到能裝下這些所有的數據,這也會使得緩存在過渡的交換之中從而降低性能。
JVM 存儲開銷影響GC
JavaGC最關鍵的是要更多的對象在年輕代時就被收集. Java堆棧被劃分為兩個區域,年輕代和年老代。一般來說年輕代佔用整個堆棧空間的20%,而年老代佔用了剩餘的80%。當一個對象第一次被創建時,他們被分配在年輕代,當年輕代滿了的時候,minorGC就會執行。在這個過程中不再被引用的對象就被清除掉,剩餘的還在被引用的就移到年老代。當年老代被填滿時,major GC最終就會發生。Major收集演算法會遍歷在圖中的每個對象,從老年代中回收內存。注意這只是非常簡單的描述了GC的過程,更加詳細的了解可以上官方網站查找。
... ...


熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦