HBase 管理,性能調優

Java GC 和 HBase 堆設置

由於 HBase 運行在 JVM,JVM 的 Garbage Collection(GC) 設置對於 HBase 流暢的運行,更高的性能是很是重要的,除了配置 HBase 堆設置的指導方針以外。有 HBase 進程輸出到它們的 GC 日誌中是一樣重要的,而且它們基於  GC  日誌的輸出調整 JVM  設置。php

我將描述最重要的 HBase JVM 堆設置,也描述怎樣是它生效以及理解 GC 日誌,在這方面。我將覆蓋一些指導方針來調整 HBase 的 Java GC 設置。java

準備工做

登錄你的 HBase region 服務器。nginx

怎樣作

如下被建議用於 Java GC 和 HBase 堆設置:git

  1. 經過編輯 hbase-env.sh 文件給 HBase 足夠大的堆大小。好比,如下片斷給 HBase 配置一個 8000-MB 的堆:github

    $ vi $HBASE_HOME/conf/hbase-env.shexport HBASE_HEAPSIZE=8000
  2. 經過如下命令使得 GC 日誌生效:算法

    export HBASE_OPTS="$HBASE_OPTS -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/usr/local/hbase/logs/gc-hbase.log"
  3. 把如下代碼加入來比默認更早的開始 Concurrent-Mark-Sweep GC(CMS)shell

    $ vi $HBASE_HOME/conf/hbase-env.shexport HBASE_OPTS="$HBASE_OPTS -XX:CMSInitiatingOccupancyFraction=60"
  4. 在集羣中同步變動並重啓 HBase。apache

  5. 檢查輸出到指定日誌文件中(/usr/local/hbase/logs/gc-hbase.log)的 GC 日誌。GC 日誌看起來像如下屏幕截圖:ruby

此處輸入圖片的描述

它怎樣工做

在步驟 1 中,咱們配置 HBase 堆內存大小。默認,HBase 使用 1GB 的堆,這對於現代的機器來講過低了。對於 HBase 來講,比 4GB 更大是好的。咱們建議 8GB 或更大,可是低於 16 GB。bash

在步驟 2 中,咱們是 JVM 日誌生效,使用這個設置,你能夠獲取 region 服務器的 JVM 日誌,和咱們在步驟 5 中展現的相似。關於 JVM 內存分配和垃圾回收的基礎知識是被要求的,爲了明白日誌輸出。如下是 JVM 分代垃圾收集系統的圖表:

此處輸入圖片的描述

這裏有 3 個堆分代:Perm(或是 Permanent)代【永久代】,Old Generation 代【老年代】,和 Young 代【年輕代】。年輕代由三個獨立的空間組成,Eden 空間和兩個 survivor 空間,S0S1

一般,對象被分配在年輕代的 Eden 空間,若是一個分配失敗(Eden 滿了),全部 java 線程中止,而且一個年輕代 GC(Minor GC)被調用。全部在年輕代存活的對象(EdenS0 空間)被拷貝到 S1 空間。若是 S1 空間滿了,對象被拷貝(提高)到老年代。當一個提高失敗,老年代被收集(Major/Full GC)。永久代和老年代一般一塊兒被收集。永久代被用於在存放類和對象中定義的方法。

回到咱們示例的步驟 5,上述選項產出的 minor GC 輸出爲如下形式:

<timestamp>: [GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] 
<starting occupancy3> -> <ending occupancy3>, <pause time3> secs] 
[Times: <user time> <system time>, <real time>]

在這個輸出中:

  • timestamp 是 GC 發生的時間,相對於應用的啓動時間。

  • collector 是 collector 用於 minor collection 的內部名字

  • starting occupancy1 是年輕代在垃圾回收前的佔用

  • ending occupancy1 是年輕代在垃圾回收後的佔用

  • pause time1 是 minor collection 中斷的時間

  • starting occupancy3 是在垃圾回收前整個堆的佔用

  • ending occupancy3 是在垃圾回收後整個堆的佔用

  • pause time3 是整個垃圾回收的中斷時間,這包括 major collection。

  • [Time:] 解釋了花費在垃圾收集的時間,用戶時間,系統時間,實際時間。

在步驟 5 中咱們輸出的第一行代表了是一個 minor GC,中斷了 JVM 0.0764200 秒,它已經把年輕代的空間從 14.8MB 下降到 1.6MB。

接着,咱們看看 CMS GC 日誌,HBase 使用 CMS GC 做爲它默認的老年代垃圾回收器。

CMS GC 執行如下步驟:

  1. 初始化標記

  2. 併發標記

  3. 重複標記

  4. 併發休眠

CMS 僅僅在它初始化標記和重複標記的階段中斷應用進程。在併發標記和睡眠階段,CMS 線程隨着應用線程一塊兒運行。

在該示例的第二行代表了 CMS 初始化標記花費了 0.0100050 秒,併發標記花費了 6.496 秒。注意,併發標記,Java 不會被中斷。

在 GC 日誌的早期屏幕截圖中,在行開始於 1441.435: [GC[YG occupancy:…] 的地方有一箇中斷。這裏的中斷是 0.0413960 秒,用於重複標記堆。以後,你能夠看到睡眠開始了。CMS 睡眠花費了 3.446 秒,可是堆大小在這裏沒有變化太多(它繼續佔據大約 150MB)。

這裏的調整點是使得全部的中斷時間更低。爲了保持中斷時間更低,你須要使用 -XX:NewSize 和 -XX:MaxNewSize JVM 參數調全年輕代空間大小,爲了將它們設置爲相對較小的值(好比,調高几百 MB)。若是服務器有更多的 CPU 資源,咱們建議經過設置 -XX:+UseParNewGC 選項使用 Parallel New Collector。你或許也想爲你的年輕代調整  parallel GC 線程數量,經過  -XX:ParallelGCThreads JVM 參數。

咱們建議加入上述設置到  HBASE_REGIONSERVER_OPTS 變量中,代替 hbase-env.sh 文件中的 HBASE_OPTS 變量。HBASE_REGIONSERVER_OPTS  僅僅影響 region 服務器的進程,這很是好,由於 HBase master  既不處理重型任務也不參與數據處理。

對於老年代來講, concurrent collection (CMS) 一般不能被加速,可是它能夠更早的開始。當分配在老年代的空間比率超過了一個閥值,CMS 開始運行。這個閥值是被收集器自動計算的。對於有些狀況,特別是在加載期間,若是 CMS 開始的太晚,HBase 或許會直接進行 full garbage collection。爲了不這個,咱們建議設置  -XX:CMSInitiatingOccupancyFraction JVM 參數來精確指定在多少百分比 CMS 應該被開始,正如咱們在步驟 3 中作的那樣。在 百分之 60 或 70 開始是一個好的實踐。當老年代使用 CMS,默認的年輕代 GC 將被設置成 Parallel New Collector。

不止這些

若是你以前使用的是 HBase  0.92 版本,考慮使用 MemStore-Local 分配 Buffer 來預防老年代堆碎片,在頻繁寫的負載下:

$ vi $HBASE_HOME/conf/hbase-site.xml  <property>
    <name>hbase.hregion.memstore.mslab.enabled</name>
    <value>true</value>
  </property>

這個特性在 HBase 0.92 中是默認開啓的。

使用壓縮

HBase 另一個最重要的特性就是使用壓縮。它是很是重要的,由於:

  • 壓縮下降從 HDFS 讀寫的字節數

  • 節約磁盤空間

  • 當從一個遠程服務器獲取數據的時候,提高了網絡帶寬的效率

HBase 支持 GZip 和 LZO 格式,個人建議是使用  LZO  壓縮算法,由於它解壓數據快而且 CPU 使用率低。更好的壓縮比是系統的首選,你應該考慮 GZip。

不幸的是,HBase 不能使用 LZO,由於 license 問題。HBase 是 Apache-licensed,然而 LZO 是 GPL-licensed。所以,咱們須要本身安裝 LZO。咱們將使用 hadoop-lzo 庫,給 Hadoop 帶來了變形的 LZO 算法。

在這方面,咱們將描述怎樣安裝 LZO 和怎樣配置 HBase 使用  LZO 壓縮。

準備工做

確保在 hadoop-lzo 被構建的機器上 Java 安裝了。Apache Ant 被要求用來從源碼構建 hadoop-lzo。經過運行一下命令來安裝  Ant:

$ sudo apt-get -y install ant

集羣中的全部節點須要有原生的 LZO 庫被安裝。你能夠經過使用如下命令安裝:

$ sudo apt-get -y install liblzo2-dev

怎樣作

咱們將使用 hadoop-lzo 庫來給 HBase 添加 LZO 壓縮支持:

  1. https://github.com/toddlipcon/hadoop-lzo 獲取最新的  hadoop-lzo 源碼

  2. 從源碼構建原生的 hadoop-lzo 庫。依賴於你的 OS,你應該選擇構建 32-bit 或 64-bit 的二進制包。好比,爲了構建  32-bit 二進制包,運行如下命令:

    $ export JAVA_HOME="/usr/local/jdk1.6"$ export CFLAGS="-m32"$ export CXXFLAGS="-m32"$ cd hadoop-lzo$ ant compile-native$ ant jar

    這些命令將建立 hadoop-lzo/build/native  目錄和 hadoop-lzo/build/hadoop-lzo-x.y.z.jar 文件。爲了構建 64-bit 二進制包,你須要改變  CFLAGS 和 CXXFLAGS 成 m64。

  3. 拷貝構建的包到你master 節點的 $HBASE_HOME/lib 和 $HBASE_HOME/lib/native 目錄:

    hadoop@master1$ cp hadoop-lzo/build/hadoop-lzo-x.y.z.jar     $HBASE_HOME/lib
    hadoop@master1$ mkdir $HBASE_HOME/lib/native/Linux-i386-32hadoop@master1$ cp  hadoop-lzo/build/native/Linux-i386-32/lib/* $HBASE_HOME/lib/native/Linux-i386-32/

    對於一個 64-bit OS,把 Linux-i386-32 改變成(在前面步驟中)  Linux-amd64-64。

  4. 添加 hbase.regionserver.codecs 的配置到你的 hbase-site.xml 文件:

    hadoop@master1$ vi $HBASE_HOME/conf/hbase-site.xml<property><name>hbase.regionserver.codecs</name><value>lzo,gz</value></property>
  5. 在集羣中同步 $HBASE_HOME/conf 和 $HBASE_HOME/lib 目錄。

  6. HBase ships 使用一個工具來測試壓縮是否被正確設置了。使用這個工具來在集羣中的每一個節點上測試 LZO 設置。若是一切都正確無誤的配置了,你將獲得成功的輸出:

    hadoop@client1$ $HBASE_HOME/bin/hbase org.apache.hadoop.hbase.util.CompressionTest /tmp/lzotest lzo12/03/11 11:01:08 INFO hfile.CacheConfig: Allocating LruBlockCache with maximum size 249.6m12/03/11 11:01:08 INFO lzo.GPLNativeCodeLoader: Loaded native gpl library12/03/11 11:01:08 INFO lzo.LzoCodec: Successfully loaded & initialized native-lzo library [hadoop-lzo rev Unknown build revision]12/03/11 11:01:08 INFO compress.CodecPool: Got brand-new compressor12/03/11 11:01:18 INFO compress.CodecPool: Got brand-new decompressor
    SUCCESS
  7. 經過使用 LZO 壓縮建立一個表來測試配置,並在 HBase Shell 中驗證它:

    $ hbase> create 't1', {NAME => 'cf1', COMPRESSION => 'LZO'}
    $ hbase> describe 't1'DESCRIPTION 
    ENABLED 
    {NAME => 't1', FAMILIES => [{NAME => 'cf1', BLOOMFILTER => 
    'NONE', true REPLICATION_SCOPE => '0', VERSIONS => '3', COMPRESSION => 'LZO',    
    MIN_VERSIONS => '0', TTL => '2147483647', BLOCKSIZE => '65536', 
    IN _MEMORY => 'false', BLOCKCACHE => 'true'}]}                                                           
    1 row(s) in 0.0790 seconds

它怎樣工做

hbase.hregion.majorcompaction 屬性指定了在 region 上全部存儲文件之間的 major compactions 時間。默認是時間是 86400000,即一天。咱們在步驟 1 中把它設置爲 0,是禁止自動的  major compaction。這將預防 major compaction 在繁忙加載時間運行,好比當  MapReduce 任務正運行在 HBase 集羣上。

換句話說, major compaction 被要求來幫助提高性能。在步驟 4 中,咱們已經展現了經過  HBase Shell 怎樣在一個特別的 region 上手動觸發  major compaction  的示例。在這個示例中,咱們已經傳遞了一個 region 名字給 major_compact 命令來僅僅在一臺單獨的 region 上調用 major compaction。它也可能在一張表中的全部 region 上運行 major compaction,經過傳遞表名給該命令。major_compact 命令爲 major compaction 給指定的表或 region 排隊;可是經過 region 服務器託管它們,這些將在後臺執行。

正如咱們在早前提到的,你或許僅僅想在一個低負載時期手動執行 major compaction。這能夠很容易的經過一個定時任務調用  major_compact 來實現。

不止這些

另一個調用  major compaction 的方法就是使用 org.apache.hadoop.hbase.client.HBaseAdmin 類提供的 majorCompact API。在 Java 中很是容易調用這個 API。所以你能夠從 Java 中管理複雜的  major compaction 調度。

管理 region 拆分

一般一個 HBase  表從一個單獨的 region 開始。儘管如此,由於數據保持增加和 region 達到了它配置的最大值,它自動分紅兩份,以致於它們能處理更多的數據。如下圖表展現了一個  HBase region 拆分:

此處輸入圖片的描述

這是 HBase region 拆分的默認行爲。這個原理在大多數狀況下工做的很好,然而有遇到問題的狀況,好比  split/ compaction 風暴問題。

隨着統一的數據分佈和增加,最後在表中的全部 region 都須要在同一時間拆分。緊接着一個拆分,壓縮將在子 region 運行以重寫他們的數據到獨立的文件中。這會引發大量的磁盤 I/O 讀寫和網絡流量。

爲了不這樣的狀況,你能夠關閉自動拆分和手動調用它。由於你能夠控制在什麼時候調用拆分,它能夠幫助擴展 I/O 負載。另外一個優點是,手動拆分可讓你有更好的 regions 控制,幫助你跟蹤和解決 region 相關的問題。

在這方面,我將描述怎樣關閉自動 region  拆分和手動調用它。

準備工做

使用你啓動集羣的用戶登陸進你的 HBase master 服務器。

怎樣作

爲了關閉自動 region 拆分和手動調用它,遵循如下步驟:

  1. 在  hbase-site.xml 文件中加入如下代碼:

    $ vi $HBASE_HOME/conf/hbase-site.xml<property><name>hbase.hregion.max.filesize</name><value>107374182400</value></property>
  2. 在集羣中同步這些變動並重啓 HBase。

  3. 使用上述設置,region 拆分將不會發生直到 region 的大小到達了配置的 100GB 閥值。你將須要在選擇的 region 上明確調用它。

  4. 爲了經過 HBase Shell 運行一個 region 拆分,使用如下命令:

    $ echo "split 'hly_temp,,1327118470453.5ef67f6d2a792fb0bd737863dc00b6a7.'" | $HBASE_HOME/bin/hbase shell
    HBase Shell; enter 'help<RETURN>' for list of supported commands.
    Type "exit<RETURN>" to leave the HBase Shell  Version 0.92.0, r1231986, Tue Jan 17 02:30:24 UTC 2012split 'hly_temp,,1327118470453.5ef67f6d2a792fb0bd737863dc00b6a7.'0 row(s) in 1.6810 seconds

它怎樣工做

hbase.hregion.max.filesize 屬性指定了最大的 region 大小(bytes)。默認,值是 1GB( HBase 0.92 以前的版本是 256MB)。這意味着當一個 region 超過這個大小,它將拆分紅兩個。在步驟 1 中咱們設置 region 最大值爲 100GB,這是一個很是高的數字。

由於拆分不會發生直到超過了 100GB 的邊界,咱們須要明確的調用它。在步驟 4,咱們在一個指定的 region 上使用 split 命令經過 HBase Shell 調用拆分。

不要忘記拆分大的 region。一個 region 在 HBase 是基礎的數據分佈和負載單元。Region 應該在低負載時期被拆分紅合適的大小。

換句話說;太多的拆分很差,在一臺 region 服務器上有太多的拆分會下降它的性能。

在手動拆分 region 以後,你或許想觸發 major compaction 和負載均衡。

不止這些

咱們在前面的設置會引發整個集羣有一個默認的 100GB 的region 最大值。除了改變整個集羣,當在建立一張表的時候,也能夠在一個列簇的基礎上指定 MAX_FILESIZE 屬性。

  $ hbase> create 't1', {NAME => 'cf1', MAX_FILESIZE => '107374182400'}

像  major compaction,你也可使用 org.apache.hadoop.hbase.client.HBaseAdmin 類提供的 split API。

相關文章
相關標籤/搜索