封面画师:画师JW     封面ID:79686153

HBase简介

HBase是一种分布性、可扩展、支持海量数据存储的NoSQL数据库。

HBase的数据模型

逻辑上,HBase的数据模型同关系型数据库类型,数据存储在一张表类,有行有列。但从HBase的底层物理存储结构(K-V)来看,HBase更像一个multi-dimensional map。

表结构(HBase逻辑结构):

表组织结构

参考资料:HBase数据模型介绍

高表行多,宽表列多。

Region是一张表的切片,而且是横向切片,相当于对宽表的切分。

store是真正存储的内容。

HBase物理存储结构:

HBase物理存储结构

如果需要在Windows和Linux上测试HBase,由于时间戳的关系,请保证这两个系统的时间是一致的。当你查询某个列时,HBase会返回时间戳较大的列的数据。

数据模型

Name Space

命名空间,类似于关系型数据库的database概念,每个命名空间下有多个表,HBase有两个自带的命名空间,分别是hbasedefault,hbase中存放的是HBase内置的表,default是用户默认使用的命名空间。

Region

类似于关系型数据库的表概念。不同的是,HBase定义表时只需要声明列族即可,不需要声明具体的列。这意味着,往HBase写入数据时,字段可以动态按需指定。因此,和关系型数据库相比,HBase能够轻松应对字段变更的场景。

表的切片。当数据不多时,表和Region是一一对应的关系,一个表就是一个Region;当数据量大起来时,一个表就会被切分成多个Region。除了系统自动帮我们切分,我们也可以进行手动切分。

HBase中的列名相当于HBase中的数据。

Row

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

因此我们查询数据时,除了可以全局扫描,还可以范围扫描。

Column

HBase中的每个列都是有Column Family(列族)和Column Qualifier(列限定符)进行限定,例如:info:name , info:age 。建表时,只需指名列族,而列限定符无需预先定义。

Time Stamp

用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入HBase的时间。

Cell

由{RowKey, column Family: column Qualifier, time stamp}唯一确定单元。cell中的数据是没有类型的,全部是字节码形式存储


基础架构

当HMaster节点挂掉后,做数据级别(表内数据)的增删改查是没问题的,但是做表级别的是不行的。

RegionServer的作用:(DML)

Data:get、put、delete

Region:splitRegion、compactRegion

Master的作用:(DDL)

Table:create、delete、alter

RegionServer:分配regions到每个RegionServer,监控每个RegionServer的状态。

HBase的安装

已单独写成笔记文档。

HBase Shell操作

基本操作

进入HBase客户端命令行:

1
[root@db06 mofan]# bin/hbase shell

查看帮助命令:

1
Hbase(mian):001:0> help

查看当前数据库中 有哪些表:

1
Hbase(mian):002:0> list

DDL

创建表:

创建表时,必须指定至少一个列族。

1
2
hbase(main):002:0> create 'student','info'
hbase(main):003:0> create 'stu','info1','info2'

查看表具体信息:

1
hbase(main):004:0> desc 'student'

变更表信息(版本号):

1
hbase(main):009:0> alter 'student', {NAME=>'info',VERSIONS=>3}

删除表:

1
2
hbase(main):011:0> disable 'student'
hbase(main):012:0> drop 'student'

我们在删除表时,必须先disable表,即:表在可用状态(enable)下不能被删除,需要删除得将其设置成不可用状态(disable)。

查看当前所有命名空间:

1
hbase(main):014:0> list_namespace

创建命名空间:

1
hbase(main):015:0> create_namespace 'bigdata'

在指定的命名空间下创建一个表:

1
hbase(main):017:0> create 'bigdata:stu',"info"

删除命名空间:

1
2
3
hbase(main):019:0> disable 'bigdata:stu'
hbase(main):020:0> drop 'bigdata:stu'
hbase(main):021:0> drop_namespace 'bigdata

删除命名空间时,不许保证当前命名空间为空。

DML

增加 & 查询

向指定表内插入数据:

1
hbase(main):024:0> put 'stu','1001','info1:name','mofan'

解析:向stu表中插入数据,RowKey:1001,列族info1下的name列,插入值:mofan

查询表内所有数据:

1
hbase(main):025:0> scan 'stu'

我们查询出来的数据是按照RowKey的字典顺序进行升序排序的,这很重要!

查询表中指定条件的数据:

1
hbase(main):026:0> get 'stu','1001'

解析:查询stu表内,RowKey为1001的数据

我们先插入几条数据备用:

1
2
3
4
5
hbase(main):027:0> put 'stu','1001','info1:sex','male'
hbase(main):028:0> put 'stu','1001','info2:addr','sichuan'
hbase(main):029:0> put 'stu','1002','info1:name','lisi'
hbase(main):030:0> put 'stu','1002','info1:phone','13212341234'
hbase(main):031:0> put 'stu','1003','info2:addr','beijing'
1
hbase(main):035:0> get 'stu','1001','info1:name'

解析:查询stu表内,RowKey为1001,列族info1下的name列的所有数据

1
hbase(main):037:0> get 'stu','1001','info1'

解析:查询stu表内,RowKey为1001,列族info1下的所有数据

使用scan进行范围扫描查询:

1
hbase(main):039:0> scan 'stu',{STARTROW=>'1001',STOPROW=>'1003'}

解析:查询stu表中,RowKey大于等于1001,小于1003的数据。 [1001,1003),左闭右开。 我们在进行查询的时候,也可以只指定STARTROW或STOPROW。

使用过滤器查询参考链接:HBase基础之常用过滤器hbase shell操作

修改 & 删除

修改指定单元格的数据:

1
hbase(main):003:0> put 'stu','1001','info1:name','zhangsan'

解析:将stu表中,RowKey为1001info1列族下的name列的数据改为zhangsan。因为是修改数据,因此必须要有原数据才可修改,否则就是增加数据或报错。

数据修改后,并不是立即在HBase中删除,它会修改数据版本,高版本的数据会覆盖低版本的数据,相当于一种软删除,我们可以用下列方式查询10个版本以内的指定数据表内的所有数据

1
hbase(main):006:0> scan 'stu',{RAW=>true,VERSIONS=>10}

我们可以在插入数据时,指定数据的时间戳,然后我们再查询的时候就只会返回时间戳最大的数据

1
hbase(main):007:0> put 'stu','1001','info1:name','wangwu',1588693216333

1588693216333为指定的时间戳,进行操作时,请将这里的时间戳设置为mofan之后,zhangsan之前。如果你是根据我一步步完成了命令的,现在进行查询stu表中的数据,得到的返回结果是张三。

结果示例:

1
2
3
4
5
6
7
ROW                    COLUMN+CELL                                                 
1001 column=info1:name, timestamp=1588733177444, value=zhangsan
1001 column=info1:sex, timestamp=1588693722432, value=male
1001 column=info2:addr, timestamp=1588693772674, value=sichuan
1002 column=info1:name, timestamp=1588693795475, value=lisi
1002 column=info1:phone, timestamp=1588693813969, value=13212341234
1003 column=info2:addr, timestamp=1588693930008, value=beijing

正是因为这个原因,我们在Windows和Linux进行HBase相关的操作时,请务必保证两个系统的时间是一致的


删除指定单元格的数据:

1
hbase(main):010:0> delete 'stu','1001','info1:sex'

解析:删除stu表中,RowKey为1001info1列族下sex列的数据。

使用delete删除数据时,如果此单元格有低版本的数据,那么查询数据时,会返回该单元格低版本的数据,而不是自己将该单元格所有版本数据全部删除。

我们可以查询表中10个版本以内的数据,得到如下结果:

1
2
3
4
5
1001                  column=info1:name, timestamp=1588733177444, type=Delete     
1001 column=info1:name, timestamp=1588733177444, value=zhangsan
1001 column=info1:name, timestamp=1588693216333, value=wangwu
1001 column=info1:name, timestamp=1588693216129, value=mofan
....

我们发现刚刚删除的单元格的type变成了Delete,然后我们查询数据,我们又会发现,返回的是wangwu,而不是一条数据都没,这也验证了我们的结论。

删除单元格内所有版本的数据:

1
hbase(main):022:0> deleteall 'stu','1001','info1:name'

解析:删除stu表中,RowKey为1001info1列族下sex列的所有版本数据。

如果这时我们再查询数据,我们无法查看到name列下的数据。我们查询表中10个版本以内的数据,得到如下结果:

1
1001                  column=info1:name, timestamp=1588735280872, type=DeleteColumn 

删除的单元格的type变成了DeleteColumn,当单元格类型为DeleteColumn时,查询数据不会返回低版本数据。

根据时间戳删除数据:

先插入一条数据,再进行删除:

1
hbase(main):004:0> put 'stu','1001','info1:name','zhaoliu'

我们使用scan查询这条数据:

1
1001                  column=info1:name, timestamp=1588744342719, value=zhaoliu

根据时间戳删除:

1
hbase(main):007:0> delete 'stu','1001','info1:name',1588744342718

注意:我们这里使用的时间戳比查询出的小1,我们测试能否删除成功。执行操作后我们可以发现,并没有删除成功。那么我们让两个时间戳相等再进行一次删除:

1
hbase(main):007:0> delete 'stu','1001','info1:name',1588744342719

执行操作后,我们发现时间戳为1588744342719的数据的type已经变成了Delete,证明删除成功。

测试根据列族进行删除:

1
hbase(main):014:0> delete 'stu','1002','info1'

虽然显示运行成功,但是我们查询数据后发现并没有被删除

1
2
3
4
1002                  column=info1:, timestamp=1588745457853, type=Delete           
1002 column=info1:name, timestamp=1588693795475, value=lisi
1002 column=info1:phone, timestamp=1588693813969, value=13212341234
1002 column=info2:, timestamp=1588745078579, type=Delete

根据RowKey进行删除:

我们删除RowKey为1001的数据,因为数据不够,我们先插入一条再进行删除:

1
2
hbase(main):023:0> put 'stu','1001','info1:sex','female'
hbase(main):026:0> deleteall 'stu','1001'

清空整个表的数据:

1
hbase(main):029:0> truncate 'stu'

解析:清空stu整个表的数据。

DML (多版本)

测试一

由于我们刚清空了stu表,我们先往stu表中put两条数据:

1
2
hbase(main):032:0> put 'stu','1005','info1:name','zhangsan'
hbase(main):033:0> put 'stu','1005','info1:name','lisi'

然后我们进行版本查询:

1
hbase(main):036:0> get 'stu','1005',{COLUMN=>'info1:name',VERSIONS=>3}

查询结果:

1
2
COLUMN                 CELL                                                         
info1:name timestamp=1588748200158, value=lisi

我们发现,尽管进行了版本查询,但结果只返回了一条数据。这是因为我们的stu表只能存储1个版本,因此查询时只返回了时间戳大的版本

测试二

我们新建一个表进行测试:

1
hbase(main):002:0> create 'stu2','info'

插入数据:

1
2
hbase(main):005:0> put 'stu2','1005','info:name','zhangsan'
hbase(main):006:0> put 'stu2','1005','info:name','lisi'

设置info列族可存储2个版本数据:

1
2
hbase(main):007:0> alter 'stu2',{NAME=>'info',VERSIONS=>2}
hbase(main):008:0> put 'stu2','1005','info:name','wangwu'

进行版本查询:

1
hbase(main):009:0> get 'stu2','1005',{COLUMN=>'info:name',VERSIONS=>3}

这时候我们发现数据依然只有一条(wangwu),是因为我们先put了数据,才进行版本设置。我们需要先进行版本设置,再put数据。

再次插入数据:

1
2
hbase(main):012:0> put 'stu2','1001','info:name','zhaoliu'
hbase(main):013:0> put 'stu2','1001','info:name','sunqi'

进行版本查询:

1
hbase(main):015:0> get 'stu2','1001',{COLUMN=>'info:name',VERSIONS=>3}

这时候我们发现查询的数据就有两条了(zhaoliu、sunqi)。

那么我们再向stu表,RowKey为1001,info列族中name列中插入一条数据:

1
hbase(main):016:0> put 'stu2','1001','info:name','zhouba'

再进行版本查询:

1
hbase(main):017:0> get 'stu2','1001',{COLUMN=>'info:name',VERSIONS=>3}

查询出来的数据依旧只有2条(zhaoba、sunqi),虽然我们查找了3个版本的数据,但我们设置了info列数只能存储两个版本的数据。

删除

在Shell模式下,如果我们在允许多个版本数据存在的表里对数据进行删除,会直接删除指定的所有版本数据,无法做到选择删除。