HBase 基础

135 阅读15分钟

#博学谷IT学习技术支持#

01 HBase基础简介

HBase产生的背景介绍

  • 从 1970 年开始,大多数的公司数据存储和维护使用的是关系型数据库
  • 大数据技术出现后,很多拥有海量数据的公司开始选择像Hadoop的方式来存储海量数据
  • Hadoop使用分布式文件系统HDFS来存储海量数据,并使用 MapReduce 来处理。Hadoop擅长于存储各种格式的庞大的数据,任意的格式甚至非结构化的处理

但是Hadoop存在的局限:

  • Hadoop主要是实现批量数据的处理,并且通过顺序方式访问数据
  • 要查找数据必须搜索整个数据集, 如果要进行随机读取数据,效率较低(压根就不支持)

总结: HADOOP仅适合存储大批量的数据, 进行顺序化读取数据, 并不支持随机读取数据操作

Hbase的基本介绍

  • NoSQL是一个通用术语,泛指一个数据库并不是使用SQL作为主要语言的非关系型数据库

  • HBase是BigTable的开源java版本。是建立在HDFS之上,提供高可靠性、高性能、列存储、可伸缩、实时读写NoSQL的数据库系统

  • HBase仅能通过主键(row key)和主键的range来检索数据,仅支持单行事务

  • 主要用来存储结构化和半结构化的松散数据

  • Hbase查询数据功能很简单,不支持join等复杂操作,不支持复杂的事务(行级的事务),从技术上来说,HBase更像是一个「数据存储」而不是「数据库」,因为HBase缺少RDBMS中的许多特性,例如带类型的列、二级索引以及高级查询语言等

  • Hbase中支持的数据类型:byte[]

  • 与Hadoop一样,Hbase目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加存储和处理能力,例如,把集群从10个节点扩展到20个节点,存储能力和处理能力都会加倍

  • HBase中的表一般有这样的特点

    • 大:一个表可以有上十亿行,上百万列
    • 面向列:面向列(族)的存储和权限控制,列(族)独立检索
    • 稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏

Hbase的应用场景

  • 对象存储

    • 不少的头条类、新闻类的新闻、网页、图片存储在Hbase之中, 一些病毒公司的病毒库也是存储在Hbase中
  • 时序数据

    • HBase之上有openTSDB模块, 可以满足时序类场景的需求
  • 推荐画像

    • 用户画像, 是一个比较大的稀疏矩阵, 蚂蚁金服的风控就是构建在Hbase之上
  • 时空数据

    • 主要是轨迹, 气象网格之类, 滴滴打车的轨迹数据主要存在Hbase之中, 另外在所有大一点的数据量的车联网企业, 数据也是存储在HBase
  • CubeDb OLAP

    • kylin 一个cube分析工具, 底层的数据就是存储在Hbase之中, 不少客户自己基于离线计算构建cube存储在hbase之中, 满足在线报表查询的需求
  • 消息/订单

    • 在电信领域、银行领域, 不少的订单查询底层的存储, 另外不少通信、消息同步的应用构建HBase之上
  • Feeds流

    • 典型的应用就是xx朋友圈类型的应用, 用户可以随时发布新内容, 评论、点赞
  • NewSQL

    • 之上有Phoenix的插件, 可以满足二级索引, SQL的查询, 对接传统数据需要SQL非事务的需求
  • 其他

    • 存储爬虫数据
    • 海量数据备份
    • 短网址
    • ………..

Hbase的发展历程

年份重大事件
2006年11月Google发布BigTable论文
2007年10月发布第一个可用的Hbase版本,基于Hadoop 0.15.0
2008年1月HBase成为Hadoop的一个子项目
2010年5月HBase成为Apache的顶级项目

Hbase的特点

  • 强一致性读/写: HBASE不是“最终一致的”数据存储 , 它非常适合于诸如高速计数器聚合等任务
  • 自动分块: HBase表通过Region分布在集群上,随着数据的增长,区域被自动拆分和重新分布
  • 自动RegionServer故障转移
  • Hadoop/HDFS集成: HBase支持HDFS开箱即用作为其分布式文件系统
  • MapReduce : HBase通过MapReduce支持大规模并行处理,将HBase用作源和接收器
  • Java Client API: HBase支持易于使用的 Java API 进行编程访问
  • Thrift/REST API
  • 块缓存和布隆过滤器 : HBase支持块Cache和Bloom过滤器进行大容量查询优化
  • 运行管理: HBase为业务洞察和JMX度量提供内置网页。

Hbase与 RDBMS 、HDFS 、 Hive 的区别

HBaseRDBMS
结构1.以表形式存在2.支持HDFS文件系统3.使用行键(row key)4.原生支持分布式存储、计算引擎5.使用行、列、列族和单元格1.数据库以表的形式存在2.支持FAT、NTFS、EXT、文件系统3.使用主键(PK)4.通过外部中间件可以支持分库分表,但底层还是单机引擎5.使用行、列、单元格
功能1.支持向外扩展2.使用API和MapReduce、Spark、Flink来访问HBase表数据3.面向列蔟,即每一个列蔟都是一个连续的单元4.数据总量不依赖具体某台机器,而取决于机器数量HBase不支持ACID(Atomicity、Consistency、Isolation、Durability)5.适合结构化数据和非结构化数据6.一般都是分布式的7. HBase不支持事务,支持的是单行数据的事务操作不支持Join1.支持向上扩展(买更好的服务器)2.使用SQL查询3.面向行,即每一行都是一个连续单元4.数据总量依赖于服务器配置5.具有ACID支持6.适合结构化数据7.传统关系型数据库一般都是中心化的8.支持事务9.支持Join
HBaseHive
1. HBase构建在HDFS之上,并为大型表提供快速记录查找(和更新) 2. HBase内部将大量数据放在HDFS中名为「StoreFiles」的索引中,以便进行高速查找 3.Hbase比较适合做快速查询等需求,而不适合做大规模的OLAP应用1. HDFS是一个非常适合存储大型文件的分布式文件系统 2. HDFS它不是一个通用的文件系统,也无法在文件中快速查询某个数据
1. NoSQL数据库2.是一种面向列存储的非关系型数据库。3.用于存储结构化和非结构化的数据4.适用于单表非关系型数据的存储,不适合做关联查询,类似JOIN等操作。5.基于HDFS6.数据持久化存储的体现形式是Hfile,存放于DataNode中,被ResionServer以region的形式进行管理6.延迟较低,接入在线业务使用8.面对大量的企业数据,HBase可以直线单表大量数据的存储,同时提供了高效的数据访问速度1.数据仓库工具2. Hive的本质其实就相当于将HDFS中已经存储的文件在Mysql中做了一个双射关系,以方便使用HQL去管理查询3.用于数据分析、清洗4. Hive适用于离线的数据分析和清洗,延迟较高5.基于HDFS、MapReduce6. Hive存储的数据依旧在DataNode上,编写的HQL语句终将是转换为MapReduce代码执行
总结: hbase与hiveuHive和Hbase是两种基于Hadoop的不同技术uHive是一种类SQL的引擎,并且运行MapReduce任务uHbase是一种在Hadoop之上的NoSQL 的Key/value数据库u这两种工具是可以同时使用的。就像用Google来搜索,用FaceBook进行社交一样,Hive可以用来进行统计查询,HBase可以用来进行实时查询,数据也可以从Hive写到HBase,或者从HBase写回Hive

03 HBase的表数据模型

在HBASE中,数据存储在具有行和列的表中。这是看起来关系数据库(RDBMS)一样,但将HBASE表看成是多个维度的Map结构更容易理解

术语:

  • 表(Table) : HBase中数据都是以表形式来组织的, HBase中的表由多个行组成

  • 行键(row key):

    • HBase中的行有一个rowkey(行键)和 一个或者多个列组成, 列的值与rowkey、列相关联

    • 行在存储是按行键的字典序排序

    • 行键的设计非常重要, 尽量让相关的行存储在一起

  • 列(Column): HBase中的列有列族(column family) 和列限定符(列名)(Column Qualifier)组成

    • 表示如下 : 列族名:列限定符 例如: C1:USER_ID C1:SEX
  • 列族(Column Family):

    • 出于性能原因, 列族将一组列及其值组织在一起
    • 每个列族都有一组存储属性: 例如 是否应该换成在内存中, 数据如何被压缩等
    • 表中的每一行都有相同的列族, 但在列族中不存储任何内容
    • 所有的列族的数据全部都存储在一块(文件系统HDFS)
    • Hbase官方建议所有的列族保持一样的列, 并且将同一类的列放在一个列族中
  • 列标识符(Column Qualifier)

    • 列族中包含一个个的列限定符, 这样可以为存储的数据提供索引
    • 列族在创建表的时候是固定的, 但列限定符是不做限制的
    • 不同的列可能会存在不同的列标识符
  • 单元格(Cell): 单元格是行、列族和列限定符的组合,包含一个值和一个时间戳, 数据以二进制存储

  • 版本号(verson num): 每条数据都会有版本号的概念

    • 每条数据都可以有多个版本号, 默认值为系统时间戳, 类型为Long
  • 时间戳(timeStamp): 每个数据都会有时间戳的概念

    • 在向Hbase插入更新数据的时候, HBase默认会将当前操作的时间记录下来, 当然也可以人为指定时间
    • 不同版本的数据按照时间倒序排序, 即最新的数据排在最前面

04 HBase的相关操作_命令式

我们可以以shell的方式来维护和管理HBase。例如:执行建表语句、执行增删改查操作等等

1) 进入HBase客户端命令操作界面
$ bin/hbase shell
 
2) 查看帮助命令
hbase(main):001:0> help

3) 查看当前数据库中有那些表 
hbase(main):002:0> list 

4) 创建一张表 
创建user表,包含info、data两个列族
hbase(main):010:0> create 'user', 'info', 'data'
或者
hbase(main):010:0> create 'user', {NAME => 'info', VERSIONS => '3'},{NAME => 'data'}

5) 添加数据操作 
向user表中插入信息,row key为rk0001,列族info中添加name列标示符,值为zhangsan
hbase(main):011:0> put 'user', 'rk0001', 'info:name', 'zhangsan'

向user表中插入信息,row key为rk0001,列族info中添加gender列标示符,值为female
hbase(main):012:0> put 'user', 'rk0001', 'info:gender', 'female'

向user表中插入信息,row key为rk0001,列族info中添加age列标示符,值为20
hbase(main):013:0> put 'user', 'rk0001', 'info:age', 20

向user表中插入信息,row key为rk0001,列族data中添加pic列标示符,值为picture
hbase(main):014:0> put 'user', 'rk0001', 'data:pic', 'picture'

6) 查询数据操作 

6.1、通过rowkey进行查询
获取user表中row key为rk0001的所有信息
hbase(main):015:0> get 'user', 'rk0001' 

6.2、查看rowkey下面的某个列族的信息
获取user表中row key为rk0001,info列族的所有信息
hbase(main):016:0> get 'user', 'rk0001', 'info'

6.3、查看rowkey指定列族指定字段的值
获取user表中row key为rk0001,info列族的name、age列标示符的信息
hbase(main):017:0> get 'user', 'rk0001', 'info:name', 'info:age’

6.4、查看rowkey指定多个列族的信息
获取user表中row key为rk0001,info、data列族的信息
hbase(main):018:0> get 'user', 'rk0001', 'info', 'data'
或者你也可以这样写
hbase(main):019:0> get 'user', 'rk0001', {COLUMN => ['info', 'data']}
或者你也可以这样写,也行
hbase(main):020:0> get 'user', 'rk0001', {COLUMN => ['info:name', 'data:pic’]}

6.5、指定rowkey与列值查询
获取user表中row key为rk0001,cell的值为zhangsan的信息
hbase(main):030:0> get 'user', 'rk0001', {FILTER => "ValueFilter(=, 'binary:zhangsan')"} 

6.7、查询所有数据 : 查询user表中的所有信息
scan 'user'
scan 'user' , {FORMATTER => 'toString’}
scan 'user' , {LIMIT => 3,FORMATTER => 'toString’}

6.8、列族查询:  查询user表中列族为info的信息
scan 'user', {COLUMNS => 'info'}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 5}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 3}

6.9、多列族查询: 查询user表中列族为info和data的信息
scan 'user', {COLUMNS => ['info', 'data']}
scan 'user', {COLUMNS => ['info:name', 'data:pic']}

6.10、指定列族与某个列名查询
查询user表中列族为info、列标示符为name的信息
scan 'user', {COLUMNS => 'info:name’}

6.11、指定列族与列名以及限定版本查询
查询user表中列族为info、列标示符为name的信息,并且版本最新的5个
scan 'user', {COLUMNS => 'info:name', VERSIONS => 5}
 
6.12、指定多个列族与按照数据值模糊查询
查询user表中列族为info和data且列标示符中含有a字符的信息
scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}

6.13、rowkey的范围值查询
查询user表中列族为info,rk范围是[rk0001, rk0003)的数据
scan 'user', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'}

6.14、指定rowkey模糊查询
查询user表中row key以rk字符开头的
scan 'user',{FILTER=>"PrefixFilter('rk')"}

6.15、指定数据范围值查询
查询user表中指定范围的数据
scan 'user', {TIMERANGE => [1392368783980, 1392380169184]}

过滤器的查询地址:
http://hbase.apache.org/2.2/devapidocs/index.html
 
7) 更新数据操作 
1、更新数据值
更新操作同插入操作一模一样,只不过有数据就更新,没数据就添加

2、更新版本号
将user表的f1列族版本号改为5
hbase(main):050:0> alter 'user', NAME => 'info', VERSIONS => 5 

8) 删除数据以及删除表操作 
1、指定rowkey以及列名进行删除
      删除user表row key为rk0001,列标示符为info:name的数据
     hbase(main):045:0> delete 'user', 'rk0001', 'info:name'
2、指定rowkey,删除一整行数据
     hbase(main):045:0>deleteall 'user', 'rk0001’
注意:  
   1. deleteall 是在 hbase 2.0版本后出现的, 在2.0版本之前, 只需要使用delete这个命令即可完成所有的删除数据工作, 
   2. delete删除数据时候, 只会删除最新版本的数据, 而deleteall 直接将对应数据的所有的历史版本全部删除
 
3、删除一个列族:
alter 'user', NAME => 'info', METHOD => 'delete’  或 alter 'user', 'delete' => 'info'

4、清空表数据
hbase(main):017:0> truncate 'user'

5、删除表
首先需要先让该表为disable状态,使用命令: hbase(main):049:0> disable 'user'
然后才能drop这个表,使用命令:hbase(main):050:0> drop 'user'
 (注意:如果直接drop表,会报错:Drop the named table. Table must first be disabled) 

8) 统计一张表有多少行数据 
hbase(main):053:0> count 'user'

HBASE高级shell管理命令

    1. status 显示服务器状态 “例如:hbase(main):058:0> status 'node01'
    1. whoami : 显示HBase当前用户,例如: hbase> whoami
    1. list : 显示当前所有的表
    1. count: 统计指定表的记录数,例如: hbase> count 'user'
    1. describe : 展示表结构信息
    1. exists: 检查表是否存在,适用于表量特别多的情况
    1. is_enabled、is_disabled: 检查表是否启用或禁用
    1. alter : 该命令可以改变表和列族的模式,

    • 例如: 为当前表增加列族: hbase> alter 'user', NAME => 'CF2', VERSIONS => 2
    • 为当前表删除列族: hbase(main):002:0> alter 'user', 'delete' => 'CF2'
    1. disable/enable : 禁用一张表/启用一张表
    1. drop : 删除一张表,记得在删除表之前必须先禁用
    1. truncate : 禁用表-删除表-创建表

05 HBase的相关操作_JavaAPI方式

需求说明:

将水表抄表数据存储到HBase

准备工作

  • 1- 创建一个新的工程
  • 2- 导入相关的pom文件
    <repositories><!--代码库-->
        <repository>
            <id>aliyun</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases><enabled>true</enabled></releases>
            <snapshots>
                <enabled>false</enabled>
                <updatePolicy>never</updatePolicy>
            </snapshots>
        </repository>
    </repositories>

    <dependencies>

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

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <target>1.8</target>
                    <source>1.8</source>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • 3- 创建包结构: com.itheima.hbase
  • 4- 在此包下, 创建一个测试类
package com.itheima.hbase;
// HBase的测试类
public class HBaseTest {
    
    
    
}

创建表

  • 操作步骤:
  1. 创建Java连接HBase的连接对象 2) 根据连接对象, 获取相关的管理对象: admin(表定义语言操作) table(表数据操作) 3) 执行相关的操作 4) 处理结果集(只有查询是存在的) 5) 释放资源

代码实现

    @Test
    public void createTableTest01() throws Exception{

        // 1) 创建Java连接HBase的连接对象
        // Configuration conf = new Configuration();
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","node1:2181,node2:2181,node3:2181"); // 指定连接那个HBase
        Connection hbaseConn = ConnectionFactory.createConnection(conf);

        // 2) 根据连接对象, 获取相关的管理对象: admin(表定义语言操作)  table(表数据操作)
        Admin admin = hbaseConn.getAdmin();
        // 3) 执行相关的操作: 创建表
        boolean flag = admin.tableExists(TableName.valueOf("WATER_BILL")); // 如果存在 返回True

        if(! flag){
            // 说明 表不存在
            // 设置列族的信息
            ColumnFamilyDescriptor familyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder("C1".getBytes()).build();
            // 设置表的结构信息: 表名 + 列族
            TableDescriptor tableDescriptor = TableDescriptorBuilder
                    .newBuilder(TableName.valueOf("WATER_BILL"))
                    .setColumnFamily(familyDescriptor)
                    .build();
            // 3.1  创建表
            admin.createTable(tableDescriptor);
        }

        // 4) 处理结果集(只有查询是存在的)
        // 5) 释放资源
        admin.close();
        hbaseConn.close();
    }