设为首页 加入收藏

TOP

HBase介绍及使用
2019-02-15 01:47:07 】 浏览:116
Tags:HBase 介绍 使用

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架构

在这里插入图片描述
角色关系:

角色 说明
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读取数据流程

在这里插入图片描述
步骤:

  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获取要查询的数据。
在这里插入图片描述
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写入数据流程

在这里插入图片描述
步骤分析:

  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

在这里插入图片描述

  1. 可视化界面,hd-even-01是master的主机号:
    http://hd-even-01:16010
    在这里插入图片描述

Hbase Shell命令

基本命令

  1. 查看服务器状态
    status ‘hd-even-01’
    在这里插入图片描述
    activiti master代表活跃的master服务器,backup masters表示备份master服务器,servers表示regionserver服务器,dead表示宕机的数量,average load表示平均加载。
  2. 查看当前所有表
    list
    在这里插入图片描述
  3. 查看帮助
    help
    在这里插入图片描述

表操作

  1. 创建表
    create ‘表名’,‘列族’,‘列族1’,‘列族2’…
    在这里插入图片描述

  2. 查看表结构
    describe ‘表名’
    在这里插入图片描述
    VERSIONS表示列族的版本号

  3. 向表中插入数据
    put ‘表名’,‘rowkey’,‘列族:列名’,‘值’
    在这里插入图片描述

  4. 全表扫描
    scan ‘表名’
    在这里插入图片描述
    rowkey表示行键,唯一不重复;timestamp表示时间戳;cell表示单元格,数据存放的位置;column familly表示列族,列族下包含多个列,一个表包含多个列族;column表示列。
    HBase没有修改功能,只有覆盖功能,只要保持rowkey不变,列族和列相同就会进行覆盖操作

  5. 筛选扫描
    scan ‘表名’,{STARTROW => ‘1001’,STOPROW = ‘1002’}
    在这里插入图片描述
    =>不是代表大于等于的意思,而是“指向”。上面代表扫描开始行是1001,结束行是1002。除此之外还有LIMIT,限制显示条件;TIMERANGE和FITLER等高级功能。

  6. 变更表信息
    alter ‘表名’,{NAME=>‘info’,VERSIONS=>‘3’,BLOCK=>‘65538’}
    在这里插入图片描述

  7. 删除数据
    根据rowkey删除
    deleteall ‘表名’,‘rowkey’
    在这里插入图片描述
    根据具体的列删除
    delete ‘表名’,‘rowkey’,‘列族:列’
    在这里插入图片描述

  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.cloneva lue(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.cloneva lue(c)));
            }
        }
    }

总结

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

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

参考资料

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

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇HBase集成MapReduce 下一篇HBase Coprocessors机制

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目