天天看点

HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

文章目录

  • Apache HBase简介
    • HBase架构
      • HBase读取数据流程
      • HBase写入数据流程
  • HBase安装部署
  • Hbase Shell命令
    • 基本命令
    • 表操作
  • HBase API操作
  • 总结
  • 参考资料

Apache HBase简介

Apache HBase™是Hadoop数据库,是一个分布式,可扩展的大数据存储。

当您需要对大数据进行随机,实时读/写访问时,请使用Apache HBase™。HBase是一个分布式的、面向列的开源数据库,该技术来源于Fay Chang所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系型数据为,它是一个适合于非结构数据存储的数据库。另一个不同的是HBase是基于列的而不是基于行的模式。

官网地址:http://hbase.apache.org/

HBase架构

HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

角色关系:

角色 说明
Client 发起HBase读写请求的客户端
Zookeeper 记载了HBase的元数据信息,其中主要是-ROOT-表所在的位置信息
HMaster 用于分配RegionServer的Region,负载均衡等作用
HRegionServer Hbase集群的一个服务器
HLog HBase日志,用于保证数据的完整性
HRegion 相当于一个表
Store 抽象的表示,表示字段的存储
MemStore 内存的存储
StoreFile 字段数据具体存在的文件
HFile 当发生溢写时,生成的文件,此文件会通过DFS Client发送到HDFS
DataNode HDFS上具体存储数据的地方

Apache HBase是构建在HDFS之上的一个组件,快速的读/写访问可以满足大数据读/写的实时性,解决了HDFS存储文件的实时性问题。

当读取数据时,HBase首先会从Zookeeper集群中获取元数据信息,以便定位数据所在的HRegion,如果MemStore存在数据,则直接返回。

当写入数据时,首先会把数据写入到StoreFile中,当StoreFile达到一定的阈值时,会溢写到HDFS中,溢写成功后,会把StoreFile文件清空。先经过StoreFile的存储是为了避免频繁访问HDFS文件太系统,提高存储性能。

下面再对HBase的读/写进行更详细的分析。

HBase读取数据流程

HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

步骤:

  1. HBase客户端发出读取请求,先访问zk集群;
  2. zk集群返回-ROOT-表的位置信息;
  3. HBase客户端根据zk集群返回的信息找到-ROOT-表,一个-ROOT-表只能存储在一个HRegion中,不可切分,.-ROOT-记录了.META表的Region信息;
  4. 通过-ROOT-表再找到.META表的元数据信息,.META表记录了用户创建的表的Region信息,.META可以有多个Region;
  5. 从 .META表中获取要查询的数据的元数据信息;
  6. 根据.META返回的元数据信息,找到对应的HRegion;
  7. HRegion返回数据到客户端。

上图中描述了一个HBase客户端发起读取请求后的整体流程,下面再具体讲解一个如何从HRegion获取要查询的数据。

HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

Memstore是内存写入缓存,BlockCache是内存读取缓存。

HBase在写入数据时,首先会把数据写入到Memstore中,达到一个阈值后会溢写到HDFS生成HFile文件。

当HBase读取数据时,如果从HDFS获取数据,首先会缓存到BlockCache中,然后再返回给客户端。

步骤分析:

  1. HBase客户端请求获取数据,首先从Memstore查找数据;
  2. 因为没有达到阈值之前,要写入的数据还会在Memstore中,所以,如果此时再读取,可以马上查找并返回。因为没有达到阈值之前,要写入的数据还会在Memstore中,所以,如果此时再读取,可以马上查找并返回;
  3. 当Memstore没有查找到数据时,代表数据可能已溢写到hdfs中,此时先查找一下BlockCache,BlockCache是读取缓存,如果要读取的数据之前从HDFS中读取过,会在BlockCache中缓存下来,此时查找就可能会查找到结果并立即返回;
  4. 当在BlockCache没有查找到数据时,此时才会从HDFS中查找数据;
  5. 当从HDFS查找到数据后,首先会把数据缓存到BlockCache;
  6. 然后再从BlockCache返回数据到HBase客户端。

注意,上面的Memstore,BlockCache和HFile都是分布式存储

HBase写入数据流程

HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

步骤分析:

  1. HBase客户端请求zk集群获取表元数据;
  2. zk集群返回表的元数据信息,-ROOT-和.Meta表的元数据;
  3. HBase客户端通过-ROOT-和.Meta表的元数据获取到可以写入数据的Region,并通过RPC协议与RegionServer进行交互;
  4. 数据首先写入到HLog中,HLog是为了防止数据丢失,以便使数据可恢复,保证数据的完整性;
  5. 然后再写入到Memstore,Memstore默认大小是16kb;
  6. 当Memstore存储满后,会溢写到HFile中,至此,HBase写数据完成。

HBase安装部署

  1. 下载安装包,目前稳定版为1.4.9

    https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/stable/

  2. 上传到服务器并解压
  3. 修改conf/hbase-env.sh文件
export JAVA_HOME=
export HBASE_MANAGES_ZK=false
           
  1. 修改conf/hbase-site.xml文件
<configuration>
        <!--设置namenode所在的位置,通过rootdir设置-->
        <property>
                <name>hbase.rootdir</name>
                <value>hdfs://hd-even-01:9000/hbase</value>
        </property>
        <!--是否开启集群-->
        <property>
                <name>hbase.cluster.distributed</name>
                <value>true</value>
        </property>
        <!--0.98版本后的新改动,之前没有port参数,默认端口为60000-->
        <property>
                <name>hbase.master.port</name>
                <value>16000</value>
        </property>
        <!--zookeeper集群的位置,如果使用zookeeper集群,需要把env.sh脚本中的HBASE_MANAGES_ZK设置为false-->
        <property>
                <name>hbase.zookeeper.quorum</name>
                <value>hd-even-01:2181,hd-even-02:2181,hd-even-03:2181</value>
        </property>
        <!--hbase的元数据存储在zookeeper集群中,值是zookeeper指定的dataDir-->
        <property>
                <name>hbase.zookeeper.property.dataDir</name>
                <value>/home/even/hd/zookeeper-3.4.10/zkData</value>
        </property>
</configuration>

           
  1. 修改conf/regionservers,添加作为regionservers的主机
# 虽然本次配置把hd-even-01作为region-master,而region-master也可以作为regionserver使用,所以此处也添加进去
hd-even-01
hd-even-02
hd-even-03
           
  1. 解决依赖包问题
# hbase需要依赖hadoop和zookeeper,因此,lib目录下需要有hadoop和zookeeper相关的包,默认情况下已包含,但需要根据自己安装的hadoop和zookeeper进行修改
cd hbase/lib
rm -f hadoop-*
rm -f zookeeper-*
#然后把自己使用的hadoop和zookeeper相关jar包拷贝过来。
           
  1. 把hadoop的配置软连接到hbase/conf中,hbase是构建在hadoop的hdfs之上的,所以需要hadoop的配置
# 根据自己的实际情况
ln -s /hadoop/core-site.xml /hbase/conf
ln -s /hadoop/hdfs-site.xml /hbase/conf
           
  1. 启动集群
# 启动master-server,推荐使用hbase-daemon.sh命令
bin/hbase-daemon.sh start master
# 启动regionserver
bin/hbase-daemon.sh start regionserver
           
  1. 启动终端
bin/hbase shell
           
HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
  1. 可视化界面,hd-even-01是master的主机号:

    http://hd-even-01:16010

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

Hbase Shell命令

基本命令

  1. 查看服务器状态

    status ‘hd-even-01’

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
    activiti master代表活跃的master服务器,backup masters表示备份master服务器,servers表示regionserver服务器,dead表示宕机的数量,average load表示平均加载。
  2. 查看当前所有表

    list

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
  3. 查看帮助

    help

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

表操作

  1. 创建表

    create ‘表名’,‘列族’,‘列族1’,‘列族2’…

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
  2. 查看表结构

    describe ‘表名’

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
    VERSIONS表示列族的版本号
  3. 向表中插入数据

    put ‘表名’,‘rowkey’,‘列族:列名’,‘值’

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
  4. 全表扫描

    scan ‘表名’

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

    rowkey表示行键,唯一不重复;timestamp表示时间戳;cell表示单元格,数据存放的位置;column familly表示列族,列族下包含多个列,一个表包含多个列族;column表示列。

    HBase没有修改功能,只有覆盖功能,只要保持rowkey不变,列族和列相同就会进行覆盖操作

  5. 筛选扫描

    scan ‘表名’,{STARTROW => ‘1001’,STOPROW = ‘1002’}

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
    =>不是代表大于等于的意思,而是“指向”。上面代表扫描开始行是1001,结束行是1002。除此之外还有LIMIT,限制显示条件;TIMERANGE和FITLER等高级功能。
  6. 变更表信息

    alter ‘表名’,{NAME=>‘info’,VERSIONS=>‘3’,BLOCK=>‘65538’}

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
  7. 删除数据

    根据rowkey删除

    deleteall ‘表名’,‘rowkey’

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料

    根据具体的列删除

    delete ‘表名’,‘rowkey’,‘列族:列’

    HBase介绍及使用Apache HBase简介HBase安装部署Hbase Shell命令HBase API操作总结参考资料
  8. 清空表

    truncate ‘表名’

  9. 删除表

    第一步,设置表为不可用状态

    disable ‘表名’

    第二步,删除该表

    drop ‘表名’

  10. 统计表中的数据行数,即rowkey的数量

    count ‘表名’

  11. 查看指定rowkey值

    get ‘表名’,‘rowkey’

  12. 查看具体列值

    get ‘表名’,‘rowkey’,‘列族:列’

HBase API操作

导入依赖:

<dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.4.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>1.4.9</version>
        </dependency>
           
  1. 建立连接
public static Configuration conf;
    public static Connection connection;

    static {
        /*resource文件夹下需要有配置文件*/
        conf = HBaseConfiguration.create();
    }
    public static void connect() throws IOException {
    	//此处注意,不用指定端口
    	//conf.set("hbase.zookeeper.quorum","hd-even-01,hd-even-02,hd-even-03");
        //不用上面的方法,则需要在resource目录下需要加入hbase-site.xml文件。
        connection = ConnectionFactory.createConnection(conf);
    }
           
  1. 关闭连接
public static void closeConnection() throws IOException {
        connection.close();
    }
           
  1. 判断表是否存在
/**
     * 判断表是否存在
     *
     * @param tableName 表名
     * @return
     * @throws IOException
     */
    public static boolean isExitTable(String tableName) throws IOException {
        /*获取管理表*/
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
        if (admin.tableExists(TableName.valueOf(tableName))) {
            return true;
        } else {
            System.out.println("查询不到表");
            return false;
        }
    }
    public static void main(String[] args) throws IOException {
        connect();
		isExitTable("table1");
        closeConnection();
    }
           
  1. 创建表
/**
     * String...表示可变参数
     *
     * @param tableName
     * @param column_Family
     * @throws IOException
     */
    public static void createTable(String tableName, String... column_Family) throws IOException {
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
        if (admin.tableExists(TableName.valueOf(tableName))) {
            System.out.println("表已存在,请输入其它表名");
        } else {
            HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf(tableName));
            for (String column : column_Family) {
                hTableDescriptor.addFamily(new HColumnDescriptor(column));
            }
            admin.createTable(hTableDescriptor);
            System.out.println("表已创建成功!");
        }
    }
    public static void main(String[] args) throws IOException {
        connect();
	    createTable("even", "info", "info1");
        closeConnection();
    }
           
  1. 删除表
/**
     * 删除表操作
     *
     * @param tableName
     */
    public static void deleteTable(String tableName) throws IOException {
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
        if (isExitTable(tableName)) {
            admin.disableTable(TableName.valueOf(tableName));
            admin.deleteTable(TableName.valueOf(tableName));
            System.out.println("删除表成功");
        }
    }
           
  1. 添加数据
/**
     * 添加数据
     *
     * @param tableName
     * @param rowKey
     * @param columnFamily
     * @param column
     * @param value
     * @throws IOException
     */
    public static void putData(String tableName, String rowKey, String columnFamily, String column, String value) throws IOException {
        HBaseAdmin admin = (HBaseAdmin) connection.getAdmin();
        if (isExitTable(tableName)) {
            HTableDescriptor tableDescriptor = admin.getTableDescriptor(TableName.valueOf(tableName));
            HColumnDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies();
            boolean isExit = false;
            /*需要判断一下列族是否存在*/
            for (HColumnDescriptor hColumnDescriptor : columnFamilies) {
                String s = hColumnDescriptor.getNameAsString();
                if (columnFamily.endsWith(s)) {
                    isExit = true;
                    break;
                }
            }
            /*如果列族存在,则put数据*/
            if (isExit) {
                Put p = new Put(Bytes.toBytes(rowKey));
                p.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value));
                Table table = connection.getTable(TableName.valueOf(tableName));
                table.put(p);
                System.out.println("数据插入成功!");
            } else
                System.out.println("不存在的列族!");
        }
    }
           
  1. 删除指定rowkey的数据
/**
     * 删除指定rowkey的数据
     *
     * @param tableName
     * @param rowKey
     * @throws IOException
     */
    public static void deleteByRowKey(String tableName, String rowKey) throws IOException {
        if (isExitTable(tableName)) {
            Table table = connection.getTable(TableName.valueOf(tableName));
            if (table.exists(new Get(Bytes.toBytes(rowKey))))
                table.delete(new Delete(Bytes.toBytes(rowKey)));
            else
                System.out.println("不存在的rowKey数据,请输入正确的rowKey");
        }
    }
           
  1. 删除多个rowkey的数据
/**
     * 删除多个rowkey的数据
     *
     * @param tableName
     * @param rowKey
     * @throws IOException
     */
    public static void deleteByRowKeys(String tableName, String... rowKey) throws IOException {
        if (isExitTable(tableName)) {
            Table table = connection.getTable(TableName.valueOf(tableName));
            List<Delete> deletes = new ArrayList<>();
            for (String row : rowKey) {
                if (table.exists(new Get(Bytes.toBytes(row))))
                    deletes.add(new Delete(Bytes.toBytes(row)));
            }
            table.delete(deletes);
            System.out.println("删除数据成功!");
        }
    }
           
  1. 扫描表
/**
     * 扫描表
     *
     * @param tableName
     * @throws IOException
     */
    public static void scanAll(String tableName) throws IOException {
        if (isExitTable(tableName)) {
            Table table = connection.getTable(TableName.valueOf(tableName));
            ResultScanner scanner = table.getScanner(new Scan());
            for (Result next : scanner) {
                Cell[] cells = next.rawCells();
                for (Cell c : cells) {
                    System.out.println("行键为:" + Bytes.toString(CellUtil.cloneRow(c)));
                    System.out.println("列族为:" + Bytes.toString(CellUtil.cloneFamily(c)));
                    System.out.println("值为:" + Bytes.toString(CellUtil.cloneValue(c)));
                    System.out.println(c);
                }
            }
        }
    }
           
  1. 根据rowkey扫描表
/**
     * 根据rowkey扫描表
     *
     * @param tableName
     * @param rowKey
     * @throws IOException
     */
    public static void scanByRowKey(String tableName, String rowKey) throws IOException {
        if (isExitTable(tableName)) {
            Table table = connection.getTable(TableName.valueOf(tableName));
            Get get = new Get(Bytes.toBytes(rowKey));
            get.addFamily(Bytes.toBytes("info"));
            get.addColumn(Bytes.toBytes("info"), Bytes.toBytes("id"));

            Result result = table.get(get);
            Cell[] cells = result.rawCells();
            for (Cell c : cells) {
                System.out.println(c);
                System.out.println("行键为:" + Bytes.toString(CellUtil.cloneRow(c)));
                System.out.println("列族为:" + Bytes.toString(CellUtil.cloneFamily(c)));
                System.out.println("值为:" + Bytes.toString(CellUtil.cloneValue(c)));
            }
        }
    }
           

总结

本文对HBase的构架,安装部署以及使用进行了简单的介绍。HBase的技术来源于Fay Change撰写的Goole论文“Bigtable:一个结构化数据的分布式存储系统”。与Hive相比,因HBase的读写分离(两个缓存区处理读写操作)令它的读/写速度更实时,而Hive只适合用来对一段时间内的数据进行分析查询。

HBase构建于HDFS之上的,所以,它也可以认为是一个类型于数据库的存储层,适用于结构化的存储,并且是一种的分布式数据库。更多内容请查看HBase官方文档。

参考资料

HBase官方文档:http://hbase.apache.org/book.html