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


一、來源

Streaming Hadoop Performance Optimization at Scale, Lessons Learned at Twitter

(Data platform @Twitter)

二、觀后感

2.1 概要###

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

其介紹了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計算。

JVM/HotSpot原生profile能力(-Xprof),其優點如下:

  1. 低開銷(使用Stack sampling)。
  2. 能揭示開銷最大的方法調用。
  3. 使用標准輸出(Stdout)將結果直接寫入Task Logs。

2.3 Hadoop的配置對象###

這里寫圖片描述

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

這里寫圖片描述

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

這里寫圖片描述

  1. get()調用引起正則表達式計算,變量替換。

這里寫圖片描述

  1. 如果在循環中對上述等方法進行調用,或者每秒一次調用,開銷很高.某些(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(列式文件格式)。

這里寫圖片描述

  1. 使用特別的反序列化手段可以在面向行的存儲中跳過一些不需要的字段。

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

這里寫圖片描述

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

這里寫圖片描述

采用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越多,效果越明顯!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM