HBase环境搭建随记

 

====软件版本====

jdk:jdk-8u77-linux-x64.tar.gz

zookeeper:zookeeper-3.4.6.tar.gz

hadoop:hadoop-2.7.4.tar.gz

hbase:hbase-1.3.1-bin.tar.gz

 

====前提准备====

3台vmware虚拟机(已配置无秘钥访问)

其中,/etc/hosts文件内容如下:

 

====安装jdk====

上传安装包,解压缩,然后配置环境变量即可。

正常配置之后,在服务器任意路径执行java -version可以显示java版本。如下所示。

 

====安装zookeeper====

这里也不在过多描述,简单罗列一下配置文件。

配置文件:zoo.cfg

需要分别在3个节点的,dataDir路径下生成节点的myid。

启动并验证zookeeper是否正常

启动命令:/home/hadmin/zookeeper-3.4.6/bin/zkServer.sh start

查看状态:/home/hadmin/zookeeper-3.4.6/bin/zkServer.sh status

启动之后,3个节点的状态分别如下:

 

====安装hadoop====

因为HBase的底层是基于Hadoop的hdfs的,所以在安装HBase之前,必须要安装Hadoop,并确保hdfs正常。

Hadoop的配置重点是各个配置文件,这里只罗列各个配置文件的基础信息(经验证,这些基本上是必须要配置的), 

需要配置环境变量的同时,共需要修改如下文件:

  • hadoop-env.sh(各节点相同)
  • core-site.xml(各节点相同)
  • hdfs-site.xml(各节点相同)
  • mapred-site.xml(各节点相同)
  • yarn-site.xml(各节点相同)
  • masters(各节点相同)
  • slaves(各节点相同)

配置文件路径:/home/hadmin/hadoop-2.7.4/etc/hadoop

 

1、环境变量

 

2、hadoop-env.sh

修改JAVA_HOME即可。

 

3、core-site.xml

<configuration>

<property>
<name>fs.defaultFS</name>
<value>hdfs://ns</value>
</property>

<property>
<name>hadoop.tmp.dir</name>
<value>/home/hadmin/data/hadoop/tmp</value>
</property>

<property>
<name>dfs.journalnode.edits.dir</name>
<value>/home/hadmin/data/hadoop/journal</value>
</property>

<property>
<name>ha.zookeeper.quorum</name>
<value>dscn1:2181,dscn2:2181,dscn3:2181</value>
</property>

</configuration>

 

4、hdfs-site.xml

<configuration>

<property>
<name>dfs.replication</name>
<value>2</value>
</property>

<property>
<name>dfs.namenode.name.dir</name>
<value>/home/hadmin/data/hadoop/hdfs/name</value>
</property>

<property>
<name>dfs.datanode.data.dir</name>
<value>/home/hadmin/data/hadoop/hdfs/data</value>
</property>

<property>
<name>dfs.permissions</name>
<value>false</value>
</property>

<property>
<name>dfs.nameservices</name>
<value>ns</value>
</property>

<property>
<name>dfs.ha.namenodes.ns</name>
<value>nn1,nn2</value>
</property>

<property>
<name>dfs.namenode.rpc-address.ns.nn1</name>
<value>dscn1:9000</value>
</property>

<property>
<name>dfs.namenode.rpc-address.ns.nn2</name>
<value>dscn2:9000</value>
</property>

<property>
<name>dfs.namenode.http-address.ns.nn1</name>
<value>dscn1:50070</value>
</property>

<property>
<name>dfs.namenode.http-address.ns.nn2</name>
<value>dscn2:50070</value>
</property>

<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://dscn1:8485;dscn2:8485;dscn3:8485/ns</value>
</property>

<property>
<name>dfs.ha.automatic-failover.enabled.ns</name>
<value>true</value>
</property>

<property>
<name>dfs.client.failover.proxy.provider.ns</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>

<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>

<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>~/.ssh/id_dsa</value>
</property>

</configuration>

 

5、mapred-site.xml

<configuration>

<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>

<property>
<name>mapreduce.reduce.memory.mb</name>
<value>128</value>
</property>

<property>
<name>mapreduce.map.memory.mb</name>
<value>256</value>
</property>

</configuration>

 

6、yarn-site.xml

<?xml version="1.0" encoding="utf-8"?>

<configuration> 
<!-- Site specific YARN configuration properties -->  
<property> 
<name>yarn.nodemanager.aux-services</name>  
<value>mapreduce_shuffle</value>
</property>

<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>

<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>

<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>ns</value>
</property>

<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>

<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>dscn1</value>
</property> 

<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>dscn2</value>
</property>

<property>
<name>yarn.resourcemanager.webapp.address.rm1</name>
<value>dscn1:8088</value>
</property>

<property>
<name>yarn.resourcemanager.webapp.address.rm2</name>
<value>dscn2:8088</value>
</property>

<property>
<name>yarn.resourcemanager.zk-address</name>
<value>dscn1:2181,dscn2:2181,dscn3:2181</value>
</property>

<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>

<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>

<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>1024</value>
</property>

<property>
<name>yarn.scheduler.minimum-allocation-mb</name>
<value>256</value>
</property>

<property>
<name>yarn.scheduler.maximum-allocation-mb</name>
<value>1024</value>
</property>
</configuration>

 

7、masters

dscn1
dscn2

 

8、slaves

dscn1
dscn2
dscn3

 

上述几个文件配置完毕之后,按照如下顺序启动

■首次启动:

1、在dscn1上

hdfs zkfc -formatZK

2、在3节点分别启动:

hadoop-daemon.sh start journalnode

3、在dscn1上:

hdfs namenode -format

hadoop-daemon.sh start namenode

4、在dscn2上:

hdfs namenode -bootstrapStandby

hadoop-daemon.sh start namenode

5、在dscn1和dscn2上:

hadoop-daemon.sh start zkfc

6、在3个节点分别启动:

hadoop-daemon.sh start datanode

7、在dscn1和dscn2上:

yarn-daemon.sh start resourcemanager

8、在3个节点分别启动:

yarn-daemon.sh start nodemanager

9、在dscn1上启动:

mr-jobhistory-daemon.sh start historyserver

 

■以后每次启动:

1、在3节点分别启动:

hadoop-daemon.sh start journalnode

2、在dscn1、dscn2上:

hadoop-daemon.sh start namenode

3、在dscn1和dscn2上:

hadoop-daemon.sh start zkfc

4、在3个节点分别启动:

hadoop-daemon.sh start datanode

5、在dscn1和dscn2上:

yarn-daemon.sh start resourcemanager

6、在3个节点分别启动:

yarn-daemon.sh start nodemanager

7、在dscn1上启动:

mr-jobhistory-daemon.sh start historyserver

 

■停止集群:

按照上面相反的顺序,把start换成stop即可。

 

安装是否正常,可以通过如下方式验证:

1、通过hadoop命令来操作hdfs

浏览hdfs根目录:hadoop fs -ls /

创建文件夹:hadoop fs -mkdir /test

 

2、通过浏览器可以查看Hadoop集群状态

其中,两个namenode,需要有一个保持active状态

 

3、通过浏览器可以查看hadoop applications状态

 

4、3个节点的jps进程如下:

dscn1:

dscn2:

dscn3:

 

====安装HBase====

hbase的安装相对简单,主要完成以下文件的配置:

1、hbase-env.sh

export JAVA_HOME=/home/hadmin/jdk1.8.0_77
export HBASE_MANAGES_ZK=false export HBASE_CLASSPATH=/home/hadmin/hadoop-2.7.4/etc/hadoop

其中,JAVA_HOME如果不配置,可能会出现如下错误:

HBASE_CLASSPATH这个配置需要特别注意,这个配置的目的是让HBase能够找到hadoop的配置文件,从而与hdfs建立联系,如果不配置这个,会出现如下错误:

另外,官方文档上也提到了这点,并提供了2种解决方法,我这里采用的是"方法a"。

 

2、hbase-site.xml

<configuration>

<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>

<property>
<name>hbase.tmp.dir</name>
<value>/home/hadmin/data/hbase/tmp</value>
</property>

<property>
<name>hbase.zookeeper.quorum</name>
<value>dscn1,dscn2,dscn3</value>
</property>

<property>
<name>hbase.rootdir</name>
<value>hdfs://ns/hbase</value>
</property>

<property>
<name>hbase.master.port</name>
<value>60000</value>
</property>

<property>
<name>hbase.master.info.port</name>
<value>60010</value>
</property>

<property>
<name>hbase.regionserver.port</name>
<value>60020</value>
</property>

<property>
<name>hbase.regionserver.info.port</name>
<value>60030</value>
</property>

<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/home/hadmin/data/zk/data</value>
</property>

</configuration>

 

3. regionservers

dscn1
dscn2
dscn3

 

按照上述的配置文件完成配置之后,就可以启动HBase了

启动命令:/home/hadmin/hbase-1.3.1/bin/start-hbase.sh

停止命令:/home/hadmin/hbase-1.3.1/bin/stop-hbase.sh

启动之后,可以通过如下几个方面来验证HBase集群是否正常。

1、查看jps进程

dscn1:

dscn2:

dscn3:

 

2、通过HBase shell控制台,创建表:

如下图所示:

建表命令:create 't1', {NAME => 'f1', VERSION => 2}

 

3、通过程序连接HBase,创建表:

如下程序中,建立了一张MY_TABLE_TEST1的表,并且进行了预分区。

建表程序如下:

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.io.compress.Compression;
import org.apache.hadoop.hbase.regionserver.BloomType;
import org.apache.hadoop.hbase.util.Bytes;

public class SplitRegion {
    private static final String TABLE_NAME = "MY_TABLE_TEST1";
    private static final String COLUMN_FAMILY = "df";

    public static void main(String[] args) throws Exception {
        System.out.print("[------]SplitRegion Start.\n");
        Configuration configuration= HBaseConfiguration.create();
        System.out.print("[------]step 1 succeed.\n");
        configuration.set("hbase.zookeeper.quorum", "192.168.6.3,192.168.6.4,192.168.6.5");
        HBaseAdmin admin = new HBaseAdmin(configuration);
        System.out.print("[------]step 2 succeed.\n");

        String table_name = TABLE_NAME;
        if (admin.tableExists(table_name)) {
            admin.disableTable(table_name);
            System.out.println("[----]disableTable table[" + table_name + "]\n");
            admin.deleteTable(table_name);
            System.out.println("[----]deleteTable table[" + table_name + "]\n");
        }

        HTableDescriptor desc = new HTableDescriptor(table_name);
        HColumnDescriptor family = new HColumnDescriptor(COLUMN_FAMILY.getBytes());
        //过期时间
        family.setTimeToLive(3 * 60 * 60 * 24);
        //按行过滤
        family.setBloomFilterType(BloomType.ROW);
        desc.addFamily(family);
        System.out.print("[------]step 3 succeed.\n");

        byte[][] splitKeys = {
                Bytes.toBytes("0"),
                Bytes.toBytes("2"),
                Bytes.toBytes("4"),
                Bytes.toBytes("6"),
                Bytes.toBytes("8"),
        };

        admin.createTable(desc, splitKeys);
        System.out.println("[----]createTable table[" + table_name + "]\n");
        System.out.print("[------]SplitRegion end.\n");
    }
}

 

工程pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <artifactId>hbase_sample</artifactId>
    <groupId>hbase_sample</groupId>
    <version>1.0</version>
    <modelVersion>4.0.0</modelVersion>
    <dependencies>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-common</artifactId>
            <version>1.3.1</version>
        </dependency>
    </dependencies>
    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <outputDirectory>target/classes</outputDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

 

通过maven,将程序编译完成,上传jar包只服务器,运行程序结果如下:

 

如果不上传jar包,直接在本地模式运行,可能会出现如下错误:

错误关键字:Exception in thread "main" java.io.IOException: Failed to get result within timeout, timeout=60000ms

 

解决办法:在客户端里(即你的程序所在的计算机)里,要修改etc/hosts文件

把你的HBase集群的服务器Master的主机名加进去,因为客户端访问HBase的过程中,

很多环节都是通过HBase Master节点的主机名访问的,加上之后,访问就一切正常了!

host文件位置:C:\Windows\System32\drivers\etc

修改之后如下图所示:

 

再次运行程序就可以正常访问Hbase集群了,结果贴图:

 

4、通过浏览器访问HBase管理界面:

地址:http://192.168.6.3:60010/

从图中可以看到,有3个Region Server,并有通过命令创建的【t1】表,以及通过程序创建的【MY_TABLE_TEST1】表。

 

====HBase调优参数====

<configuration>

<!--
RegionServer的共享目录,用来持久化HBase。
默认情况下HBase是写到/tmp的。不改这个配置,数据会在重启的时候丢失。
-->
<property>
<name>hbase.rootdir</name>
<value>hdfs://ns/hbase</value>
</property>

<!--
HBase的运行模式。false是单机模式,true是分布式模式。
若为false, HBase和Zookeeper会运行在同一个JVM里面。
默认: false
-->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>

<!--
Zookeeper集群的地址列表,用逗号分割。
如果在hbase-env.sh设置了HBASE_MANAGES_ZK,这些ZooKeeper节点就会和HBase一起启动。
默认: localhost。


部署的zookeeper越多,可靠性就越高,但是部署只能部署奇数个,主要为了便于选出leader。最好给每个zookeeper 1G的内存和独立的磁盘,可以确保高性能。hbase.zookeeper.property.dataDir可以修改zookeeper保存数据的路径。
-->
<property>
<name>hbase.zookeeper.quorum</name>
<value>dscn11,dscn12,dscn13</value>
</property>

<!--
本地文件系统的临时文件夹。
可以修改到一个更为持久的目录上。(/tmp会在重启时清除)
默认:${Java.io.tmpdir}/hbase-${user.name}
-->
<property>
<name>hbase.tmp.dir</name>
<value>/home/hadmin/data/hadoop</value>
</property>

<!--
最大HStoreFile大小。
若某个列族的HStoreFile增长达到这个值,这个Hegion会被切割成两个。
默认:10737418240(10G)

小region对split和compaction友好,因为拆分region或compact小region里的storefile速度很快,内存占用低。
缺点是split和compaction会很频繁。
特别是数量较多的小region不停地split, compaction,会导致集群响应时间波动很大,region数量太多不仅给管理上带来麻烦,甚至会引发一些Hbase的bug。
一般512以下的都算小region。

大region,则不太适合经常split和compaction,因为做一次compact和split会产生较长时间的停顿,对应用的读写性能冲击非常大。
此外,大region意味着较大的storefile,compaction时对内存也是一个挑战。
当然,大region也有其用武之地。如果你的应用场景中,某个时间点的访问量较低,
那么在此时做compact和split,既能顺利完成split和compaction,又能保证绝大多数时间平稳的读写性能。

既然split和compaction如此影响性能,有没有办法去掉?
compaction是无法避免的,split倒是可以从自动调整为手动。
只要通过将这个参数值调大到某个很难达到的值,比如100G,就可以间接禁用自动split(RegionServer不会对未到达100G的region做split)。
再配合RegionSplitter这个工具,在需要split时,手动split。
手动split在灵活性和稳定性上比起自动split要高很多,相反,管理成本增加不多,比较推荐online实时系统使用。

内存方面,小region在设置memstore的大小值上比较灵活,大region则过大过小都不行,过大会导致flush时app的IO wait增高,过小则因store file过多影响读性能。
-->
<property>
<name>hbase.hregion.max.filesize</name>
<value>1073741824</value>
</property>

<!--
RegionServers受理的RPC Server实例数量。
对于Master来说,这个属性是Master受理的handler数量
默认: 10

RegionServer的请求处理IO线程数。
这个参数的调优与内存息息相关。
较少的IO线程,适用于处理单次请求内存消耗较高的Big PUT场景(大容量单次PUT或设置了较大cache的scan,均属于Big PUT)或ReigonServer的内存比较紧张的场景。
较多的IO线程,适用于单次请求内存消耗低,TPS要求非常高的场景。设置该值的时候,以监控内存为主要参考。
这里需要注意的是如果server的region数量很少,大量的请求都落在一个region上,因快速充满memstore触发flush导致的读写锁会影响全局TPS,不是IO线程数越高越好。

-->
<property>
<name>hbase.regionserver.handler.count</name>
<value>600</value>
</property>

<!--
如果memstore有hbase.hregion.memstore.block.multiplier倍数的hbase.hregion.flush.size的大小,就会阻塞update操作。
这是为了预防在update高峰期会导致的失控。如果不设上界,flush的时候会花很长的时间来合并或者分割,最坏的情况就是引发out of memory异常。
默认: 2

当一个region里的memstore占用内存大小超过hbase.hregion.memstore.flush.size两倍的大小时,block该region的所有请求,进行flush,释放内存。
虽然我们设置了region所占用的memstores总内存大小,比如64M,但想象一下,在最后63.9M的时候,我Put了一个200M的数据,
此时memstore的大小会瞬间暴涨到超过预期的hbase.hregion.memstore.flush.size的几倍。

这个参数的作用是当memstore的大小增至超过hbase.hregion.memstore.flush.size 2倍时,block所有请求,遏制风险进一步扩大。
调优: 这个参数的默认值还是比较靠谱的。如果你预估你的正常应用场景(不包括异常)不会出现突发写或写的量可控,那么保持默认值即可。
如果正常情况下,你的写请求量就会经常暴长到正常的几倍,那么你应该调大这个倍数并调整其他参数值,
比如hfile.block.cache.size和hbase.regionserver.global.memstore.upperLimit/lowerLimit,以预留更多内存,防止HBase server OOM。
-->
<property>
<name>hbase.hregion.memstore.block.multiplier</name>
<value>8</value>
</property>

<!--
当memstore的大小超过这个值的时候,会flush到磁盘。
这个值被一个线程每隔hbase.server.thread.wakefrequency检查一下。
默认:134217728(128M),单位:bytes
-->
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>33554432</value>
</property>

<!--
默认值:0.4
这个参数的作用是防止内存占用过大,当ReigonServer内所有region的memstores所占用内存总和达到heap的40%时,
HBase会强制block所有的更新并flush这些region以释放所有memstore占用的内存。

调优:这是一个Heap内存保护参数,默认值已经能适用大多数场景。
参数调整会影响读写,如果写的压力大导致经常超过这个阀值,则调小读缓存hfile.block.cache.size增大该阀值,或者Heap余量较多时,不修改读缓存大小。
如果在高压情况下,也没超过这个阀值,那么建议你适当调小这个阀值再做压测,确保触发次数不要太多,然后还有较多Heap余量的时候,调大hfile.block.cache.size提高读性能。
还有一种可能性是?hbase.hregion.memstore.flush.size保持不变,但RS维护了过多的region,要知道 region数量直接影响占用内存的大小。
-->
<property>
<name>hbase.regionserver.global.memstore.size</name>
<value>0.5</value>
</property>

<!--
BucketCache工作模式。heap、offheap和file
默认:none

这三种工作模式在内存逻辑组织形式以及缓存流程上都是相同的,参见上节讲解。不同的是三者对应的最终存储介质有所不同。
其中heap模式和offheap模式都使用内存作为最终存储介质,
heap模式分配内存会从JVM提供的heap区分配,而后者会直接从操作系统分配。这两种内存分配模式会对HBase实际工作性能产生一定的影响。
影响最大的无疑是GC ,相比heap模式,offheap模式因为内存属于操作系统,所以基本不会产生CMS GC,也就在任何情况下都不会因为内存碎片导致触发Full GC。

除此之外,在内存分配以及读取方面,两者性能也有不同,
比如,内存分配时heap模式需要首先从操作系统分配内存再拷贝到JVMheap,相比offheap直接从操作系统分配内存更耗时;
但是反过来,读取缓存时heap模式可以从JVM heap中直接读取,而offheap模式则需要首先从操作系统拷贝到JVM heap再读取,显得后者更费时。

file模式和前面两者不同,它使用Fussion-IO或者SSD等作为存储介质,相比昂贵的内存,这样可以提供更大的存储容量,因此可以极大地提升缓存命中率。
-->
<property>
<name>hbase.bucketcache.ioengine</name>
<value>offheap</value>
</property>

<!--
分配给HFile/StoreFile的block cache占最大堆(-Xmx setting)的比例。
默认0.25意思是分配25%。设置为0就是禁用,但不推荐。

storefile的读缓存占用Heap的大小百分比,0.2表示20%。该值直接影响数据读的性能。
当然是越大越好,如果写比读少很多,开到0.4-0.5也没问题。
如果读写较均衡,0.3左右。如果写比读多,果断默认吧。
设置这个值的时候,你同时要参考?hbase.regionserver.global.memstore.upperLimit?,
该值是memstore占heap的最大百分比,两个参数一个影响读,一个影响写。如果两值加起来超过80-90%,会有OOM的风险,谨慎设置。
-->
<property>
<name>hfile.block.cache.size</name>
<value>0.3</value>
</property>

<!--
bucketcache的大小,小于1时为整体内存的比例,大于等于1时为cache的实际容量,单位M。默认0 
-->
<property>
<name>hbase.bucketcache.size</name>
<value>25600</value>
</property>

<!--
hdfs的副本数
默认:3
-->
<property>
<name>dfs.replication</name>
<value>1</value>
</property>

<!--
是否使用HBase Replication(集群复制)功能
默认:false
HBase默认此特性是关闭的,需要在集群上(所有集群)进行设定并重启集群,
-->
<property>
<name>hbase.replication</name>
<value>true</value>
</property>

<!--
-->
<property>
<name>replication.source.maxretriesmultiplier</name>
<value>300</value>
</property>

<!--
-->
<property>
<name>replication.source.sleepforretries</name>
<value>1</value> 
</property>

<!--
-->
<property>
<name>replication.sleep.before.failover</name>
<value>30000</value>
</property>

</configuration>

 

====HBase内存策略====

尝试修改HBase的内存规划策略,在hbase-site.xml中增加配置:

<property>
<name>hbase.bucketcache.ioengine</name>
<value>heap</value>
</property>

然后重新启动集群,发现RegionServer正常启动之后,稍后就会自动消息,查看regionserver日志,提示如下错误:

错误关键字:

HRegionServer Aborted

bucketCacheSize <= 0; Check hbase.bucketcache.size setting and/or server java heap size

日志中提示未配置hbase.bucketcache.size,尝试在hbase-site.xml中增加如下配置项:

<property>
<name>hbase.bucketcache.size</name>
<value>0.2</value>
</property>

重新启动hbase,会提示如下错误:

错误关键字:

Exception in thread "main" java.lang.RuntimeException: Current heap configuration for MemStore and BlockCache exceeds the threshold required for successful cluster operation. The combined value cannot exceed 0.8. Please check the settings for hbase.regionserver.global.memstore.size and hfile.block.cache.size in your configuration. hbase.regionserver.global.memstore.size is 0.4 hfile.block.cache.size is 0.6

从错误提示上看,是我们配置的内存超出了hbase的限制。

那么,hbase对于region的初始内存限制似乎什么样的呢?我们来看看源代码

  • org.apache.hadoop.hbase.HConstants(只摘录了几个用到的常量)
  public static final float HBASE_CLUSTER_MINIMUM_MEMORY_THRESHOLD = 0.2f;
  public static final String BUCKET_CACHE_IOENGINE_KEY = "hbase.bucketcache.ioengine";
  public static final String HFILE_BLOCK_CACHE_SIZE_KEY = "hfile.block.cache.size";
  public static final float HFILE_BLOCK_CACHE_SIZE_DEFAULT = 0.4f;
  public static final String BUCKET_CACHE_SIZE_KEY = "hbase.bucketcache.size";
  • org.apache.hadoop.hbase.io.util.HeapMemorySizeUtil(只摘录了相关的常量及函数)
  private static final int CONVERT_TO_PERCENTAGE = 100;
  public static final float DEFAULT_MEMSTORE_SIZE = 0.4f;
  public static final String MEMSTORE_SIZE_KEY = "hbase.regionserver.global.memstore.size";
  public static final String MEMSTORE_SIZE_OLD_KEY = "hbase.regionserver.global.memstore.upperLimit";

  public static void checkForClusterFreeMemoryLimit(Configuration conf) {
    if (conf.get(MEMSTORE_SIZE_OLD_KEY) != null) {
      LOG.warn(MEMSTORE_SIZE_OLD_KEY + " is deprecated by " + MEMSTORE_SIZE_KEY);
    }
    float globalMemstoreSize = getGlobalMemStorePercent(conf, false);
    int gml = (int)(globalMemstoreSize * CONVERT_TO_PERCENTAGE);
    float blockCacheUpperLimit = getBlockCacheHeapPercent(conf);
    int bcul = (int)(blockCacheUpperLimit * CONVERT_TO_PERCENTAGE);
    if (CONVERT_TO_PERCENTAGE - (gml + bcul)
            < (int)(CONVERT_TO_PERCENTAGE *
                    HConstants.HBASE_CLUSTER_MINIMUM_MEMORY_THRESHOLD)) {
      throw new RuntimeException("Current heap configuration for MemStore and BlockCache exceeds "
          + "the threshold required for successful cluster operation. "
          + "The combined value cannot exceed 0.8. Please check "
          + "the settings for hbase.regionserver.global.memstore.size and "
          + "hfile.block.cache.size in your configuration. "
          + "hbase.regionserver.global.memstore.size is " + globalMemstoreSize
          + " hfile.block.cache.size is " + blockCacheUpperLimit);
    }
  }
  
  /**
   * Retrieve global memstore configured size as percentage of total heap.
   * @param c
   * @param logInvalid
   */
  public static float getGlobalMemStorePercent(final Configuration c, final boolean logInvalid) {
    float limit = c.getFloat(MEMSTORE_SIZE_KEY,
        c.getFloat(MEMSTORE_SIZE_OLD_KEY, DEFAULT_MEMSTORE_SIZE));
    if (limit > 0.8f || limit <= 0.0f) {
      if (logInvalid) {
        LOG.warn("Setting global memstore limit to default of " + DEFAULT_MEMSTORE_SIZE
            + " because supplied value outside allowed range of (0 -> 0.8]");
      }
      limit = DEFAULT_MEMSTORE_SIZE;
    }
    return limit;
  }

  /**
   * Retrieve configured size for on heap block cache as percentage of total heap.
   * @param conf
   */
  public static float getBlockCacheHeapPercent(final Configuration conf) {
    // L1 block cache is always on heap
    float l1CachePercent = conf.getFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY,
        HConstants.HFILE_BLOCK_CACHE_SIZE_DEFAULT);
    float l2CachePercent = getL2BlockCacheHeapPercent(conf);
    return l1CachePercent + l2CachePercent;
  }  

  /**
   * @param conf
   * @return The on heap size for L2 block cache.
   */
  public static float getL2BlockCacheHeapPercent(Configuration conf) {
    float l2CachePercent = 0.0F;
    String bucketCacheIOEngineName = conf.get(HConstants.BUCKET_CACHE_IOENGINE_KEY, null);
    // L2 block cache can be on heap when IOEngine is "heap"
    if (bucketCacheIOEngineName != null && bucketCacheIOEngineName.startsWith("heap")) {
      float bucketCachePercentage = conf.getFloat(HConstants.BUCKET_CACHE_SIZE_KEY, 0F);
      long max = -1L;
      final MemoryUsage usage = safeGetHeapMemoryUsage();
      if (usage != null) {
        max = usage.getMax();
      }
      l2CachePercent = bucketCachePercentage < 1 ? bucketCachePercentage
          : (bucketCachePercentage * 1024 * 1024) / max;
    }
    return l2CachePercent;
  }
  • getFloat函数定义

从头上面的源代码得出的结论如下:

a) 在hbase.bucketcache.ioengine为heap的时候:

hbase.regionserver.global.memstore.size + (hfile.block.cache.size + hbase.bucketcache.size)的和超过了80%,则提示上面的错误。

※由于hbase.bucketcache.size > 1时,不按照百分比计算,不占用百分比。

 

b) 在hbase.bucketcache.ioengine为offheap的时候

hbase.regionserver.global.memstore.size + hfile.block.cache.size的和超过了80%,则提示上面的错误。

 

综合上面的因素,我采用了如下的方式设置内存策略:

<property>
<name>hbase.bucketcache.ioengine</name>
<value>offheap</value>
</property>

<property>
<name>hbase.bucketcache.size</name>
<value>32</value>
</property>

<property>
<name>hfile.block.cache.size</name>
<value>0.4</value>
</property>

<property>
<name>hbase.regionserver.global.memstore.size</name>
<value>0.4</value>
</property>

重新启动HBase集群之后,日志中错误消失,jps进程均正常。

观察HBase的UI界面,可以看到LruBlockCache及BucketCache均变为有效状态,配置成功。

 

我们在追加一个实验,删除掉BucketCache的配置,然后重启HBase集群,观察HBase管理界面。

修改后的配置文件截图:

管理界面截图:

会发现代表BucketCache的L2配置也显示没有被配置,也简介的证明了注释掉的几个配置的作用。

另外,如果想将L1也禁用掉,可以按照如下方式设置。

<property>
<name>hfile.block.cache.size</name>
<value>0</value>
</property>

设置之后,L1就也被禁止掉了。

 

====清除Dead Region Servers====

在上述的配置文件中,修改了HBase一些默认端口地址,这里尝试恢复使用默认的端口,

重新启动HBase,通过管理界面查看的时候发现出现了【Dead Region Servers】中有残留Region

网上的回答如下:

从笔者的回答中可以看出,虽然RegionServer已经死掉了,不过由于死掉的RegionServer的WAL仍然存在于HDFS中,并且处于“splitting”状态,

按照笔者的方式,清理HDFS中将WALs,然后重启HBase之后,确实解决了这个问题。

 

====配置HBase Backup Master====

为了增加HBase集群的可用性,可以为HBase增加多个backup master。当master挂掉后,backup master可以自动接管整个hbase的集群。

配置方法:在hbase的conf下增加文件backup-masters,在该文件里面增加backup master的机器列表。然后将该文件上传到各个节点。

这里尝试将第二个节点(dscn2)作为backup。

然后重新启动HBase集群,可以从第二个节点的jps进程中看到也启动了HMaster

可以全部重新启动hbase,也可以单独启动hmaster backup:

■全部重启命令:

start-hbase.sh   //全部启动

stop-hbase-sh   //全部停止

■启动指定组件:

hbase-daemon.sh start/stop/restart master  //启动、停止或重启Hmaster

hbase-daemon.sh start/stop/restart master --backup  //启动、停止或重启HMaster backup

hbase-daemon.sh start/stop/restart regionserver  //启动、停止或重启HRegionServer

从HBase管理界面上也可以看到,相比之前Backup master中增加了新的节点。

 

 

====HBase集群操作命令====

1、启动整个集群

命令:./bin/start-hbase.sh

 

2、停止整个集群

命令:./bin/stop-hbase.sh

 

3、挨个滚动重启

命令:./bin/rolling-restart.sh

执行后的结果图片如下所示

 

4、开启/关闭/重启HMaster

命令:./bin/hbase-daemon.sh start/stop/restart master(当前节点)

命令:./bin/hbase-daemons.sh start/stop/restart master(所有节点)

 

5、开启/关闭/重启所有HRegionServer

命令:./bin/hbase-daemon.sh start/stop/restart regionserver(当前节点)

命令:./bin/hbase-daemons.sh start/stop/restart regionserver(所有节点)

 

6、开启/关闭/重启所有Zookeeper

命令:./bin/hbase-daemon.sh start/stop/restart zookeeper(当前节点)

命令:./bin/hbase-daemons.sh start/stop/restart zookeeper(所有节点)

 

7、开启/关闭/重启HMaster-backup

命令:./bin/hbase-daemon.sh start/stop/restart master --backup(当前节点)

命令:./bin/hbase-daemons.sh start/stop/restart master --backup(所有节点)

 

--------------------------

以下摘自:http://www.cnblogs.com/skyl/p/4853773.html

start-hbase.sh的流程如下:

1.运行hbase-config.sh(作用后面解释)

2.解析参数(0.96版本及以后才可以带唯一参数autorestart,作用就是重启)

3.调用hbase-daemon.sh来启动master;调用hbase-daemons.sh来启动regionserver zookeeper master-backup

 

hbase-config.sh的作用:

装载相关配置,如HBASE_HOME目录,conf目录,regionserver机器列表,JAVA_HOME目录等,它会调用$HBASE_HOME/conf/hbase-env.sh

 

hbase-env.sh的作用:

主要是配置JVM及其GC参数,还可以配置log目录及参数,配置是否需要hbase管理ZK,配置进程id目录等

hbase-daemons.sh的作用:

根据需要启动的进程,

如为zookeeper,则调用zookeepers.sh

如为regionserver,则调用regionservers.sh

如为master-backup,则调用master-backup.sh

 

zookeepers.sh的作用:

如果hbase-env.sh中的HBASE_MANAGES_ZK" = "true",那么通过ZKServerTool这个类解析xml配置文件,

获取ZK节点列表(即hbase.zookeeper.quorum的配置值),然后通过SSH向这些节点发送远程命令:

cd ${HBASE_HOME};

$bin/hbase-daemon.sh --config ${HBASE_CONF_DIR} start/stop zookeeper

 

regionservers.sh的作用:

与zookeepers.sh类似,通过${HBASE_CONF_DIR}/regionservers配置文件,获取regionserver机器列表,然后SSH向这些机器发送远程命令:

cd ${HBASE_HOME};

$bin/hbase-daemon.sh --config ${HBASE_CONF_DIR} start/stop regionserver

 

master-backup.sh的作用:

通过${HBASE_CONF_DIR}/backup-masters这个配置文件,获取backup-masters机器列表(默认配置中,这个配置文件并不存在,所以不会启动backup-master),

然后SSH向这些机器发送远程命令:

cd ${HBASE_HOME};

$bin/hbase-daemon.sh --config ${HBASE_CONF_DIR} start/stop master --backup

 

hbase-daemon.sh的作用:

无论是zookeepers.sh还是regionservers.sh或是master-backup.sh,最终都会调用本地的hbase-daemon.sh,其执行过程如下:

1.运行hbase-config.sh,装载各种配置(java环境、log配置、进程ID目录等)

2.如果是start命令?

滚动out输出文件,滚动gc日志文件,日志文件中输出启动时间+ulimit -a信息,如

“Mon Nov 26 10:31:42 CST 2012 Starting master on dwxx.yy.taobao”

"..open files (-n) 65536.."

3.调用$HBASE_HOME/bin/hbase start master/regionserver/zookeeper

4.执行wait,等待3中开启的进程结束

5.执行cleanZNode,将regionserver在zk上登记的节点删除,这样做的目的是:在regionserver进程意外退出的情况下,可以免去3分钟的ZK心跳超时等待,直接由master进行宕机恢复

6.如果是stop命令?

根据进程ID,检查进程是否存在;调用kill命令,然后等待到进程不存在为止

7.如果是restart命令?

调用stop后,再调用start。。。

 

★HBase命令参数解析

1.bin/hbase shell

这个就是常用的shell工具,运维常用的DDL和DML都会通过此进行,其具体实现(对hbase的调用)是用ruby写的

 

2.bin/hbase hbck

运维常用工具,检查集群的数据一致性状态,其执行是直接调用org.apache.hadoop.hbase.util.HBaseFsck中的main函数

 

3.bin/hbase hlog

log分析工具,其执行是直接调用org.apache.hadoop.hbase.regionserver.wal.HLogPrettyPrinter中的main函数

 

4.bin/hbase hfile

hfile分析工具,其执行是直接调用org.apache.hadoop.hbase.io.hfile.HFile中的main函数

 

5.bin/hbase zkcli

查看/管理ZK的shell工具,很实用,经常用,

比如你可以通过(get /IP/master)其得知当前的active master,可以通过(get /IP/root-region-server)得知当前root region所在的server,

你也可以在测试中通过(delete /IP/rs/dwxx.yy.taobao),模拟regionserver与ZK断开连接,

其执行则是调用了org.apache.zookeeper.ZooKeeperMain的main函数

 

6.bin/hbase classpath

打印classpath

 

7.bin/hbase version

打印hbase版本信息

 

====HBase集群备份及恢复(待更新)====

====HBase集群复制(待更新)====

====HBase快照(待更新)====

 

--END--