Hbase

一、Hbase集群安装与常见问题解决

首先说明,要使用hbase是需要先安装hadoop和zookeeper的(也可以使用自带的但是不建议),参考[zookeeper集群安装]
[hadoop集群安装]
我用的是三台机器,mini1,mini2,mini3
Hbase的安装流程
1、将hbase上传到hadoop集群,我这里上传的是hbase-0.99.2-bin.tar.gz。然后解压并且重命名为hbase,为了方便管理我讲hbase移动到了apps目录下。(上传、解压、重命名)

[root@mini1 ~]# tar –zxvf  hbase-0.99.2-bin.tar.gz
[root@mini1 ~]# mv hbase-0.99.2 hbase
[root@mini1 ~]# mv hbase apps
[root@mini1 ~]# cd apps/
[root@mini1 apps]# ll
总用量 20
drwxr-xr-x.  8 root   root   4096 10月 19 15:15 apache-flume-1.6.0-bin
drwxrwxr-x. 10 hadoop hadoop 4096 9月  30 22:04 hadoop-2.6.4
drwxr-xr-x.  7 root   root   4096 10月 30 00:20 hbase
drwxr-xr-x.  8 root   root   4096 10月 17 12:38 hive
drwxr-xr-x. 10 root   root   4096 10月 29 23:21 zookeeper-3.4.6

2、修改环境变量
在编辑模式下,最后面添加

[root@mini1 apps]# vi /etc/profile
...
export HBASE_HOME=/root/apps/hbase
export PATH=$PATH:$HBASE_HOME/bin

[root@mini1 apps]#source /etc/profile

在机器mini2,mini3上也执行2操作修改环境变量

3、修改配置文件
修改的是 hbase-env.sh,hbase-site.xml, regionservers
我们现在文本编辑器里面修改再上传覆盖就好了
hbase-env.sh添加内容如下
第一行指定jdk位置
第二行指定额外的classpath元素
第三行是关于jvm的可以不需要
第四行,true表示使用hbase自带的zookeeper,false表示使用自己的zookeeper(推荐,至少趁此学一下zookeeper,相信学了hbase后面的storm跟spark也会去学,后面很多都要使用zookeeper,一劳永逸的事)。

export JAVA_HOME=/heima32/jdk1.7.0_55/
export JAVA_CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export HBASE_OPTS="-XX:+UseConcMarkSweepGC"
export HBASE_MANAGES_ZK=false

hbase-site.xml内容如下

<configuration>
<property>
<name>hbase.master</name>
<value>mini1:60000</value>
<description>指定hbase的主节点与端口号</description>
</property>
<property>
<name>hbase.master.maxclockskew</name> 
<value>180000</value>
<description>时间同步允许的时间差</description>
</property>
<property>
<name>hbase.rootdir</name>
<value>hdfs://mini1:9000/hbase</value>
<description>hbase共享目录,持久化hbase数据,这个需要看你hadoop的核心文件里面配置的是不是mini1:9000不是的话得改成自己的hadoop里面写的</description>
</property>
<property>
<name>hbase.cluster.distributed</name> 
<value>true</value>
<description>是否是分布式的,当然</description>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>mini1,mini2,mini3</value>
<description>指定zookeeper,我的zookeeper集群就是在这三台机器的</description>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/root/hbase/tmp/zookeeper</value>
<description>zookeeper配置信息快照的位置,目录会自己创建的</description>
</property>
</configuration>

regionservers里面添加从节点机器名

mini2
mini3

然后将三个文件上传到hbase的conf目录下

4、将按照配置好的hbase上传到其他机器
这里是mini1配置好了,发送到mini2和mini3机器

[root@mini1 ~]# scp -r /root/apps/hbase mini2:/root/apps
[root@mini1 ~]# scp -r /root/apps/hbase mini3:/root/apps

5、启动hbase
进入到mini1的hbase的bin目录下启动
启动完了使用jsp命令查看是否启动起来了

[root@mini1 bin]# ./start-hbase.sh 
starting master, logging to /root/apps/hbase/logs/hbase-root-master-mini1.out
mini2: starting regionserver, logging to /root/apps/hbase/bin/../logs/hbase-root-regionserver-mini2.out
mini3: starting regionserver, logging to /root/apps/hbase/bin/../logs/hbase-root-regionserver-mini3.out
[root@mini1 bin]# jps
1593 ResourceManager
7133 HMaster
4550 QuorumPeerMain
2831 NameNode
7310 Jps

注:启动起来的前提需要启动hadoop和zookeeper,最后启动的话,那么mini1机器上会多出HMaster进程,mini2和mini3上多出了HRegionServer。

常见问题解决
这些问题都是我遇到的
下面的是自己的hosts文件,三台机器一样

[root@mini1 bin]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6 localhost.jinbm
192.168.25.127 mini1
192.168.25.129 mini2
192.168.25.130 mini3

1、如果启动不起来,查看日志出现下面的异常

Cause:
org.apache.hadoop.hbase.ClockOutOfSyncException: org.apache.hadoop.hbase.ClockOutOfSyncException: 
Server mini2,16020,1508608510960 has been rejected; Reported time is too far out of sync with master.  
Time difference of 428987358ms > max allowed of 180000ms

出现这个问题是当时我mini2这台机器和mini1的时间差太多了记得是4天,明显大于配置文件中写的时间同步允许的时间差也就是180000ms。

同步时间即可
ntpdate没有的话安装就好了
每台机器都像下面这样执行

[root@mini1 bin]# ntpdate
-bash: ntpdate: command not found
[root@mini1 bin]# yum install ntp
...
[root@mini1 bin]# ntpdate
30 Oct 06:21:25 ntpdate[10542]: no servers can be used, exiting
[root@mini1 bin]# ntpdate -u ntp.api.bz
29 Oct 22:22:37 ntpdate[10543]: step time server 115.28.122.198 offset -28798.299112 sec
[root@mini1 bin]# date
2017年 10月 29日 星期日 22:22:44 CST

在使用ntpdate同步时间时出现以下错误:

ntpdate[46700]: no server suitable for synchronization found

没有找到好的解决方案,只能换另外一个工具来完成时间同步。

这里使用的Centos6.5,yum源使用的是阿里云的镜像。

yum install -y rdate
安装完毕后,使用下述命令即可。

rdate -s time-b.nist.gov

然后启动出现的问题如下

[root@mini1 bin]# ./start-hbase.sh 
starting master, logging to /root/apps/hbase/logs/hbase-root-master-mini1.out
root@mini3's password: root@mini2's password: 
mini3: starting regionserver, logging to /root/apps/hbase/bin/../logs/hbase-root-regionserver-mini3.out

这个时候我们只能输一个密码,所以有一个肯定是启动不了的。
解决办法:设置mini1在mini2和mini3上免密登录。

免密登录,先生存秘钥,在mini2和mini3上授权认证通过。
[root@mini1 ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
52:1e:06:fa:7e:01:3d:a6:1d:bd:cb:19:08:86:cc:ca root@mini1
The key's randomart image is:
+--[ RSA 2048]----+
|      .          |
|   o o o .       |
|    = + O .      |
| . . o X = .     |
|  E   + S o      |
|     . . o +     |
|      . . +      |
|       .         |
|                 |
+-----------------+
[root@mini1 ~]# cd .ssh/
[root@mini1 .ssh]# ll
总用量 12
-rw-------. 1 root root 1675 10月 30 00:31 id_rsa
-rw-r--r--. 1 root root  392 10月 30 00:31 id_rsa.pub
-rw-r--r--. 1 root root 2359 10月 13 04:33 known_hosts
[root@mini1 .ssh]# ssh-copy-id mini2
root@mini2's password: 
Now try logging into the machine, with "ssh 'mini2'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

[root@mini1 .ssh]# ssh-copy-id mini3
root@mini3's password: 
Now try logging into the machine, with "ssh 'mini3'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.
测试免密登录
[root@mini1 .ssh]# ssh mini2
Last login: Mon Oct 30 00:25:33 2017 from mini1
[root@mini2 ~]# 

再次启动OK

[root@mini1 bin]# ./start-hbase.sh 
starting master, logging to /root/apps/hbase/logs/hbase-root-master-mini1.out
mini2: starting regionserver, logging to /root/apps/hbase/bin/../logs/hbase-root-regionserver-mini2.out
mini3: starting regionserver, logging to /root/apps/hbase/bin/../logs/hbase-root-regionserver-mini3.out

测试HRegionServer上下线

单独启动HRegionServer节点:

启动集群中所有的regionserver
./hbase-daemons.sh start regionserver
启动某个regionserver
./hbase-daemon.sh start regionserver

二、javaapi 访问 hbase

Hbase介绍
HBASE是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBASE技术可在廉价PC Server上搭建起大规模结构化存储集群。
HBASE的目标是存储并处理大型的数据,更具体来说是仅需使用普通的硬件配置,就能够处理由成千上万的行和列所组成的大型数据。
HBASE是Google Bigtable的开源实现,但是也有很多不同之处。比如:Google Bigtable利用GFS作为其文件存储系统,HBASE利用Hadoop HDFS作为其文件存储系统;Google运行MAPREDUCE来处理Bigtable中的海量数据,HBASE同样利用Hadoop MapReduce来处理HBASE中的海量数据;Google Bigtable利用Chubby作为协同服务,HBASE利用Zookeeper作为对应。

    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-client</artifactId>
      <version>0.99.2</version>
    </dependency>

1、创建表

public class HBaseTest {

    Configuration config = null;
    private Connection connection = null;
    private Table table = null;

    @Before
    public void init() throws Exception {
        config = HBaseConfiguration.create();// 配置
        config.set("hbase.zookeeper.quorum", "192.168.25.127,192.168.25.129,192.168.25.130");// zookeeper地址
        config.set("hbase.zookeeper.property.clientPort", "2181");// zookeeper端口
        connection = ConnectionFactory.createConnection(config);
        table = connection.getTable(TableName.valueOf("user1"));
    }
    /**
     * 创建表
     * @throws Exception
     */
    @Test
    public void testCreateTable() throws Exception{
        //创建表管理类
        HBaseAdmin admin = new HBaseAdmin(config);
        //创建表描述类
        TableName tableName = TableName.valueOf("user2");
        HTableDescriptor descriptor = new HTableDescriptor(tableName);
        //创建列族描述类
        HColumnDescriptor info1 = new HColumnDescriptor("info1");
        //列族加入表中
        descriptor.addFamily(info1);
        HColumnDescriptor info2 = new HColumnDescriptor("info2");
        descriptor.addFamily(info2);
        //创建表
        admin.createTable(descriptor);
    }
}

如果执行之后发现程序卡住不动,或者过了很久之后出现下面的异常

org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=35, exceptions:
...
Caused by: org.apache.hadoop.hbase.MasterNotRunningException: com.google.protobuf.ServiceException: java.net.UnknownHostException: unknown host: mini1
...
Caused by: com.google.protobuf.ServiceException: java.net.UnknownHostException: unknown host: mini1
...

首先确保关闭了hadoop的安全模式,然后linux下的ip地址跟主机名必须对应,最后windows下的ip地址跟主机名也要对应,我这在linux下/etc/hosts文件中

[root@mini1 ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6 localhost.jinbm
192.168.25.127 mini1
192.168.25.129 mini2
192.168.25.130 mini3

但是当时出现windows下的hosts文件没有配置后三个映射导致出现上面的异常。

执行之后去hbase集群查看
user2表已经创建

hbase(main):002:0> list
TABLE                                                                                                                                                                             
user1                                                                                                                                                                             
user2                                                                                                                                                                             
2 row(s) in 0.0130 seconds

=> ["user1", "user2"]

2、删除表
删除表跟shell命令一样,也是要先disable表之后才能删除

    @Test
    public void testDeleteTable() throws Exception{
        HBaseAdmin admin = new HBaseAdmin(config);
        admin.disableTable("user2");
        admin.deleteTable("user2");
    }

3、单条插入(修改)

    /**
     * 向表中插入数据
     * 单条插入(包括修改)
     * @throws Exception
     */
    @Test
    public void testPut() throws Exception{
        //rowkey
        Put put = new Put(Bytes.toBytes("1234"));
        //列族,列,值
        put.add(Bytes.toBytes("info1"), Bytes.toBytes("gender"), Bytes.toBytes("1"));
        put.add(Bytes.toBytes("info2"), Bytes.toBytes("name"), Bytes.toBytes("wangwu"));
        table.put(put);
        //提交
        table.flushCommits();
    }

查看

hbase(main):008:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info2:age, timestamp=1509315527064, value=18                                                                                 
 1234                                         column=info2:name, timestamp=1509315500250, value=zhangsan                                                                          
 12345                                        column=info2:age, timestamp=1509315533683, value=18                                                                                 
 12345                                        column=info2:name, timestamp=1509315548481, value=lisi                                                                              
2 row(s) in 0.1030 seconds

hbase(main):009:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:gender, timestamp=1509315890353, value=1                                                                               
 1234                                         column=info2:age, timestamp=1509315527064, value=18                                                                                 
 1234                                         column=info2:name, timestamp=1509315890353, value=wangwu                                                                            
 12345                                        column=info2:age, timestamp=1509315533683, value=18                                                                                 
 12345                                        column=info2:name, timestamp=1509315548481, value=lisi                                                                              
2 row(s) in 0.0440 seconds

发现添加了一条数据和修改了一条数据

4、批量插入数据
Table有2个重载的方法,一个是table.put(Put put)也就是单条插入,一个是table.put(list)list泛型是Put,这就是批量插入。

    /**
     * 向表中插入数据
     * 多条插入,使用list
     * @throws Exception
     */
    @Test
    public void testPut2() throws Exception{
        //可以通过将自动刷新设置为false来激活缓冲区
        table.setAutoFlushTo(false);
        //设置数据将被写入的缓冲区大小
        table.setWriteBufferSize(534534534);
        List<Put> putList = new ArrayList<>();
        for (int i=20;i<=30;i++){
            //rowkey
            Put put = new Put(Bytes.toBytes("jbm_"+i));
            //列族,列,值
            put.add(Bytes.toBytes("info1"), Bytes.toBytes("age"), Bytes.toBytes(i));
            put.add(Bytes.toBytes("info1"), Bytes.toBytes("name"), Bytes.toBytes("lucy"+i));
            putList.add(put);
        }
        table.put(putList);
        //提交
        table.flushCommits();
    }

执行之后查看

hbase(main):010:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:gender, timestamp=1509315890353, value=1                                                                               
 1234                                         column=info2:age, timestamp=1509315527064, value=18                                                                                 
 1234                                         column=info2:name, timestamp=1509315890353, value=wangwu                                                                            
 12345                                        column=info2:age, timestamp=1509315533683, value=18                                                                                 
 12345                                        column=info2:name, timestamp=1509315548481, value=lisi                                                                              
 jbm_20                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x14                                                                   
 jbm_20                                       column=info1:name, timestamp=1509316527223, value=lucy20                                                                            
 jbm_21                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x15                                                                   
 jbm_21                                       column=info1:name, timestamp=1509316527223, value=lucy21                                                                            
 jbm_22                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x16                                                                   
 jbm_22                                       column=info1:name, timestamp=1509316527223, value=lucy22                                                                            
 jbm_23                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x17                                                                   
 jbm_23                                       column=info1:name, timestamp=1509316527223, value=lucy23                                                                            
 jbm_24                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x18                                                                   
 jbm_24                                       column=info1:name, timestamp=1509316527223, value=lucy24                                                                            
 jbm_25                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x19                                                                   
 jbm_25                                       column=info1:name, timestamp=1509316527223, value=lucy25                                                                            
 jbm_26                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x1A                                                                   
 jbm_26                                       column=info1:name, timestamp=1509316527223, value=lucy26                                                                            
 jbm_27                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x1B                                                                   
 jbm_27                                       column=info1:name, timestamp=1509316527223, value=lucy27                                                                            
 jbm_28                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x1C                                                                   
 jbm_28                                       column=info1:name, timestamp=1509316527223, value=lucy28                                                                            
 jbm_29                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x1D                                                                   
 jbm_29                                       column=info1:name, timestamp=1509316527223, value=lucy29                                                                            
 jbm_30                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x1E                                                                   
 jbm_30                                       column=info1:name, timestamp=1509316527223, value=lucy30  

5、修改数据

/**
     * 修改数据
     * @throws Exception
     */
    @Test
    public void testUpdate() throws Exception{
        Put put = new Put(Bytes.toBytes("1234"));
        put.add(Bytes.toBytes("info2"), Bytes.toBytes("name"), Bytes.toBytes("tom"));
        table.put(put);
        table.flushCommits();
    }

执行之后查看

hbase(main):010:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:gender, timestamp=1509315890353, value=1                                                                               
 1234                                         column=info2:age, timestamp=1509315527064, value=18                                                                                 
 1234                                         column=info2:name, timestamp=1509315890353, value=wangwu  
 ...
 hbase(main):013:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:gender, timestamp=1509315890353, value=1                                                                               
 1234                                         column=info2:age, timestamp=1509315527064, value=18                                                                                 
 1234                                         column=info2:name, timestamp=1509316978243, value=tom    

发现wangwu已被改为了tom

6、删除整行数据
删除rowkey为1234整行数据

    /**
     * 删除数据
     * @throws Exception
     */
    @Test
    public void testDeleteData() throws Exception{
        Delete delete = new Delete(Bytes.toBytes("1234"));
        table.delete(delete);
        table.flushCommits();
    }

7、单条查询

    /**
     * 单条查询
     * @throws Exception
     */
    @Test
    public void testGetSingle() throws Exception{
        //rowkey
        Get get = new Get(Bytes.toBytes("12345"));
        Result result = table.get(get);
        //列族,列名
        byte[] name = result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"));
        byte[] age = result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("age"));
        System.out.println(Bytes.toString(name));
        System.out.println(Bytes.toString(age));
    }

执行后hbase查看和控制台查看

hbase(main):001:0> scan 'user1'
 12345                                        column=info2:age, timestamp=1509315533683, value=18                                                                                 
 12345                                        column=info2:name, timestamp=1509315548481, value=lisi  
...
控制台输出
lisi
18

8、多条查询
这里叫做扫描更适合吧,先用全表扫描,和命令行的scan ‘表名’一样

    /**
     * 多条查询
     * 全表扫描
     * @throws Exception
     */
    @Test
    public void testGetMany() throws Exception{

        Scan scan = new Scan();
        //字典序   类似于分页
        scan.setStartRow(Bytes.toBytes("jbm_20"));
        scan.setStopRow(Bytes.toBytes("jbm_30"));
        ResultScanner resultScanner = table.getScanner(scan);
        for (Result result : resultScanner) {
            //Single row result of a Get or Scan query. Result
            //Result 一次获取一个rowkey对应的记录
            //列族,列名
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name"));
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age"));
            System.out.print(Bytes.toString(name)+",");
            System.out.print(Bytes.toInt(age));
            System.out.println();
        }

    }

执行控制台输出结果

lucy20,20
lucy21,21
lucy22,22
lucy23,23
lucy24,24
lucy25,25
lucy26,26
lucy27,27
lucy28,28
lucy29,29

9、Hbase过滤器
1)、列值过滤器
SingleColumnValueFilter
过滤列值的相等、不等、范围等

    /**
     * 全表扫描过滤器
     * 列值过滤器
     * @throws Exception
     */
    @Test
    public void testFilter() throws Exception{

        Scan scan = new Scan();
        //列值过滤器
        SingleColumnValueFilter columnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), 
                Bytes.toBytes("name"), CompareOp.EQUAL, Bytes.toBytes("lisi"));
        //设置过滤器
        scan.setFilter(columnValueFilter);
        //获取结果集
        ResultScanner resultScanner = table.getScanner(scan);
        for (Result result : resultScanner) {
            byte[] name = result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("name"));
            byte[] age = result.getValue(Bytes.toBytes("info2"), Bytes.toBytes("age"));
            System.out.print(Bytes.toString(name)+",");
            System.out.print(Bytes.toString(age));
            System.out.println();
        }
    }

执行查看输出

hbase(main):001:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 12345                                        column=info2:age, timestamp=1509315533683, value=18                                                                                 
 12345                                        column=info2:name, timestamp=1509315548481, value=lisi                                                                              
 jbm_20                                       column=info1:age, timestamp=1509316527223, value=\x00\x00\x00\x14   
 ...
控制台输出
lisi,18

2)、rowkey过滤器
RowFilter 通过正则,过滤rowKey值。

    /**
     * 全表扫描过滤器
     * rowkey过滤
     * @throws Exception
     */
    @Test
    public void testRowkeyFilter() throws Exception{

        Scan scan = new Scan();
        //rowkey过滤器
        //匹配以jbm开头的
        RowFilter filter = new RowFilter(CompareOp.EQUAL, new RegexStringComparator("^jbm"));
        //设置过滤器
        scan.setFilter(filter);
        //获取结果集
        ResultScanner resultScanner = table.getScanner(scan);
        for (Result result : resultScanner) {
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name"));
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age"));
            System.out.print(Bytes.toString(name)+",");
            System.out.print(Bytes.toInt(age));
            System.out.println();
        }
    }

控制台输出

lucy20,20
lucy21,21
lucy22,22
lucy23,23
lucy24,24
lucy25,25
lucy26,26
lucy27,27
lucy28,28
lucy29,29
lucy30,30

3)、列名前缀过滤器
ColumnPrefixFilter列名前缀过滤

    /**
     * 全表扫描过滤器
     * 列名前缀过滤
     * @throws Exception
     */
    @Test
    public void testColumnPrefixFilter() throws Exception{

        Scan scan = new Scan();
        //列名前缀过滤器 列名前缀为na(注:不是指值的前缀)
        ColumnPrefixFilter filter = new ColumnPrefixFilter(Bytes.toBytes("na"));
        //设置过滤器
        scan.setFilter(filter);
        //获取结果集
        ResultScanner resultScanner = table.getScanner(scan);
        for (Result result : resultScanner) {
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name"));
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age"));
            if(name!=null){
                System.out.print(Bytes.toString(name)+" ");
            }
            if(age!=null){
                System.out.print(age);
            }
            System.out.println();
        }
    }

从输出结果就能看到,只会拿到name列,age列是拿不到的

lucy20 
lucy21 
lucy22 
lucy23 
lucy24 
lucy25 
lucy26 
lucy27 
lucy28 
lucy29 
lucy30

4)、过滤器集合

/**
     * 全表扫描过滤器
     * 过滤器集合
     * @throws Exception
     */
    @Test
    public void testFilterList() throws Exception{
        Scan scan = new Scan();
        //过滤器集合:MUST_PASS_ALL(and),MUST_PASS_ONE(or)
        FilterList filterList = new FilterList(Operator.MUST_PASS_ALL);
        //ROWKEY过滤器
        RowFilter rowFilter = new RowFilter(CompareOp.EQUAL, new RegexStringComparator("^jbm"));
        //列值过滤器     age大于25
        SingleColumnValueFilter columnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), 
                Bytes.toBytes("age"), CompareOp.GREATER, Bytes.toBytes(25));
        filterList.addFilter(columnValueFilter);
        filterList.addFilter(rowFilter);
        //设置过滤器
        scan.setFilter(filterList);
        //获取结果集
        ResultScanner resultScanner = table.getScanner(scan);
        for (Result result : resultScanner) {
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name"));
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age"));
            if(name!=null){
                System.out.print(Bytes.toString(name)+" ");
            }
            if(age!=null){
                System.out.print(Bytes.toInt(age)+" ");
            }
            System.out.println();
        }
    }

输出

lucy26 26 
lucy27 27 
lucy28 28 
lucy29 29 
lucy30 30 

更多的过滤器用法

https://blog.csdn.net/m0_37739193/article/details/73615016

三、Hbase命令

hbase提供了一个shell的终端给用户交互

[root@mini1 bin]# ./hbase shell

退出使用quit或者ctrl+c即可。
注:需要关闭hadoop的安全模式不然进行一些操作,比如scan会卡住
进入到hadoop的bin目录下

[root@mini1 bin]# hadoop dfsadmin -safemode leave

接下来可以使用hbase命令来进行操作了

1、创建表
create ‘表名’,’列族1’,’列族2’,…’列族n’

create 'user1','info1','info2'

2、查看所有表
list

hbase(main):002:0> list                                                                                                                                                                         
1 row(s) in 1.4540 seconds
=> ["user1"]

3、描述表
describe ‘表名’

hbase(main):014:0> describe 'user1'
Table user1 is ENABLED                                                                                                                                                            
COLUMN FAMILIES DESCRIPTION                                                                                                                                                       
{NAME => 'info1', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => 'FOREVER', KE
EP_DELETED_CELLS => 'FALSE', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}                                                                                    
{NAME => 'info2', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => 'FOREVER', KE
EP_DELETED_CELLS => 'FALSE', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}                                                                                    
2 row(s) in 0.0790 seconds

4、删除表
注:删除表之前需要先使表disable不然直接删除会报错,会提示先disable 表
disable ‘表名’
drop ‘表名’

hbase(main):004:0> disable 'user1'
0 row(s) in 1.4110 seconds

hbase(main):005:0> drop 'user1'
0 row(s) in 0.2330 seconds
hbase(main):006:0> list
TABLE                                                                                                                                                                             
0 row(s) in 0.0450 seconds

=> []

5、判断表是否存在

hbase(main):013:0> exists 'user1'
Table user1 does exist                                                                                                                                                             
0 row(s) in 0.0980 seconds

6、向表中添加记录
create ‘表名’,’rowkey’(键),’列族:列名’,’值’

hbase(main):011:0> put 'user1','1234','info1:name','zhangsan'
0 row(s) in 0.1310 seconds

7、扫描表
扫描整张表

hbase(main):015:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:name, timestamp=1509303796190, value=zhangsan                                                                          
1 row(s) in 0.0630 seconds

注:hbase没有直接修改操作,但是可以覆盖,只要rowkey跟列族列名一致就会覆盖
比如这里要修改上面插入数据的info:name为’lisi’

hbase(main):002:0> put 'user1','1234','info1:name','list'
0 row(s) in 0.1470 seconds

hbase(main):003:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:name, timestamp=1509304915052, value=list  

但是如果rowkey相同,列族相同只要列名不同就只会添加而不会覆盖
比如插入年龄为18岁

hbase(main):004:0> put 'user1','1234','info1:age','18'
0 row(s) in 0.0500 seconds

hbase(main):005:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:age, timestamp=1509305017108, value=18                                                                                 
 1234                                         column=info1:name, timestamp=1509304915052, value=list   

8、查询记录数
注:rowkey相同的话只算一条
count ‘表名’

hbase(main):008:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:age, timestamp=1509305121972, value=18                                                                                 
 1234                                         column=info1:name, timestamp=1509304915052, value=list                                                                              
 12345                                        column=info1:age, timestamp=1509305156151, value=24                                                                                 
 12345                                        column=info2:name, timestamp=1509305221477, value=lucy                                                                              
2 row(s) in 0.0460 seconds

hbase(main):009:0> count 'user1'
2 row(s) in 0.0540 seconds

=> 2

9、查询
获取某个列族
获取某个列族的列

hbase(main):010:0> get 'user1','1234','info1'
COLUMN                                        CELL                                                                                                                                
 info1:age                                    timestamp=1509305121972, value=18                                                                                                   
 info1:name                                   timestamp=1509304915052, value=list                                                                                                 
2 row(s) in 0.0970 seconds

hbase(main):011:0> get 'user1','1234','info1:name'
COLUMN                                        CELL                                                                                                                                
 info1:name                                   timestamp=1509304915052, value=list                                                                                                 
1 row(s) in 0.0700 seconds

查询某个列,某个时间戳版本的值

get 'user1', '1234bbb', {COLUMN => 'info1:username',TIMESTAMP => 1538014481194}

Hbase中多版本(version)数据获取办法

参考https://blog.csdn.net/liuchuanhong1/article/details/53895234/
···
alter 'user',{NAME=>'info1',VERSIONS=>3}
get 'user','1234',{COLUMN=>'info1:name',VERSIONS=>3}
···

9、删除记录
可以删除一个列族的一个列记录
delete ‘表名’ ,‘rowkey’ , ‘列族:列’
也可以删除一整行
deleteall ‘表名’,’rowkey;

hbase(main):012:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:age, timestamp=1509305121972, value=18                                                                                 
 1234                                         column=info1:name, timestamp=1509304915052, value=list                                                                              
 12345                                        column=info1:age, timestamp=1509305156151, value=24                                                                                 
 12345                                        column=info2:name, timestamp=1509305221477, value=lucy                                                                              
2 row(s) in 0.0930 seconds

hbase(main):013:0> delete 'user1','1234','info1:name'
0 row(s) in 0.1160 seconds

hbase(main):014:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 1234                                         column=info1:age, timestamp=1509305121972, value=18                                                                                 
 12345                                        column=info1:age, timestamp=1509305156151, value=24                                                                                 
 12345                                        column=info2:name, timestamp=1509305221477, value=lucy                                                                              
2 row(s) in 0.0430 seconds
hbase(main):018:0> deleteall 'user1','1234'
0 row(s) in 0.0130 seconds

hbase(main):019:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
 12345                                        column=info1:age, timestamp=1509305156151, value=24                                                                                 
 12345                                        column=info2:name, timestamp=1509305221477, value=lucy                                                                              
1 row(s) in 0.0570 seconds

10、清空表
truncate ‘表名’

hbase(main):025:0> truncate 'user1'
Truncating 'user1' table (it may take a while):
 - Disabling table...
 - Truncating table...
0 row(s) in 1.5680 seconds

hbase(main):026:0> list
TABLE                                                                                                                                                                             
user1                                                                                                                                                                             
1 row(s) in 0.1010 seconds

=> ["user1"]
hbase(main):027:0> scan 'user1'
ROW                                           COLUMN+CELL                                                                                                                         
0 row(s) in 0.0400 seconds

四、HTable基本概念

从一个示例说起

传统的关系型数据库想必大家都不陌生,我们将以一个简单的例子来说明使用RDBMS和HBase各自的解决方式及优缺点。

以博文为例,RDBMS的表设计如下:

为了方便理解,我们以一些数据示例下

 

上面的例子,我们用HBase可以按以下方式设计

同样为了方便理解,我们以一些数据示例下,同时用红色标出了一些关键概念,后面会解释

 

HTable一些基本概念

  • Row key

行主键, HBase不支持条件查询和Order by等查询,读取记录只能按Row key(及其range)或全表扫描,因此Row key需要根据业务来设计以利用其存储排序特性(Table按Row key字典序排序如1,10,100,11,2)提高性能。

  • Column Family(列族)

在表创建时声明,每个Column Family为一个存储单元。在上例中设计了一个HBase表blog,该表有两个列族:article和author。

  • Column(列)

HBase的每个列都属于一个列族,以列族名为前缀,如列article:title和article:content属于article列族,author:name和author:nickname属于author列族。
Column不用创建表时定义即可以动态新增,同一Column Family的Columns会群聚在一个存储单元上,并依Column key排序,因此设计时应将具有相同I/O特性的Column设计在一个Column Family上以提高性能。

  • Timestamp

HBase通过row和column确定一份数据,这份数据的值可能有多个版本,不同版本的值按照时间倒序排序,即最新的数据排在最前面,查询时默认返回最新版本。如上例中row key=1的author:nickname值有两个版本,分别为1317180070811对应的“一叶渡江”和1317180718830对应的“yedu”(对应到实际业务可以理解为在某时刻修改了nickname为yedu,但旧值仍然存在)。Timestamp默认为系统当前时间(精确到毫秒),也可以在写入数据时指定该值。

  • Value

每个值通过4个键唯一索引,tableName+RowKey+ColumnKey+Timestamp=>value,例如上例中{tableName=’blog’,RowKey=’1’,ColumnName=’author:nickname’,Timestamp=’ 1317180718830’}索引到的唯一值是“yedu”。

  • 存储类型

TableName 是字符串
RowKey 和 ColumnName 是二进制值(Java 类型 byte[])
Timestamp 是一个 64 位整数(Java 类型 long)
value 是一个字节数组(Java类型 byte[])。

五、Hbase存储详解

Hbase是bigtable的开源山寨版本。是建立的hdfs之上,提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统。

它介于nosql和RDBMS之间,仅能通过主键(row key)和主键的range来检索数据,仅支持单行事务。主要用来存储非结构化和半结构化的松散数据。

与hadoop一样,Hbase目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加计算和存储能力。

Hbase中的表一般有这样的特点:

1 大:一个表可以有上亿行,上百万列

2 面向列:面向列(族)的存储和权限控制,列(族)独立检索。

3 稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏。

下面一幅图是Hbase在Hadoop Ecosystem中的位置。

本页无标题

二、逻辑视图

Hbase以表的形式存储数据。表有行和列组成。列划分为若干个列族(row family)

Row Key

Row Key

与nosql数据库们一样,row key是用来检索记录的主键。访问Hbase table中的行,只有三种方式:

1 通过单个row key访问

2 通过row key的range

3 全表扫描

Row key行键 (Row key)可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在Hbase内部,row key保存为字节数组。

存储时,数据按照Row key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。

注意:

字典序对int排序的结果是1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。要保持整形的自然序,行键必须用0作左填充。

行的一次读写是原子操作 (不论一次读写多少列)。

列族

Hbase表中的每个列,都归属与某个列族。列族是表的chema的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如courses:history,courses:math

都属于courses 这个列族。

时间戳

Hbase中通过row和columns确定的为一个存贮单元称为cell。每个 cell都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由Hbase(在数据写入时自动 )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。

Cell

由{row key, column, version} 唯一确定的单元。cell中的数据是没有类型的,全部是字节码形式存贮。

三、物理存储

1 已经提到过,Table中的所有行都按照row key的字典序排列。

2 Table 在行的方向上分割为多个Hregion。

本页无标题

3 region按大小分割的,每个表一开始只有一个region,随着数据不断插入表,region不断增大,当增大到一个阀值的时候,Hregion就会等分会两个新的Hregion。当table中的行不断增多,就会有越来越多的Hregion。

本页无标题

4 HRegion是Hbase中分布式存储和负载均衡的最小单元。最小单元就表示不同的Hregion可以分布在不同的HRegion server上。但一个Hregion是不会拆分到多个server上的。

5 HRegion虽然是分布式存储的最小单元,但并不是存储的最小单元。

5 HRegion虽然是分布式存储的最小单元,但并不是存储的最小单元。

事实上,HRegion由一个或者多个Store组成,每个store保存一个columns family。

每个Strore又由一个memStore和0至多个StoreFile组成。如图:

StoreFile以HFile格式保存在HDFS上。

本页无标题

Hbase基本组件说明:

Client

包含访问HBase的接口,并维护cache来加快对HBase的访问,比如region的位置信息

Master

为Region server分配region

负责Region server的负载均衡

发现失效的Region server并重新分配其上的region

管理用户对table的增删改查操作

Region Server

Regionserver维护region,处理对这些region的IO请求

Regionserver负责切分在运行过程中变得过大的region

Zookeeper作用

通过选举,保证任何时候,集群中只有一个master,Master与RegionServers 启动时会向ZooKeeper注册

存贮所有Region的寻址入口

实时监控Region server的上线和下线信息。并实时通知给Master

存储HBase的schema和table元数据

默认情况下,HBase 管理ZooKeeper 实例,比如, 启动或者停止ZooKeeper

Zookeeper的引入使得Master不再是单点故障

HBase容错性
Master容错:Zookeeper重新选择一个新的Master
无Master过程中,数据读取仍照常进行;
无master过程中,region切分、负载均衡等无法进行;
RegionServer容错:定时向Zookeeper汇报心跳,如果一旦时间内未出现心跳,Master将该RegionServer上的Region重新分配到其他RegionServer上,失效服务器上“预写”日志由主服务器进行分割并派送给新的RegionServer
Zookeeper容错:Zookeeper是一个可靠地服务,一般配置3或5个Zookeeper实例

HBase存储数据其底层使用的是HDFS来作为存储介质,HBase的每一张表对应的HDFS目录上的一个文件夹,文件夹名以HBase表进行命名(如果没有使用命名空间,则默认在default目录下),在表文件夹下存放在若干个Region命名的文件夹,Region文件夹中的每个列簇也是用文件夹进行存储的,每个列簇中存储就是实际的数据,以HFile的形式存在。路径格式如下:

/hbase/data/default/<tbl_name>/<region_id>/<cf>/<hfile_id>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值