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。

相关文章
相关标签/搜索