标签:regexp href git string github hba buffer ini lib
现代服务器通常有多个磁盘硬件来提供大存储能力。这些磁盘通常配置成 RAID 阵列,作为它们的出厂设置。这在很多情况下是有益的,但对 Hadoop 却不是。
Hadoop 的 slave 节点存储了 HDFS 数据块和 MapReduce 临时文件在它的本地磁盘。这些本地磁盘操作受益于使用多个独立的磁盘来扩展磁盘 I/O。
在这方面,我们将描述怎样通过使用多个磁盘设置 Hadoop 来扩展磁盘 I/O。
我们假设你的每个 DataNode 节点都有多个磁盘。这些磁盘是 JBOD (简单磁盘捆绑)或 RAID0 配置。假设这些磁盘挂载在 /mnt/d0, /mnt/d1, …, /mnt/dn。并且用户在每个挂载点授予了 HDFS 写权限。
为了设置 Hadoop 来扩展磁盘 I/O,遵照这些指示:
在每个 DataNode 节点,在每块磁盘上为 HDFS 创建目录来存储它的数据块:
hadoop$ mkdir -p /mnt/d0/dfs/data
hadoop$ mkdir -p /mnt/d1/dfs/data
…
hadoop$ mkdir -p /mnt/dn/dfs/data
加入以下代码到 HDFS 配置文件中(hdfs-site.xml):
<property>
<name>dfs.data.dir</name>
<value>/mnt/d0/dfs/data,/mnt/d1/dfs/data,...,/mnt/dn/dfs/data</value>
</property>
同步修改过的 hdfs-site.xml 到集群:
hadoop@master1$ for slave in `cat $HADOOP_HOME/conf/slaves`
do
rsync -avz $HADOOP_HOME/conf/ $slave:$HADOOP_HOME/conf/
done
重起 HDFS:
hadoop@master1$ $HADOOP_HOME/bin/stop-dfs.sh
hadoop@master1$ $HADOOP_HOME/bin/start-dfs.sh
我建议 DataNode 节点为 JBOD 或是 RAID0,因为你不需要 RAID 冗余,因为 HDFS 通过使用节点间的副本确保了它的数据冗余。因此,当单个磁盘失败了,不会造成数据丢失。
选择哪一个,JBOD 或 RAID0?从理论上来说,使用 JBOD 配置会比 RAID 配置的性能更好。这是因为,在 RAID 配置中,在整个写操作完成之前,你不得不等待阵列中最慢的磁盘完成,这使得平均 I/O 时间等于最慢的磁盘 I/O 时间。JBOD 配置中,最快的磁盘中的操作独立于最慢的磁盘,这使得平均的 I/O 时间比最慢的快。尽管如此,企业级的 RAID 卡或许有很大的影响。在决定选择哪个之前,你或许想对你的 JBOD 和 RAID0 做下基准测试。
对于这两个 JBOD 和 RAID0 配置,你将把磁盘挂载在不同的路径。这里的关键点是设置 dfs.data.dirproperty 在每个磁盘上的所有目录的创建。dfs.data.dirproperty 指定了DataNode 应该存储它本地块在哪里。通过设置它来逗号分隔多个目录,DataNode 以 round robin 方法在所有磁盘上存储它的块。这会使得 Hadoop 高效的扩展磁盘 I/O 操作所有磁盘。
警告:不要在 dfs.data.dir property 值的目录路径之间留下空白,不然它或许不会按照期望那样工作。
你将需要同步这些改变到所有的集群中,并且重起 HDFS 以使它们生效。
如果你运行了 MapReduce,MapReduce 存储它的临时文件在 TaskTracker 的本地文件系统,你或许也想设置 MapReduce 来扩展它的磁盘 I/O:
在每个 TaskTracker 节点,为 MapReduce 在每个磁盘上创建目录来存储它的中间数据文件:
hadoop$ mkdir -p /mnt/d0/mapred/local
hadoop$ mkdir -p /mnt/d1/mapred/local
…
hadoop$ mkdir -p /mnt/dn/mapred/local
把以下代码加入 MapReduce 的配置文件中(mapred-site.xml):
hadoop@master1$ vi $HADOOP_HOME/conf/mapred-site.xml
<property>
<name>mapred.local.dir</name>
<value>/mnt/d0/mapred/local,/mnt/d1/mapred/local,...,/mnt/dn/mapred/local</value>
</property>
同步变更的 mapred-site.xml 文件到集群中,并重起 MapReduce
MapReduce 在执行期间在 TaskTracker 的本地磁盘生成很多临时文件。像 HDFS,在不同的磁盘上设置多个目录有助于大大扩展 MapReduce 的磁盘 I/O。
Hadoop 有“机架感知”的概念,管理者可以定义在集群中每个 DataNode 的机架位置。使得 Hadoop 能机架感知及其重要的,因为:
在这方面,我们将描述怎样使得 Hadoop 可以机架感知以及为什么它那么重要。
你需要知道你的每一个 slave 节点属于哪个机架。以启动 Hadoop 的用户登陆进 master 节点。
以下步骤描述了怎样使得 Hadoop 能机架感知:
创建一个 topology.sh 脚本并把它存储在 Hadoop 的配置目录下。改变 topology.data 的路径,在第 3 行,加入你的环境变量:
hadoop@master1$ vi $HADOOP_HOME/conf/topology.sh
while [ $# -gt 0 ] ; do
nodeArg=$1
exec< /usr/local/hadoop/current/conf/topology.data
result=""
while read line ; do
ar=( $line )
if [ "${ar[0]}" = "$nodeArg" ] ; then
result="${ar[1]}"
fi
done
shift
if [ -z "$result" ] ; then
echo -n "/default/rack "
else
echo -n "$result "
fi
done
不要忘记设置这个脚本的可执行权限
hadoop@master1$ chmod +x $HADOOP_HOME/conf/topology.sh
创建一个 topology.data 文件,如以下片段中那样;改变 IP 地址和机架,加入你自己的环境变量:
hadoop@master1$ vi $HADOOP_HOME/conf/topology.data
10.161.30.108 /dc1/rack1
10.166.221.198 /dc1/rack2
10.160.19.149 /dc1/rack3
把以下加入你的 Hadoop 核心配置文件(ore-site.xml):
hadoop@master1$ vi $HADOOP_HOME/conf/core-site.xml
<property>
<name>topology.script.file.name</name>
<value>/usr/local/hadoop/current/conf/topology.sh</value>
</property>
在集群中同步变更的文件并重起 HDFS 和 MapReduce。
确保 HDFS 现在是机架感知的。如果一切工作良好,你应该可以在你的 NameNode 日志文件中发现像以下的一些东西:
2012-03-10 13:43:17,284 INFO org.apache.hadoop.net.NetworkTopology:
Adding a new node: /dc1/rack3/10.160.19.149:50010
2012-03-10 13:43:17,297 INFO org.apache.hadoop.net.NetworkTopology:
Adding a new node: /dc1/rack1/10.161.30.108:50010
2012-03-10 13:43:17,429 INFO org.apache.hadoop.net.NetworkTopology:
Adding a new node: /dc1/rack2/10.166.221.198:50010
确保 MapReduce 现在是机架感知的。如果一切工作良好,你应该会在你的 JobTracker 日志文件中发现像以下的一些东西:
2012-03-10 13:50:38,341 INFO org.apache.hadoop.net.NetworkTopology:
Adding a new node: /dc1/rack3/ip-10-160-19-149.us-west-1.compute.internal
2012-03-10 13:50:38,485 INFO org.apache.hadoop.net.NetworkTopology:
Adding a new node: /dc1/rack1/ip-10-161-30-108.us-west-1.compute.internal
2012-03-10 13:50:38,569 INFO org.apache.hadoop.net.NetworkTopology:
Adding a new node: /dc1/rack2/ip-10-166-221-198.us-west-1.compute.internal
下面的图表显示了 Hadoop 机架感知的概念:
HDFS 文件的每个块将被复制到多个 DataNodes,来预防丢失所有的数据副本由于一台机器的失效。尽管如此,如果所有的副本数据被复制到同一个机架的 DataNodes,然后这个机架失效了,所有的数据副本将被丢失。为了避免这个,NameNode 需要知道网络拓扑为了使用那些信息来使得数据智能复制。
正如以上图表所显示的那样,使用默认的三个复制因素,两个数据副本将位于同一个机架的机器上,另外一个将被放在一个不同机架的机器上。这确保了单个机架失效,不会导致所有数据副本丢失。正常来说,同一个机架的两台机器有更多的带宽和更低的延迟,相对于两台机器在不同的机架来说。使用网络拓扑信息,Hadoop 可以通过从合适的 DataNodes 读取数据来最大化提升网络性能。如果数据在本地机器可用,Hadoop 将从它那里读取数据。如果不可用,Hadoop 将尝试从同一机架的机器读取数据,如果它也是不可用的,将从不同机架的机器读取数据。
在步骤 1 中,我们创建了 topology.sh 脚本。这个脚本以 DNS 名字作为参数并返回网络拓扑名字(机架)作为输出。DNS 名字映射到网络拓扑是由 topology.data 文件提供,在步骤 2 中创建。如果一个实体没有在 topology.data 中发现,脚本将返回 /default/rack 作为默认的机架名字。
注意:我们使用 IP 地址,而不是主机名在 topology.data 文件中。这是一个已知的 BUG,Hadoop 没有正确处理开头字母从 “a” 到 “f” 主机名。检查 HADOOP-6682 获取更多信息。
注:上述的 BUG 已经在 0.22.0 版本中解决了。所以应该可以使用主机名了,但是需要测试下。
在步骤 3 中,我们在 core-site.xml 中设置 topology.script.file.name 属性,告诉 Hadoop 调用 topology.sh 来解析 DNS 名字为网络拓扑名字。
然后重起 Hadoop,如步骤 5 和 6 中的日志显示那样,HDFS 和 MapReduce 加入了正确的机架名作为 slave 节点 DNS 名字的前缀。这个表明 HDFS 和 MapReduce 的机架感知使用上面提到的设置工作的很好。
如果你纯粹是为 Hadoop 挂载磁盘,你可以使用 ext3 或 ext4,或 XFS 文件系统,我建议你使用 noatime 和 nodiratime 属性挂载磁盘。
如果你以 noatime 挂载磁盘,访问时间戳不会更新,当一个文件在文件系统中被读的时候。在这个 nodiratime 属性情况中,挂载磁盘不会更新文件系统中目录的 inode 访问时间。因为它们没有更多的磁盘 I/O 更新访问时间戳,这提升了文件系统的访问速度。
在这方面,我们将描述为什么 Hadoop 建议使用 noatime 和 nodiratime,以及怎样使用 noatime 和 nodiratime 挂载磁盘。
你需要在你的 slave 节点有 root 权限。我们假设你的 Hadoop 仅仅只有两块磁盘 - /dev/xvdc 和 /dev/xvdd。这两块磁盘被分别地挂载在 /mnt/is1 和 /mnt/is2。而且,我们假设你使用的是 ext3 文件系统。
为了使用 noatime 和 nodiratime 挂载磁盘,在集群中的每台 slave 节点执行以下指令:
加入以下命令到 /etc/fstab 文件中:
$ sudo vi /etc/fstab
/dev/xvdc /mnt/is1 ext3 defaults,noatime,nodiratime 0 0
/dev/xvdd /mnt/is2 ext3 defaults,noatime,nodiratime 0 0
卸载磁盘并再次挂载它们使变更生效:
$ sudo umount /dev/xvdc
$ sudo umount /dev/xvdd
$ sudo mount /dev/xvdc
$ sudo mount /dev/xvdd
检查已经生效的挂载选项:
$ mount
/dev/xvdc on /mnt/is1 type ext3 (rw,noatime,nodiratime)
/dev/xvdd on /mnt/is2 type ext3 (rw,noatime,nodiratime)
因为 Hadoop (HDFS) 使用 NameNode 管理元数据(inode),被 Hadoop 保存的任何访问时间信息是独立块的独立 atime 属性。因此,DataNode 本地文件系统的访问时间戳是没有意义的。这就是为什么我建议你使用noatime 和 nodiratime 挂载磁盘,如果磁盘纯粹是为了给 Hadoop 使用。使用noatime 和 nodiratime 挂载磁盘保存了一个本地文件每次被访问的写 I/O。
这些选项被设置在 /etc/fstab 文件中,不要忘记卸载和再次挂载,为了使变更生效。
使得这些选项生效,可以提升 HDFS 的读性能。因为 HBase 存储在 HDFS 上存储它的数据,HBase 读性能也会被提升。
另一个优化方法是降低 ext3 或 ext4 文件系统上保留块的百分比。默认,一些文件系统块被保留供特权进程使用。这是为了避免用户进程装满磁盘空间的情况,这是被系统守护进程要求的,为了保持正常工作。这是非常重要的对于主机操作系统中的磁盘,但是对于仅仅是 Hadoop 使用的磁盘作用有限。
通常这些 Hadoop 磁盘有一个非常大的存储空间。降低保留块的百分比可以给 HDFS 集群增加一些存储容量。正常来说,默认的保留块百分比是 5%。它可以被降低到 1%。
注意:不要在主机操作系统上降低磁盘空间的保留块。
为了实现这个,在集群中的每个 slave 节点的每个磁盘运行以下命令:
$ sudo tune2fs -m 1 /dev/xvdc
tune2fs 1.41.12 (17-May-2010)
Setting reserved blocks percentage to 1% (1100915 blocks)
Linux 移动那些一段时间没有被访问的内存页到 swap 空间,即使它由足够可用的内存。这叫做 swap out。换一句话说,从 swap 空间读 swapped out 的数据到内存中叫做 swap in。Swapping 在大多数情形是有必要的,但是因为 Java Virtual Machine(JVM) 在 swapping 下不是表现的很好,如果 swapped 了,HBase 运行可能会遇到问题。ZooKeeper 的 session 过期或许是 被 swap 引入的典型问题。
在这方面,我们将描述怎样调整 Linux 的 vm.swappiness 参数来避免 swap。
确保在你的集群节点中有 root 权限。
为了调整 Linux 参数来避免 swap,在集群中的每个节点上调用以下命令:
执行以下命令来设置 vm.swappiness 参数为 0:
root# sysctl -w vm.swappiness=0
vm.swappiness = 0
这个改变将一直有效直到下次服务器重启。
把以下加入 /etc/sysctl.conf 文件,以至于该设置永久生效:
root# echo "vm.swappiness = 0" >> /etc/sysctl.conf
vm.swappiness 参数被用于定义多少积极内存页被交换到磁盘。它接收从 0 到 100 的任何值 - 一个更低的值意味着内核将更少的交换,但是一个更高的值使得内核应用更经常的交换。默认值是 60。
我们在步骤 1 中把 vm.swappiness 设置成 0,这将使得内核避免把进程尽可能的从物理内存中交换出去。这对 HBase 是非常有用的,因为 HBase 的进程消费大量的内存,一个高的 vm.swappiness 值将使得 HBase 交换很多并遭遇非常慢的垃圾回收。随着 ZooKeeper session 超时,这可能会导致 RegionServer 进程被杀死。我们建议你设置它为 0 或者任何更低的数字(比如,10)并观察 swapping 状态。
注意该值被 sysctl 命令设置仅仅会持久化直到服务器下次重启。你需要在 /etc/sysctl.conf 文件设置 vm.swappiness,以至于该设置无论服务器什么时候重启都会生效。
因为 HBase 运行在 JVM,JVM 的 Garbage Collection(GC) 设置对于 HBase 流畅的运行,更高的性能是非常重要的,除了配置 HBase 堆设置的指导方针之外。有 HBase 进程输出到它们的 GC 日志中是同样重要的,并且它们基于 GC 日志的输出调整 JVM 设置。
我将描述最重要的 HBase JVM 堆设置,也描述怎样是它生效以及理解 GC 日志,在这方面。我将覆盖一些指导方针来调整 HBase 的 Java GC 设置。
登陆你的 HBase region 服务器。
以下被建议用于 Java GC 和 HBase 堆设置:
通过编辑 hbase-env.sh 文件给 HBase 足够大的堆大小。比如,以下片段给 HBase 配置一个 8000-MB 的堆:
$ vi $HBASE_HOME/conf/hbase-env.sh
export HBASE_HEAPSIZE=8000
通过以下命令使得 GC 日志生效:
export HBASE_OPTS="$HBASE_OPTS -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/usr/local/hbase/logs/gc-hbase.log"
把以下代码加入来比默认更早的开始 Concurrent-Mark-Sweep GC(CMS):
$ vi $HBASE_HOME/conf/hbase-env.sh
export HBASE_OPTS="$HBASE_OPTS -XX:CMSInitiatingOccupancyFraction=60"
在步骤 1 中,我们配置 HBase 堆内存大小。默认,HBase 使用 1GB 的堆,这对于现代的机器来说太低了。对于 HBase 来说,比 4GB 更大是好的。我们建议 8GB 或更大,但是低于 16 GB。
在步骤 2 中,我们是 JVM 日志生效,使用这个设置,你可以获取 region 服务器的 JVM 日志,和我们在步骤 5 中展示的类似。关于 JVM 内存分配和垃圾回收的基础知识是被要求的,为了明白日志输出。以下是 JVM 分代垃圾收集系统的图表:
这里有 3 个堆分代:Perm(或是 Permanent)代【永久代】,Old Generation 代【老年代】,和 Young 代【年轻代】。年轻代由三个独立的空间组成,Eden 空间和两个 survivor 空间,S0 和 S1。
通常,对象被分配在年轻代的 Eden 空间,如果一个分配失败(Eden 满了),所有 java 线程停止,并且一个年轻代 GC(Minor GC)被调用。所有在年轻代存活的对象(Eden 和 S0 空间)被拷贝到 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>]
在这个输出中:
在步骤 5 中我们输出的第一行表明了是一个 minor GC,中断了 JVM 0.0764200 秒,它已经把年轻代的空间从 14.8MB 降低到 1.6MB。
接着,我们看看 CMS GC 日志,HBase 使用 CMS GC 作为它默认的老年代垃圾回收器。
CMS GC 执行以下步骤:
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 另外一个最重要的特性就是使用压缩。它是非常重要的,因为:
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 压缩支持:
从源码构建原生的 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。
拷贝构建的包到你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-32
hadoop@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。
添加 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>
HBase ships 使用一个工具来测试压缩是否被正确设置了。使用这个工具来在集群中的每个节点上测试 LZO 设置。如果一切都正确无误的配置了,你将得到成功的输出:
hadoop@client1$ $HBASE_HOME/bin/hbase org.apache.hadoop.hbase.util.CompressionTest /tmp/lzotest lzo
12/03/11 11:01:08 INFO hfile.CacheConfig: Allocating LruBlockCache with maximum size 249.6m
12/03/11 11:01:08 INFO lzo.GPLNativeCodeLoader: Loaded native gpl library
12/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 compressor
12/03/11 11:01:18 INFO compress.CodecPool: Got brand-new decompressor
SUCCESS
通过使用 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 调度。
通常一个 HBase 表从一个单独的 region 开始。尽管如此,因为数据保持增长和 region 达到了它配置的最大值,它自动分成两份,以至于它们能处理更多的数据。以下图表展示了一个 HBase region 拆分:
这是 HBase region 拆分的默认行为。这个原理在大多数情况下工作的很好,然而有遇到问题的情况,比如 split/ compaction 风暴问题。
随着统一的数据分布和增长,最后在表中的所有 region 都需要在同一时间拆分。紧接着一个拆分,压缩将在子 region 运行以重写他们的数据到独立的文件中。这会引起大量的磁盘 I/O 读写和网络流量。
为了避免这样的情况,你可以关闭自动拆分和手动调用它。因为你可以控制在何时调用拆分,它可以帮助扩展 I/O 负载。另一个优势是,手动拆分可以让你有更好的 regions 控制,帮助你跟踪和解决 region 相关的问题。
在这方面,我将描述怎样关闭自动 region 拆分和手动调用它。
使用你启动集群的用户登录进你的 HBase master 服务器。
为了关闭自动 region 拆分和手动调用它,遵循以下步骤:
在 hbase-site.xml 文件中加入以下代码:
$ vi $HBASE_HOME/conf/hbase-site.xml
<property>
<name>hbase.hregion.max.filesize</name>
<value>107374182400</value>
</property>
为了通过 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 2012
split ‘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。
标签:regexp href git string github hba buffer ini lib
原文地址:http://www.cnblogs.com/seaspring/p/6569015.html