#博学谷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 的区别
| HBase | RDBMS | |
|---|---|---|
| 结构 | 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不支持事务,支持的是单行数据的事务操作不支持Join | 1.支持向上扩展(买更好的服务器)2.使用SQL查询3.面向行,即每一行都是一个连续单元4.数据总量依赖于服务器配置5.具有ACID支持6.适合结构化数据7.传统关系型数据库一般都是中心化的8.支持事务9.支持Join |
| HBase | Hive |
|---|---|
| 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管理命令
-
- status 显示服务器状态 “例如:hbase(main):058:0> status 'node01'
-
- whoami : 显示HBase当前用户,例如: hbase> whoami
-
- list : 显示当前所有的表
-
- count: 统计指定表的记录数,例如: hbase> count 'user'
-
- describe : 展示表结构信息
-
- exists: 检查表是否存在,适用于表量特别多的情况
-
- is_enabled、is_disabled: 检查表是否启用或禁用
-
-
alter : 该命令可以改变表和列族的模式,
- 例如: 为当前表增加列族: hbase> alter 'user', NAME => 'CF2', VERSIONS => 2
- 为当前表删除列族: hbase(main):002:0> alter 'user', 'delete' => 'CF2'
-
-
- disable/enable : 禁用一张表/启用一张表
-
- drop : 删除一张表,记得在删除表之前必须先禁用
-
- 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 {
}
创建表
- 操作步骤:
- 创建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();
}