學習筆記:Twitter核心數據類庫團隊的Hadoop優化經驗

1、來源

Streaming Hadoop Performance Optimization at Scale, Lessons Learned at Twitter正則表達式

(Data platform @Twitter)性能優化

2、觀後感

2.1 概要

此稿介紹了Twitter的核心數據類庫團隊,在使用Hadoop處理離線任務時,使用的性能分析方法,及由此發現的問題和優化手段,對如何使用 JVM/HotSpot profile(-Xprof)分析Hadoop Job的方法調用開銷、Hadoop配置對象的高開銷、MapReduce階段的排序中對象序列化/反序列的高開銷問題及優化等給出了實際可操做的方案。markdown

其介紹了Apache Parquet這一面向列的存儲格式,併成功應用於列投影(column project),配合predicated push-down技術,過濾不須要的列,極大提升了數據壓縮比和序列化/反序列化的性能。
純乾貨。
32個贊!數據結構

2.2 優化總結

1) Profile!(-Xprofile)性能優化不能靠猜,而應靠分析!
2) 序列化開銷很大,可是Hadoop裏有許多序列化(操做)!
3) 根據特定(數據)訪問模式,選擇不一樣的存儲格式(面向行仍是面向列)!
4) 使用column projection。
5) 在Hadoop的MR階段,排序開銷很大,使用Raw Comparators以下降開銷。
注:此排序針對如Comparator,其會引起序列化/反序列化操做。
6) I/O並不必定就是瓶頸。必要的時候要多I/O換取更少的CPU計算。ide

JVM/HotSpot原生profile能力(-Xprof),其優勢以下:
1) 低開銷(使用Stack sampling)。
2) 能揭示開銷最大的方法調用。
3) 使用標準輸出(Stdout)將結果直接寫入Task Logs。函數

2.3 Hadoop的配置對象

這裏寫圖片描述

1) Hadoop的Configuration Object開銷出人意料的高。
2) Conf的操做看起來就像一個HashMap的操做。oop

這裏寫圖片描述

3) 構造函數:讀取+解壓+分析一個來自磁盤的XML文件post

這裏寫圖片描述

4) get()調用引發正則表達式計算,變量替換。性能

這裏寫圖片描述

5) 若是在循環中對上述等方法進行調用,或者每秒一次調用,開銷很高.某些(Hadoop)Jobs有30%的時間花在配置相關的方法上!(的確是出人意料的高開銷)

這裏寫圖片描述

總之,沒有profile(-Xprof)技術,不可能獲取以上洞察,也不可能輕易找到優化的契機和方向,須要使用profile技術來獲知I/O和CPU誰纔是真正的瓶頸。

2.4 中間結果的壓縮

  • Xprof揭示了spill線程中的壓縮和解壓縮操做消耗了大量時間。
  • 中間結果是臨時的。
  • 使用lz4方法取代lzo level 3,減小了30%多的中間數據,使其能被更快地讀取。
  • 並使得某些大型Jobs提速150%。

這裏寫圖片描述

2.5 對記錄的序列化和反序列,會成爲Hadoop Job中開銷最高的操做!

這裏寫圖片描述

2.6 對記錄的序列化是CPU敏感的,相對比之下,I/O都不算什麼了!

這裏寫圖片描述

2.7 如何消除或者減少序列化/反序列化引發的(CPU)開銷?

2.7.1 使用Hadoop的Raw Comparator API(來比較元素大小)

開銷分析:以下圖所示,Hadoop的MR在map和reduce階段,會反序列化map結果的keys以在此階段進行排序。

這裏寫圖片描述

(反序列化操做)開銷很大,特別是對於複雜的、非原語的keys,而這些keys又很經常使用。

這裏寫圖片描述

Hadoop提供了一個RawComparator API,用於對已序列化的(原始的)數據(字節級)進行比較:

這裏寫圖片描述

這裏寫圖片描述

不幸的是,須要親手實現一個自定義的Comparator。

如今,假設數據已序列化後的字節流,自己是易於比較的:
Scala有個很拉風的API,Scala還有一些宏能夠產生這些API,以用於:
Tuples , case classes , thrift objects , primitives , Strings,等等數據結構。

這裏寫圖片描述

怎麼拉風法呢?首先,定義一個密集且易於比較的數據序列化(字節)格式:

這裏寫圖片描述

其次,生成一個用於比較的方法,以利用這種數據格式的優點:

這裏寫圖片描述

下圖是採用上述優化手段後的比較開銷對比:

這裏寫圖片描述

提速到150%!
接着優化!

2.7.2 使用column projection

不要讀取不須要的列:

這裏寫圖片描述

1) 可以使用Apache Parquet(列式文件格式)。

這裏寫圖片描述

2) 使用特別的反序列化手段能夠在面向行的存儲中跳過一些不須要的字段。

面向列的存儲中,一整列按順序存儲(而不是向面向行的存儲那樣,列是分開存儲的):

這裏寫圖片描述

能夠看到,面向列的存儲,使得同類型的字段被順序排在一塊兒(易於壓縮):

這裏寫圖片描述

採用Lzo + Parquet,文件小了2倍多!

2.7.3 Apache Parquet

1) 按列存儲,能夠有效地進行列投影(column projection)。
2) 可按需從磁盤上讀取列。
3) 更重要的是:能夠只反序列化須要的列!

這裏寫圖片描述

看下效果:

這裏寫圖片描述

能夠看到,列數越少,Parquet的威力越大,到40列時,其效率反而不如Lzo Thrift。

  • 在讀取全部列的狀況下,Parquet通常比面向行的存儲慢。
  • Parquet是種密集格式,其讀性能和模式中列的數目相關,空值讀取也消耗時間。
  • 而面向行的格式(thrift)是稀疏的,因此其讀性能和數據的列數相關,空值讀取是不消耗時間的。

這裏寫圖片描述

跳過不須要的字段,以下所示:

這裏寫圖片描述

  • 雖然,沒有下降I/O開銷
  • 可是,能夠僅將感興趣的字段編碼進對象中
  • 相對於從磁盤讀取 + 略過編碼後字節的開銷,在解碼字符串時所花的CPU時間要高的多!

看下各類列映射方案的對比:

這裏寫圖片描述

Parquet Thrift還有不少優化空間;Parquet在選取的列數小於13列以前,是更快的;此模式相對平坦,且大多數列都被生成了。

  • 還能夠採用Predicate Push-Down策略,使得Parquet能夠跳過一些不知足過濾條件的數據記錄。
  • Parquet存儲了一些統計信息,好比記錄的chunks,因此在某些場景下,能夠經過對這些統計信息進行讀取分析,以跳過整個數據塊(chunk)。

這裏寫圖片描述

注:左圖爲column projection,中圖爲predicate push-down過濾,右圖爲組合效果。能夠看到不少字段被跳過了,那絕壁能夠優化序列化/反序列化的效率。

下圖則展現了push-down過濾 + parquet的優化成效:

這裏寫圖片描述

2.8 結語

感嘆:Twitter真是一家偉大的公司!上述優化手段,集羣越大、Hadoop Job越多,效果越明顯!

相關文章
相關標籤/搜索