Hbase 深入浅出

概述

HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。

与FUJITSU Cliq等商用大数据产品不同,HBase是Google Bigtable的开源实现,类似Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MapReduce来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用 Chubby作为协同服务,HBase利用Zookeeper作为对应

特点

  1. Hbase可以往数据里面insert,也可以update一些数据,但update的实际上也是insert,只是插入一个新的时间戳的一行。delete数据,也是insert,只是insert一行带有delete标记的一行。Hbase的所有操作都是追加插入操作。Hbase是一种日志集数据库。它的存储方式,像是日志文件一样。它是批量大量的往硬盘中写,通常都是以文件形式的读写。这个读写速度,取决于硬盘与机器之间的传输有多快。
  2. Hbase中数据可以保存许多不同时间戳的版本(即同一数据可以复制许多不同的版本,准许数据冗余,也是优势)。数据按时间排序,因此Hbase特别适合寻找按照时间排序寻找Top n的场景。找出某个人最近浏览的消息,最近写的N篇博客,N种行为等等,因此Hbase在互联网应用非常多。
  3. Hbase只有主键索引,因此在建模的时候会遇到了问题。例如,在一张表中,很多的列我都想做某种条件的查询。但却只能在主键上建快速查询。
  4. Hbase是列式数据库,列式数据库的优势在于数据分析。
  5. Hbase中的数据都是字符串,没有其他类型。

NoSQL数据库

NoSQL 数据库和关系型数据库的设计目的是为了解决不同的问题,NoSQL 数据模型相对简单,它适合应用灵活更强的 IT 系统,不需要预先定义表如构,而且 NoSQL 对数据库性能要求较高,对 PB 级别的数据进行快速的检索,不需要高度的数据一致性及廷迟性的埸景,可以快的跟据 Key-Value 的方式来查看数据。在市埸上有四种NoSQL数据库,分别是:

  • 键值存储数据库:Key-Value 的鐽值对,通常用 Hash Table 来实现,这类数据库的查找速度快、简单,易部署,但数据无结构化,如果区部查找会很慢,和应用埸景是内容缓存,快速的检索数据,主要用于大量数据的高访问量负X,也适用于一些日志系统, e.g. Redis, Oracle BDB, Tokyo Cabinet;
  • 列存储数据库:以列族 Column Family 式存储,将同一列数据存在一起,鐽的特点是指向了多少个列,这些列是由列族来实现的,它的好处是查找快速,扩展性非常好以便应用海量数据存储和处理,但功能相对局限,对设计要求很特定的要求,非常适合分布式文件系统 e.g. HBase、Cassandra, Accumulo, Riak;
  • 文档存储数据库:Key-Value 对应的键值时,Value 为结构化数据,更了解 Value 的内容,数据结构不严格,表结构可变它不需要像关系型数据库一样要预先定义表结构,可以看作他是键值数据库的升级版,文档类型处理得力比较好,但查询能力不高,缺乏统一的查询语法。使用埸景是 Web 应用,,e.g. MongoDB, CouchDB, Couchbase Server ;
  • 图形数据库:图结构,它可以提用图结构的算法,比如最佳路线寻址,N度关系查找,使用灵活的图形模型并且能扩展到不同的服务器上,但很多时候要对整个图作计算才能得出需要的信息,这种结构不太适合分布式的集群方案。应用埸景:推荐系统,社交网络和关于结构关系图谱, e.g. Neo4J, Infinite Graph;

NoSQL与RDBMS的区别

http://ov1nop9io.bkt.clouddn.com/1005794-20170815072006725-2132221664.png

NoSQL 与 RDBMS 最大的分别是数据量和读写吞吐量的不同,数据布局和数据访问频率也不同,他们两个应用解决问题的本质也不一样,比如列存储数据库可以快速查找的原因是列族的设计可以在每一次查询中大量减少磁盘 IO 和数据量的访问。NoSQL 数据库很容易支持数据量达 PB 级别的数据,因为它的特性很容易支持分布式水平扩展;但 RDBMS 只能处理 TB+ 级别的数据,如果你的数据场景是要处理很多事务性数据 e.g. 更新和删除,那么还是优先选择关系型数据库 RBDMS,因为NoSQL数据库不太善于频繁的处理数据更新和删除,因为数据是分布在不同的节点上,还有数据是默认有三份副本,如果需要太量的更新操作,那么每台节点上的数据也有一并更新,这太太增加了解决方案的复杂性;NoSQL 遵从 CAP 和 BASE 理论,RDBMS 遵从 ACID 的理论。如果只有上千行和上百万行的数据,则用傅统数据库会比较适合。

Hbase表结构

HBase 是以数据为中心,RDBMS 是以关系为数据,HBase 是 NoSQL 数据库中的列存储数据库,它有以下特点:强一致性读写,自动分片,HBase 通过 Region 分布在集群中,数据增加时,Region 会自动分割并重新分片。RegionServer 自动故障移取,HBase 支持 HDFS 之外的存储文件,HBase 通过 MapReduce 支持大并发处理,HBase 支持以 API 方式访问数据,HBase 以 Bloom Filters 和 Bloom Cache 对大量数据进行查询优化。HBase 适合场景是存在随机读写的埸景,每秒需要在 TB 级别数据上完成数以千计的操作,访问的操作的方式要简单、明确和直接,如果应用只是插入数据而且处理时需要读取全部数据。HBase 不支持二次索引、事务性数据、关联表的操作。HBase 的使用埸景:消息 (Message) 比如点赞,电商中的 SMS/ MMS,有随机读写的能力,局部数据进行 TopN 的查询、简单实体、图数据、指标。

http://ov1nop9io.bkt.clouddn.com/1005794-20170814194337318-228599821.png

  1. HBase 在表中存储数据,而表数据最后存储在 HDFS 上,数据被分割成 HDFS 块 (Block) 存储在集群的多个节点上,以128G为一个 BlockSize;

  2. HBase 是由 Column Family (列族),Column (列) 和 Row Key (行) 组成的,列族是列的一个集合,列族可以有任意数量的列,e.g. contactinfo:fname, contactinfo:lname 它也可以单独对每个列族进行存储属性优化,比如对 profilephoto 进行压缩存储。

  3. HBase 每一行都有一个 RowKey 用于快速检索,来保证一行数据的完整性,每个 RowKey 就类似于 RDBMS 的主键,HBase 表是基于 RowKey 进行快速检索,行按照排序后进行存储,

  4. HBase 底层磁盘上是按照 Column Family 分开进行存储。这样的好处是相对于行存,占用空间会很小;

  5. HBase 中间的数据是存储在 Cell 中,而且 Cell 是有版本化的,可以自定义保留多少过版本,Cell 为空时不存储。

架构

http://ww4.sinaimg.cn/mw690/63503acbjw1f5x1207zfmj20gr0atq4h.jpg

HBase采用Master/Slave架构搭建集群,它隶属于Hadoop生态系统,由以下类型节点组成:HMaster节点、HRegionServer节点、ZooKeeper集群,而在底层,它将数据存储于HDFS中,因而涉及到HDFS的NameNode、DataNode等节点。

Zookeeper

Zookeeper Quorum存储-ROOT-表地址、HMaster地址。HRegionServer把自己以Ephedral方式注册到Zookeeper中,HMaster随时感知各个HRegionServer的健康状况。

HMaster

HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master在运行。
HMaster主要负责Table和Region的管理工作

  1. 实现DDL操作(Data Definition Language,namespace和table的增删改,column familiy的增删改等)。
  2. 管理HRegionServer的负载均衡,调整Region分布。
  3. 管理和分配HRegion,比如在HRegion split时分配新的HRegion;在HRegionServer退出时迁移其内的HRegion到其他HRegionServer上。
  4. 权限控制(ACL)。

HRegionServer

HBase中最核心的模块,主要负责响应用户I/O请求,向HDFS文件系统中读写数据。

  1. 存放和管理本地HRegion。读写HDFS,管理Table中的数据。
  2. Client直接通过HRegionServer读写数据(从HMaster中获取元数据,找到RowKey所在的HRegion/HRegionServer后)。

HRegion

http://ww2.sinaimg.cn/mw690/63503acbjw1f5x2cuji5gj20k409ddho.jpg

HBase使用RowKey将表水平切割成多个HRegion,从HMaster的角度,每个HRegion都纪录了它的StartKey和EndKey(第一个HRegion的StartKey为空,最后一个HRegion的EndKey为空),由于RowKey是排序的,因而Client可以通过HMaster快速的定位每个RowKey在哪个HRegion中。HRegion由HMaster分配到相应的HRegionServer中,然后由HRegionServer负责HRegion的启动和管理,和Client的通信,负责数据的读(使用HDFS)。

常用Shell命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
显示hbase中的表
list

创建user表,包含info、data两个列族
create 'user', 'info1', 'data1'
create 'user', {NAME => 'info', VERSIONS => '3'}

user表中插入信息,row key为rk0001,列族info中添加name列标示符,值为zhangsan
put 'user', 'rk0001', 'info:name', 'zhangsan'

user表中插入信息,row key为rk0001,列族info中添加gender列标示符,值为female
put 'user', 'rk0001', 'info:gender', 'female'

user表中插入信息,row key为rk0001,列族info中添加age列标示符,值为20
put 'user', 'rk0001', 'info:age', 20

user表中插入信息,row key为rk0001,列族data中添加pic列标示符,值为picture
put 'user', 'rk0001', 'data:pic', 'picture'

获取user表中row key为rk0001的所有信息
get 'user', 'rk0001'

获取user表中row key为rk0001,info列族的所有信息
get 'user', 'rk0001', 'info'

获取user表中row key为rk0001,info列族的name、age列标示符的信息
get 'user', 'rk0001', 'info:name', 'info:age'

获取user表中row key为rk0001,info、data列族的信息
get 'user', 'rk0001', 'info', 'data'
get 'user', 'rk0001', {COLUMN => ['info', 'data']}

get 'user', 'rk0001', {COLUMN => ['info:name', 'data:pic']}

获取user表中row key为rk0001,列族为info,版本号最新5个的信息
get 'user', 'rk0001', {COLUMN => 'info', VERSIONS => 2}
get 'user', 'rk0001', {COLUMN => 'info:name', VERSIONS => 5}
get 'user', 'rk0001', {COLUMN => 'info:name', VERSIONS => 5, TIMERANGE => [1392368783980, 1392380169184]}

获取user表中row key为rk0001,cell的值为zhangsan的信息
get 'people', 'rk0001', {FILTER => "ValueFilter(=, 'binary:图片')"}

获取user表中row key为rk0001,列标示符中含有a的信息
get 'people', 'rk0001', {FILTER => "(QualifierFilter(=,'substring:a'))"}

put 'user', 'rk0002', 'info:name', 'fanbingbing'
put 'user', 'rk0002', 'info:gender', 'female'
put 'user', 'rk0002', 'info:nationality', '中国'
get 'user', 'rk0002', {FILTER => "ValueFilter(=, 'binary:中国')"}


查询user表中的所有信息
scan 'user'

查询user表中列族为info的信息
scan 'user', {COLUMNS => 'info'}
scan 'user', {COLUMNS => 'info', RAW => true, VERSIONS => 5}
scan 'persion', {COLUMNS => 'info', RAW => true, VERSIONS => 3}
查询user表中列族为info和data的信息
scan 'user', {COLUMNS => ['info', 'data']}
scan 'user', {COLUMNS => ['info:name', 'data:pic']}


查询user表中列族为info、列标示符为name的信息
scan 'user', {COLUMNS => 'info:name'}

查询user表中列族为info、列标示符为name的信息,并且版本最新的5
scan 'user', {COLUMNS => 'info:name', VERSIONS => 5}

查询user表中列族为info和data且列标示符中含有a字符的信息
scan 'user', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}

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

查询user表中row key以rk字符开头的
scan 'user',{FILTER=>"PrefixFilter('rk')"}

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

删除数据
删除userrow key为rk0001,列标示符为info:name的数据
delete 'people', 'rk0001', 'info:name'
删除userrow key为rk0001,列标示符为info:name,timestamp1392383705316的数据
delete 'user', 'rk0001', 'info:name', 1392383705316


清空user表中的数据
truncate 'people'


修改表结构
首先停用user表(新版本不用)
disable 'user'

添加两个列族f1和f2
alter 'people', NAME => 'f1'
alter 'user', NAME => 'f2'
启用表
enable 'user'


###disable 'user'(新版本不用)
删除一个列族:
alter 'user', NAME => 'f1', METHOD => 'delete'alter 'user', 'delete' => 'f1'

添加列族f1同时删除列族f2
alter 'user', {NAME => 'f1'}, {NAME => 'f2', METHOD => 'delete'}

user表的f1列族版本号改为5
alter 'people', NAME => 'info', VERSIONS => 5
启用表
enable 'user'


删除表
disable 'user'
drop 'user'


get 'person', 'rk0001', {FILTER => "ValueFilter(=, 'binary:中国')"}
get 'person', 'rk0001', {FILTER => "(QualifierFilter(=,'substring:a'))"}
scan 'person', {COLUMNS => 'info:name'}
scan 'person', {COLUMNS => ['info', 'data'], FILTER => "(QualifierFilter(=,'substring:a'))"}
scan 'person', {COLUMNS => 'info', STARTROW => 'rk0001', ENDROW => 'rk0003'}

scan 'person', {COLUMNS => 'info', STARTROW => '20140201', ENDROW => '20140301'}
scan 'person', {COLUMNS => 'info:name', TIMERANGE => [1395978233636, 1395987769587]}
delete 'person', 'rk0001', 'info:name'

alter 'person', NAME => 'ffff'
alter 'person', NAME => 'info', VERSIONS => 10


get 'user', 'rk0002', {COLUMN => ['info:name', 'data:pic']}