HBase学习笔记

概述

  1. HBase原本是由Yahoo!公司开发,后来贡献给了Apache的一套开源的,基于Hadoop的,分布式的,可扩展的,支持海量数据存储的非关系型(NoSQL)数据库.
  2. 如果需要对大量数据进行随机且实时读写,那么可以考虑使用HBase.
  3. HBase能够管理非常大的表:billions of rows * millions of columns.
  4. HBase是仿照Google的Big Table来进行实现的,因此,HBase和Big Table的原理几乎一致,只是实现语言不同.HBase是使用Java语言实现的,Big Table是使用C语言实现的.
  5. HBase将数据存储在HDFS上
  6. HBase能够存储结构化(数据本身有结构,经过解析之后,能够用传统数据库中的一个或者几个表来存储)和半结构化的数据(数据本身有结构,但是解析之后无法用传统数据库中的表来存储).
  7. HBase本身作为数据库,提供了完整的增删改查功能.HBase基于HDFS来进行存储,HDFS的特点是允许一次写入多次读取,不允许修改而允许追加写入.但是HBase提供了功能,HBase实际上并没有去修改写入的数据,而是在文件的末尾去追加数据.HBase会对写入的每条数据自动添加一个时间戳,当用户获取数据的时候,HBase自动返回最新的数据,那么从用户的角度来看,就是发生了数据的修改.
  8. 在HBase中,可能会存在好几个版本的数据,数据的每一个时间戳称之为一个版本.

数据模型

1)NameSpace
命名空间,类似于关系型数据库的 DatabBase 概念,每个命名空间下有多个表。HBase有两个自带的命名空间,分别是 hbase 和 default,hbase 中存放的是 HBase 内置的表default 是用户默认使用的命名空间
2)HRegion
类似于关系型数据库的表概念。不同的是,HBase 定义表时只需要声明列族即可,不需要声明具体的列。这意味着,往 HBase 写入数据时,字段可以动态、按需指定。因此,和关系型数据库相比,HBase 能够轻松应对字段变更的场景。
3) RowKey行键

  1. 在Hbase中没有主键的概念,取而代之的是行键.
  2. 在HBase中,定义表的时候不需要指定行键列,而是在添加数据的时候手动添加行键

4)Row
HBase 表中的每行数据都由一个 RowKey 和多个 Column(列)组成,数据是按照 RowKey的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索,所以 RowKey 的设计十分重要。
5) Column Family:列族/列簇

  1. 在HBase中,没有表关联的概念,取而代之的是用列族来进行设计.
  2. 在HBase中,一个表至少要包含一个列族,可以包含多个列族,理论上不限制列族的数量,一般不超过3个.
  3. 在Hbase中强调列族,不强调列.在定义表的时候必须定义列族,列可以动态增删,一个列族中可以包含0到多个列

6)Column
HBase 中的每个列都由 Column Family(列族)Column Qualifier(列限定符)进行限定,例如 info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义。
7)TimeStamp
用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入 HBase 的时间。
8)Cell
单元格, 由{rowkey, column Family:column Qualifier, timeStamp} 唯一确定的单元。cell 中的数据是没有类型的,全部是字节码形式存储.

HBase 基本架构

1)HRegionServer
HRegionServer 为 HRegion 的管理者,主要作用如下:

  1. 对于数据的操作:get, put, delete,scan;
  2. 对于 HRegion 的操作:splitRegion、compactRegion。

2)HMaster
HMaster 是所有HRegionServer 的管理者,主要作用如下:
1.记录和存储元数据.HBase中的元数据包含namespace名,table名,columnfamily名以及属性信息等.注意,在HBase中,列不是元数据,因为列可以动态增删. 对于表的操作create, drop等以及namespace操作都会产生元数据
2. 对于 HRegionServer的操作:管理HRegionServer,但是需要注意的是,HMaster对HRegionServer的管理权限并不大,它只能决定HRegion交由哪一个HRegionServer来进行管理.监控每个 HRegionServer的状态,负载均衡和故障转移。

3)Zookeeper
HBase 通过 Zookeeper 来做 HMaster 的高可用、HRegionServer 的监控、元数据的入口以及集群配置的维护等工作。
4)HDFS
HDFS 为 HBase 提供最终的底层数据存储服务,同时为 HBase 提供高可用的支持

HBase 安装部署

1.下载hbase-2.4.2-bin.tar.gz并上传
官网下载hbase-2.4.2-bin.tar.gz
2.首先保证 Zookeeper 集群的正常部署,并启动之




3.Hadoop 集群的正常部署并启动HDFS

4.将hbase-2.4.2-bin.tar.gz解压到指定目录:

5.进入到hbase-2.4.2/conf目录下,修改 HBase 对应的配置文件
hbase-env.sh 修改内容:

false代表的是关闭HBase自带的Zookeeper,让它使用我们自己安装的Zookeeper

hbase-site.xml 修改内容(先将<configuration></configuration>之间的内容删除掉):
注意:hbase.rootdir端口号要跟$HADOOP_HOME/etc/hadoop/core-site.xml中的fs.defaultFS的端口号一致

<configuration>
        <!--指定HBase在HDFS上的数据存储目录-->
        <property>
                <name>hbase.rootdir</name>
                <value>hdfs://hadoop102:8020/HBase</value>
        </property>
        <!--开启HBase的分布式-->
        <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
        </property>
        <!--配置Zookeeper的连接地址-->
        <property>
                <name>hbase.zookeeper.quorum</name>
                <value>hadoop102:2181,hadoop103:2181,hadoop104:2181</value>
        </property>
        <property>
                <name>hbase.zookeeper.property.dataDir</name>
                <value>/opt/module/zookeeper-3.5.7/zkData</value>
        </property>
        <property>
                <name>hbase.unsafe.stream.capability.enforce</name>
                <value>false</value>
        </property>
        <property>
                <name>hbase.wal.provider</name>
                <value>filesystem</value>
        </property>
</configuration>

6.打开regionservers,添加当前的三台主机的主机名


添加如下内容:

hadoop102
hadoop103
hadoop104

7.将hadoop的核心配置文件拷贝到当前的HBase的配置目录下

8.HBase 远程拷贝给另外两台主机

xsync文件内容:

#!/bin/bash
if [ $# -lt 1 ]
then
        echo "Not Enough Arguement!"
        exit;
fi
for host in hadoop102 hadoop103 hadoop104
do
        echo =========== $host ===========
        for file in $@
        do
                if [ -e $file ]
                then
                        pdir=$(cd -P $(dirname $file);pwd)
                        fname=$(basename $file)
                        ssh $host "mkdir -p $pdir"
                        rsync -av $pdir/$fname $host:$pdir
                else
                        echo $file does not exists!
                fi
        done
done

9.配置三台主机的环境变量(注:我的环境变量是配置在my_env.sh中的,你也可以配置在/etc/profile)

my_env.sh添加如下内容:


HBase 服务的启动

1.启动Hbase
启动方式1:


提示:如果集群之间的节点时间不同步,会导致 regionserver 无法启动,抛出ClockOutOfSyncException 异常。
a、同步时间服务 (第一种方法)
b、属性:hbase.master.maxclockskew 设置更大的值 (第二种)

<property>
 <name>hbase.master.maxclockskew</name>
 <value>180000</value>
 <description>Time difference of regionserver from master</description>
</property>

启动方式2:

2.停止HBase:

启动成功后,可以通过“ip:port”的方式来访问 HBase 管理页面,例如:
http://hadoop102:16010

HBase Shell 操作

1.进入 HBase 客户端命令行

2.查看帮助命令
在这里插入图片描述
3.查看当前数据库中有哪些表

4.查看当前HBase在执行的任务
在这里插入图片描述

5.查看HBase的运行状态
在这里插入图片描述

6.查看HBase的版本
在这里插入图片描述

7.查看HBase的当前用户
在这里插入图片描述

8.建一张person表,包含3个列族:basic,info,other
在这里插入图片描述
等价写法:

9.向person表中添加一个行键为p1的数据,向basic列族的name列中添加数据

在这里插入图片描述
10.获取指定行键的数据

11.获取指定行键,指定列族的数据
在这里插入图片描述
等价写法:
在这里插入图片描述

12.获取指定行键多列族的数据
在这里插入图片描述
等价的写法:
在这里插入图片描述

13.获取指定行键指定列的数据
在这里插入图片描述
等价的写法:
在这里插入图片描述
14.扫描整表
在这里插入图片描述

15.获取指定列族的数据(注意:scan是没有类似于上面的等价写法的)
在这里插入图片描述

16.获取多个列族的数据
在这里插入图片描述

17.获取多个列的数据
在这里插入图片描述

18.修改数据
在这里插入图片描述

19.删除指定行键指定列族的指定列
在这里插入图片描述

20.删除指定行键的所有数据 (注意:无法删除列族)
在这里插入图片描述
21.指定每一个列族允许获取的版本数
在这里插入图片描述

22.描述表的基本信息
在这里插入图片描述
等价的写法:
在这里插入图片描述

23.获取指定行键指定列的指定版本数的数据
在这里插入图片描述
24.获取指定列的指定版本数的数据
在这里插入图片描述
25.统计person表中行键的个数
在这里插入图片描述

26.获取person表对应的HRegion的个数
在这里插入图片描述

27.摧毁重建person表
在这里插入图片描述

28.查看所有的空间
在这里插入图片描述

29.创建damo空间
在这里插入图片描述

30.在damo空间下创建users表
在这里插入图片描述

31.获取damo空间下所有的表
在这里插入图片描述

32.描述damo空间
在这里插入图片描述

33.删除damo空间,要求这个空间为空
在这里插入图片描述
34.禁用表(想要删除表,必须要先禁用表才能删除)
在这里插入图片描述

35.删除表
在这里插入图片描述

36.启用表
在这里插入图片描述

37.判断表是否存在
在这里插入图片描述

38.判断person表是否被禁用
在这里插入图片描述

39.判断person表是否被启用
在这里插入图片描述

40.查看所有空间下的所有的表
在这里插入图片描述

41.定位s1行键所在的HRegion的位置
在这里插入图片描述

42.展现所有的过滤器
在这里插入图片描述

43.禁用demo空间下所有的表(:可省略)
在这里插入图片描述

44.删除demo空间下所有的表(:已省略)
在这里插入图片描述

45.启用demo空间下所有的表(:可省略)
在这里插入图片描述

HBase API

新建项目后在 pom.xml 中添加依赖:

<properties>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-common</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-protocol</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-mapreduce</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-zookeeper</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>compile</scope>
        </dependency>
    </properties>

创建空间

public void createNameSpace() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //获取管理权
        Admin admin = connection.getAdmin();
        //构建空间描述器
        NamespaceDescriptor descriptor = NamespaceDescriptor.create("space1").build();
        //创建space1空间
        admin.createNamespace(descriptor);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

获取所有的命名空间

public void listNamespace() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //获取管理权
        Admin admin = connection.getAdmin();
        //获取所有的命名空间
        String[] spaces = admin.listNamespaces();
        System.out.println(Arrays.toString(spaces));
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

删除空间

public void deleteNamespace() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //获取管理权
        Admin admin = connection.getAdmin();
        //删除space1空间
        admin.deleteNamespace("space1");
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

创建表

public void createTable() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //获取管理权
        Admin admin = connection.getAdmin();
        //构建列族描述器
        ColumnFamilyDescriptor cf1 = ColumnFamilyDescriptorBuilder.newBuilder("basic".getBytes(StandardCharsets.UTF_8)).build();
        ColumnFamilyDescriptor cf2 = ColumnFamilyDescriptorBuilder.newBuilder("info".getBytes(StandardCharsets.UTF_8)).build();
        //构建表描述器
        TableDescriptor users = TableDescriptorBuilder.newBuilder(TableName.valueOf("users")).setColumnFamily(cf1).setColumnFamily(cf2).build();
        //创建表
        admin.createTable(users);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

往表中添加数据

public void appendData() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //获取管理权
        Admin admin = connection.getAdmin();
        //构建Append对象(指定行键)
        Append append = new Append("u1".getBytes(StandardCharsets.UTF_8));
        //指定列族
        byte[] basic = "basic".getBytes(StandardCharsets.UTF_8);
        byte[] info = "info".getBytes(StandardCharsets.UTF_8);
        //指定列和数据
        append.addColumn(basic, "name".getBytes(StandardCharsets.UTF_8), "Bob".getBytes(StandardCharsets.UTF_8));
        append.addColumn(basic,"age".getBytes(StandardCharsets.UTF_8),"20".getBytes(StandardCharsets.UTF_8));
        append.addColumn(basic,"sex".getBytes(StandardCharsets.UTF_8),"male".getBytes(StandardCharsets.UTF_8));
        append.addColumn(info,"address".getBytes(StandardCharsets.UTF_8),"beijing".getBytes(StandardCharsets.UTF_8));
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //添加数据
        users.append(append);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

修改表中的数据

    //添加/修改数据(put可以一条一条地添加,也可以一批一批地添加数据)
    public void putData() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //获取管理权
        Admin admin = connection.getAdmin();
        //构建Put对象
        Put put = new Put("u1".getBytes(StandardCharsets.UTF_8));
        //指定列和数据
        put.addColumn("basic".getBytes(StandardCharsets.UTF_8),"passwd".getBytes(StandardCharsets.UTF_8),"12345678".getBytes(StandardCharsets.UTF_8));
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //添加/修改数据
        users.put(put);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

添加百万条数据

public void putMillionData() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //指定列族
        byte[] basic = "basic".getBytes(StandardCharsets.UTF_8);
        //指定列
        byte[] passwd = "passwd".getBytes(StandardCharsets.UTF_8);
        //构建一个集合实现批量添加数据
        ArrayList<Put> puts = new ArrayList<>();
        //记录起始时间
        long begin = System.currentTimeMillis();
        //添加百万条数据
        for(int i=0;i<1000000;i++){
            //构建Put对象
            Put put = new Put(("u" +i).getBytes(StandardCharsets.UTF_8));
            //添加数据
            put.addColumn(basic,passwd,getPasswd());
            //将put对象放到puts集合中
            puts.add(put);
            //  每1000条向users表中添加一次
            if(puts.size()>=1000){
                users.put(puts);
                //清空集合
                puts.clear();
            }
        }
        //记录结束时间
       long end=System.currentTimeMillis();
        System.out.println(end-begin);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }
    //产生6位大写字母的随机密码
    private byte[] getPasswd() {
        StringBuilder sb = new StringBuilder();
        for(int i = 0;i < 6;i++){
         char c= (char)(Math.random()*26+65);
         sb.append(c);
        }
        return sb.toString().getBytes(StandardCharsets.UTF_8);
    }

获取一行数据(指定行键)

public void getLine() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Get对象
        Get get = new Get("u1".getBytes(StandardCharsets.UTF_8));
        //查询数据,获取结果
        Result result = users.get(get);
        //获取一行数据
        NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> families = result.getMap();
        for (Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> family : families.entrySet()) {
            // 键表示的是列族名
            System.out.println("Column Family:"+new String(family.getKey()));
            // 值表示的是这个列族所包含的列
            NavigableMap<byte[], NavigableMap<Long, byte[]>> columns = family.getValue();
            for (Map.Entry<byte[], NavigableMap<Long, byte[]>> column : columns.entrySet()) {
                // 键表示的是列名
                System.out.println("Column:"+new String(column.getKey()));
                // 值表示的是实际数据
                NavigableMap<Long, byte[]> values = column.getValue();
                for (Map.Entry<Long, byte[]> value : values.entrySet()) {
                    // 键表示的是时间戳
                    System.out.println("Timestamp:"+value.getKey());
                    //值表示的是实际的值
                    System.out.println("value:"+new String(value.getValue()));
                }
            }
        }
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

获取指定行键指定列族的数据

public void getFamily() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Get对象
        Get get = new Get("u1".getBytes(StandardCharsets.UTF_8));
        //指定列族
        get.addFamily("basic".getBytes(StandardCharsets.UTF_8));
        //查询数据,获取结果
        Result result = users.get(get);
        //获取数据
        NavigableMap<byte[], byte[]> columns = result.getFamilyMap("basic".getBytes(StandardCharsets.UTF_8));
        for (Map.Entry<byte[], byte[]> column : columns.entrySet()) {
            // 键是列族中所包含的列名,值是实际数据
            System.out.println(new String(column.getKey())+" = "+new String(column.getValue()));
        }
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

获取指定行键指定列的数据

public void getList() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Get对象
        Get get = new Get("u1".getBytes(StandardCharsets.UTF_8));
        // 指定列
        byte[] basic = "basic".getBytes(StandardCharsets.UTF_8);
        byte[] passwd = "passwd".getBytes(StandardCharsets.UTF_8);
        get.addColumn(basic,passwd);
        //查询数据,获取结果
        Result result = users.get(get);
        // 获取实际数据
        byte[] value = result.getValue(basic, passwd);
        System.out.println(new String(value));
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

遍历数据(获取指定列的数据scan)

 public void scan() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Scan对象
        // Scan scan = new Scan(); //扫描整表
        Scan scan = new Scan("u100".getBytes(StandardCharsets.UTF_8)); //从指定行键开始
        //获取结果集
        ResultScanner result = users.getScanner(scan);
        //遍历结果集
        byte[] basic = "basic".getBytes(StandardCharsets.UTF_8);
        byte[] passwd = "passwd".getBytes(StandardCharsets.UTF_8);
        for (Result r : result) {
            byte[] value = r.getValue(basic, passwd);
            System.out.println(new String(value));
        }
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

遍历过程中过滤数据

public void filter() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Scan对象
        Scan scan = new Scan();
        //封装Filter对象,匹配有AAA(3个A)的密码,过滤掉相等的
        ValueFilter valueFilter = new ValueFilter(CompareOperator.EQUAL, new RegexStringComparator(".*AAA.*"));
        //设置过滤器
        scan.setFilter(valueFilter);
        //获取结果集
        ResultScanner rs= users.getScanner(scan);
        byte[] basic = "basic".getBytes(StandardCharsets.UTF_8);
        byte[] passwd = "passwd".getBytes(StandardCharsets.UTF_8);
        //遍历结果集
        for (Result r : rs) {
            byte[] value = r.getValue(basic, passwd);
            System.out.println(new String(value));
        }
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

删除指定行键指定列的数据

public void deleteData() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Delete对象
        Delete delete = new Delete("u1".getBytes(StandardCharsets.UTF_8));
        //指定列族指定列
        delete.addColumn("basic".getBytes(StandardCharsets.UTF_8),"age".getBytes(StandardCharsets.UTF_8));
        //删除数据
        users.delete(delete);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

删除指定行键指定列族的数据

public void deleteFamily() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Delete对象
        Delete delete = new Delete("u1".getBytes(StandardCharsets.UTF_8));
        //指定列族
        delete.addFamily("info".getBytes(StandardCharsets.UTF_8));
        //删除数据
        users.delete(delete);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

删除指定行键的数据

public void deleteRowkey() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //指定要操作的表
        Table users = connection.getTable(TableName.valueOf("users"));
        //获取管理权
        Admin admin = connection.getAdmin();
        //封装Delete对象
        Delete delete = new Delete("u1".getBytes(StandardCharsets.UTF_8));
        //删除数据
        users.delete(delete);
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

删除表

public void deleteFamily() throws IOException {
        //获取HBase的配置
        Configuration conf = HBaseConfiguration.create();
        //配置Zookeeper的连接地址
        conf.set("hbase.zookeeper.quorum","hadoop102:2181,hadoop103:2181,hadoop104:2181");
        //发起连接
        Connection connection = ConnectionFactory.createConnection(conf);
        //获取管理权
        Admin admin = connection.getAdmin();
        //禁用表
        admin.disableTable(TableName.valueOf("users"));
        //删除表
        admin.deleteTable(TableName.valueOf("users"));
        //关闭管理权
        admin.close();
        //关闭连接
        connection.close();
    }

HBase基本架构

HRegion

  1. 在HBase中,会将一个表从行键方向上进行切分,切分成1个或多个HRegion
  2. 切分之后,每一个HRegion都会交给某一个HRegionServer来进行管理
  3. 一个表至少会包含1个HRegion,可以包含多个HRegion
  4. 在HBase中,行键是有序的,所以HRegion之间的数据是不交叉的
  5. 因为HRegion会交给HRegionServer来管理,并且HRegion之间的数据是相互不交叉的,所以能保证请求不会集中在某一个节点上而是会分散到不同的节点上
  6. 随着时间的推移,HRegion管理的数据会不断增多,达到指定的条件时,会自动的进行分裂
  7. 每一个HRegion包含一个或多个HStore,HStore的数量由列族的数量决定.
  8. 每一个HStore都会包含1个memStore以及包含0到多个StoreFile/HFile

在这里插入图片描述

  1. StoreFile
    存储实际数据的物理文件.每个 HStore 会有0个或多个 StoreFile(HFile),数据在每个 StoreFile 中都是有序的。
  2. MemStore
    写缓存,由于 HFile 中的数据要求是有序的,所以数据是先存储在 MemStore 中,排好序后,等到达刷写时机才会刷写到 HFile,每次刷写都会形成一个新的 HFile。
  3. WAL
    由于数据要经 MemStore 排序后才能刷写到 HFile,但把数据保存在内存中会有很高的概率导致数据丢失,为了解决这个问题,数据会先写在一个叫做 Write-Ahead logfile 的文件中,然后再写入 MemStore 中。所以在系统出现故障的时候,数据可以通过这个日志文件重建

Zookeeper

  1. 在HBase中,Zookeeper充当了注册中心
  2. 当HBase启动后,会自动地在Zookeeper上来注册一个/hbase节点
  3. 当Active HMaster启动之后,会自动的在Zookeeper上注册一个临时节点/hbase/master,当Active HMaster宕机之后,这个临时节点就会消失,此时Zookeeper就会从Backup HMaster中选择最早注册的节点来切换为Active状态
  4. 当Backup HMaster启动之后,会自动的在Zookeeper的/hbase/backup-masters节点上注册一个临时子节点
  5. 当HRegionServer启动之后,也会自动的在Zookeeper的/hbase/rs节点下注册一个临时子节点

HMaster

  1. 在Hbase中,允许用户在任意一台安装了Hbase的节点上启动HMaster,理论上不限制HMaster的数量
  2. 在HBase中,如果启动了多个HMaster,那么HMaster之间就会分为Active和Backup两种状态
  3. 如果启动多个HMaster,那么最先注册到Zookeeper上的HMaster就会成为Active状态,后注册到Zookeeper上的HMaster就会成为Backup状态.
  4. 当Active HMaster接收到请求之后,需要考虑将数据同步给其它的Backup HMaster.同步的节点数量越多,此时效率就会越低.
  5. 因此在HBase中,虽然理论上不限制HMaster的个数,但是实际过程中,HMaster的个数不会超过3个:1个Active HMaster+2个Backup HMaster.
  6. Active HMaster会实时监控Zookeeper上/hbase/backup-masters下的节点变化以确定需要同步(数据)的节点是哪几个

HBase 写流程

在这里插入图片描述

1)Client 先发送请求到 zookeeper,请求获取 hbase:meta 表位于哪个 HRegion Server。
2) Zookeeper收到请求之后,会将hbase:meta表的位置返回给客户端.
3)客户端访问对应的 HRegion Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,查询出目标数据位于哪个 HRegion Server 中的哪个 HRegion 中。
4)与目标 HRegion Server 进行通讯;
5)将数据顺序写入(追加)到 WAL;
6)将数据写入对应的 MemStore,数据会在 MemStore 进行排序;
7)向客户端发送 ack;
8)等达到 MemStore 的刷写时机后,将数据刷写到 HFile。
注意问题:

  1. 当客户端第一次请求Zookeeper之后,会自动缓存hbase:meta表的位置,之后客户端的每次请求就可以不用再访问Zookeeper
  2. 当客户端获取到HRegion的位置之后,也会自动缓存这个HRegion的位置,之后如果还操作这个HRegion,就可以直接访问
  3. 随着时间的推移,客户端缓存的位置越来越多,此时效率就会越来越高.但是,如果客户端发生宕机,那么此时就会导致缓存崩溃,那么需要重新建立缓存.

HRegionServer

  1. 在实际生产过程中,一般会考虑将HRegionServer和DataNode部署在相同的节点上,避免频繁的跨节点的请求
  2. HRegionServer的作用是管理HRegion,每一个HRegionServer默认大概能够管理1000个HRegion,每一个HRegion默认能够最多管理10G数据
  3. 每一个HRegionServer包含三部分结构:1到多个WAL,1个BlockCache以及0到多个HRegion
    在这里插入图片描述

WAL:发生写操作之前的日志

  1. 当HRegionServer接收到写请求之后,会先试图将请求记录到WAL中,之后再将数据更新到对应的memStore中
  2. 通过WAL这个机制,能够有效的保证数据不会丢失,但是因为WAL是落地在磁盘上的,因此会导致写入效率在一定程度上会降低.因此在实际过程中,如果能够容忍一定程度上的数据丢失并且想要提高写入效率,那么此时可以考虑关闭WAL机制
  3. 在HBase0.94版本之前,WAL只能采用串行写机制;从HBase0.94版本开始,引入了NIO中的Channel机制,使得WAL支持使用并行写机制,从而保证效率能够提升

BlockCache:数据块缓存

  1. BlockCache本质上是一个读缓存,维系在内存中,默认大小是128M
  2. 在HBase中,在读取数据的时候,会将读取到的数据放到BlockCache中,从而下次再次读取数据的时候,可以从BlockCache中读取,减少对HStore的读取
  3. BlockCache在缓存的时候,还采用了"局部性"原理:
    a.时间局部性:在HBase中,如果一条数据被读取过,那么HBase会认为这条数据被再次读取的概率会高于其它没有被读取过的数据,那么此时HBase就会将这条数据放到缓存中(只要是读取过的数据都会被放到缓存中)
    b.空间局部性:在Hbase中,如果一条数据被读取过,那么HBase会认为与这条数据相邻的数据被读取的概率会高于其它不相邻的数据,那么此时HBase就会将与这条数据相邻的数据也放到缓存中
    随着时间的推移,BlockCache会被放满,那么此时BlockCache就会采用LRU(Least Recently Userd,最近最少使用的数据就会被清理掉)策略.

HRegion

HBase分布式存储和管理的基本结构,但不是数据存储的最小单位.

  1. 每一个HRegion会至少包含1个HStore,可以包含多个HStore,HStore的数量由列族的数量来决定
  2. 每一个HStore中会包含1个memStore以及0到多个HFile/StoreFile
  3. memStore本质上是一个写缓存,维系在内存中,大小默认是128M,可以通过hbase.hregion.max.filesize属性来调节
  4. 当达到一定条件时,就会将memStore进行冲刷,冲刷产生HFile.HFile最终以Block的形式落地到DataNode上
  5. memStore的冲刷条件:
    a.当memstroe 的大小达到了 hbase.hregion.memstore.flush.size(默认值 128M),会自动的进行冲刷,产生一个HFile
    b.当距离上一次冲刷达到指定时间间隔(默认是1h,可以通过属性hbase.regionservers.optionalcacheflushinterval来修改,单位是毫秒)之后,也会自动的冲刷memStore产生HFile
    c.当某一个HRegionServer上所有的memStore所占内存之和/实际物理内存>0.4,那么会冲刷当前HRegionServer上较大的几个memStore(HRegion 会按照其所有 memstore 的大小顺序(由大到小)依次进行刷写),直到这个值小于0.4为止
    d.随着时间的推移,第三个条件更容易满足,此时会产生大量的小文件

Compaction机制

由于memstore每次刷写都会生成一个新的HFile,且同一个字段的不同版本(timestamp)和不同类型(Put/Delete)有可能会分布在不同的 HFile 中,因此查询时需要遍历所有的 HFile。为了减少 HFile 的个数,以及清理掉过期和删除的数据,会进行 StoreFile Compaction。
在HBase中,提供了2种Compaction机制:minor compact和major compact

  1. minor compact
    初次合并.在合并的时候,会将当前HStore中相邻的几个小的HFile合并成一个大的HFile,原本就是大的HFile不参与合并,因此合并完成之后依然存在多个HFile
  2. major compact
    主要合并.在合并的时候,会将当前HStore中的所有HFile进行合并,因此合并完成之后只存在一个HFile

相对而言,minor compact合并效率更高一些,HBase中默认采用的合并机制是minor compact.实际过程中,也会使用major compact,但是因为major compact的效率较低,需要对大量数据进行读写,因此一般是放在相对空闲的时间来进行.
需要注意的是,在major compact的时候,会自动清理掉被标记为删除的数据或者是过时的数据

写流程(补充)

  1. 当HRegionServer接收到写请求的时候,会先将这个写请求记录到WAL中,记录成功之后,再将数据更新到memStore中
  2. 数据在memStore中会进行排序,按照行键字典序->列族字典序->列字典序->时间戳倒序来进行排序
  3. 当达到冲刷条件的时候,memStore会自动冲刷产生HFile.HFile最终会以Block形式落地到HDFS的DataNode上

在这里插入图片描述
a. DataBlock:数据块.用于存储数据
每一个HFile中包含1个到多个DataBlock,DataBlock是数据存储的基本结构/最小单位.
因为HFile中的数据是有序的,所以切分出来的DataBlock之间的数据是不交叉的.
DataBlock大小默认是64KB.小的DataBlock利于查询get,大的DataBlock利于遍历scan.
每一个DataBlock都是由1个Magic(魔数)以及1到多个KeyValue来构成的.

  1. Magic:魔数,本质上就是一个随机数,用于校验的.
  2. KeyValue:存储数据,每一条数据最终都会以键值对的形式来进行存储

在这里插入图片描述

b. MetaBlock:元数据块.用于存储元数据的.注意,不是所有的HFile都包含这一部分,一般只有hbase:meta表对应的HFile会包含这一部分
c. FileInfo:文件信息.用于记录HFile大小,所属HStore等信息
d. DataIndex:数据索引,用于记录DataBlock的索引
e. MetaIndex:元数据索引,用于记录MetaBlock的索引
f. Trailer:文件末尾,占用固定的字节大小,用于记录FileInfo,DataIndex和MetaIndex在文件中的起始字节
在HFile中,需要先读取文件末尾,通过Trailer来锁定DataIndex的位置,然后读取DataIndex,通过DataIndex来定位DataBlock的位置

读流程

  1. Client 先访问 zookeeper,获取 hbase:meta 表位于哪个 HRegion Server。
  2. 访问对应的 Region Server,获取 hbase:meta 表,根据读请求的 namespace:table/rowkey,查询出目标数据位于哪个 HRegion Server 中的哪个 HRegion 中。并将该 table 的 region 信息以及 meta 表的位置信息缓存在客户端的 meta cache,方便下次访问。
  3. 与目标 Region Server 进行通讯;当HRegionServer接收到读请求的时候,会先考虑从BlockCache中获取数据
  4. 如果BlockCache中没有目标数据,那么会试图从memStore中来获取
  5. 如果memStore中也没有目标数据,那么会试图从HFile中来获取.在读取HFile的时候,可以先根据行键范围进行筛选,筛选掉不符合范围的HFile,但是不代表剩余的HFile中一定有要找的数据.筛选完之后,如果开启了布隆过滤器,那么可以利用布隆过滤器再次筛选,被筛选掉的文件一定没有要找的数据,但是不代表剩余的文件中一定有要找的数据.
  6. 将在 Block Cache(读缓存),MemStore 和 Store File(HFile)中查询到的所有目标数据进行合并。此处所有数据是指同一条数据的不同版本(time stamp)或者不同的类型(Put/Delete)。
  7. 将从文件中查询到的数据块(Block,HFile 数据存储单元,默认大小为 64KB)缓存到Block Cache。
  8. 将合并后的最终结果返回给客户端

布隆过滤器(BloomFilter)在使用的时候,需要定义一个字节数组和3个不同的哈希函数.当有了数据之后,利用这3个哈希函数对数据进行映射,映射到数组的不同位置上.
在BloomFilter中,如果映射到了0,那么说明这个元素一定不存在,但是如果映射到了1,不代表元素存在,BloomFilter只能判断元素没有,不能判断元素有
BloomFilter的优势在于理解和实现过程相对容易,但是缺点也同样明显:随着元素个数的增多,数组中空闲的位置会越来越少,此时误判率也会越来越高-----数组扩容
在这里插入图片描述

Region Split

默认情况下,每个 Table 起初只有一个 Region,随着数据的不断写入,Region 会自动进行拆分。刚拆分时,两个子 Region 都位于当前的 Region Server,但处于负载均衡的考虑,HMaster 有可能会将某个 Region 转移给其他的 Region Server。
在这里插入图片描述

设计与优化

  1. 行键设计
    a.行键在设计的时候要尽量的散列,例如可以考虑使用哈希,加密算法等使结果散列,这样能保证请求不会集中在一个节点上
    b.行键设计最好有意义,如果行键真的完全随机,会增加查询难度,例如:订单的行键可以设计为:210510abj025 -> 520jba015012
    c.行键在使用的时候要保证唯一
  2. 列族设计
    a.在HBase中虽然理论上不限制列族的数量,但是实际过程中,一个表中的列族数量一般不超过3个
    b.在设计列族的时候,要尽量将具有相同特性的数据或者经常使用的数据放在一个列族中,尽量避免跨列族查询
  3. 调节DataBlock的大小,小的DataBlock利于查询,大的DataBlock利于遍历.在建表的时候,就可以根据当前场景来确定DataBlock的大小.例如create 'person',{NAME => 'basic',BOLCKSIZE ='32768'}
  4. 关闭BlockCache.如果HBase的遍历较多,此时没有必要将数据放到读缓存中.此时可以考虑关闭BlockCache.
    create 'person',{NAME => 'basic',BLOCKCACHE => 'false'}
    alter 'person',{NAME => 'basic',BLOCKCACHE => 'false'}
  5. 更改BloomFilter的级别.BloomFilter支持三种方式:NONE,ROW以及ROWCOL.NONE不使用BloomFilter,如果节点硬件性能一般,可以考虑关闭BloomFilter,ROW对行键进行过滤,BloomFilter默认就是这个值,ROWCOL表示对行键,列族和列同时进行过滤,如果节点硬件性能较好,可以使用这个值.
  6. 开启数据压缩机制.如果HBase占用了大量的HDFS空间,导致HDFS空间不够,那么可以考虑对HBase上的数据进行压缩.通过COMPRESSION属性来修改,支持NONE,LZO,SNAPPY和GZIP.其中NONE表示不压缩,HBase默认不压缩.
  7. 在查询的时候可以考虑显式的指定列,此时可以减少在网络中传输的数据量.
  8. 如果数据量较大,那么在读写的时候可以考虑使用批量读写
  9. 关闭WAL.如果想要提高写入效率,又能够容忍一定的数据丢失,那么可以考虑关闭WAL
  10. 预创建HRegion.当HRegion管理的数据比较多(默认是10G)的时候,会进行分裂.HRegion分裂之后可能会发生管理权的转移,此时HRegion的分裂和转移都要花费时间.因此在能够预估数据量的前提下,可以考虑在建表的时候就构建多个HRegion.
  11. 调整Zookeeper的有效Session时长, 默认情况下,HMaster和Zookeeper之间通过心跳来保证联系,心跳间隔时间默认是180s,也就意味着HMaster每隔3min向Zookeeper发送一次心跳.如果HMaster发生了故障,那么可能Zookeeper需要在3min之后才发现故障.在业务高峰期,HBase有3min不能使用,此时会造成大量的损失.因此需要调节这个时长,通过属性zookeeper.session.timeout来调节,单位是秒,放在hbase-site.xml

HBase 与 Hive 的对比

1.Hive
(1) 数据仓库
Hive 的本质其实就相当于将 HDFS 中已经存储的文件在 Mysql 中做了一个双射关系,以
方便使用 HQL 去管理查询。
(2) 用于数据分析、清洗
Hive 适用于离线的数据分析和清洗,延迟较高。
(3) 基于 HDFS、MapReduce
Hive 存储的数据依旧在 DataNode 上,编写的 HQL 语句终将是转换为 MapReduce 代码执行。
2.HBase
(1) 数据库
是一种面向列族存储的非关系型数据库。
(2) 用于存储结构化和非结构化的数据
适用于单表非关系型数据的存储,不适合做关联查询,类似 JOIN 等操作。
(3) 基于 HDFS
数据持久化存储的体现形式是 HFile,存放于 DataNode 中,被 ResionServer 以 region 的形式进行管理。
(4) 延迟较低,接入在线业务使用
面对大量的企业数据,HBase 可以直线单表大量数据的存储,同时提供了高效的数据访问速度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值