背景
HBase是Apache顶级项目Hadoop的子项目。与传统的RDBMS关系型数据库(Oracle, MySQL, DB2, Hive)等不同,HBase属于NoSQL数据库。 Hbase是对于谷歌提出的BigTable的开源实现。
定义
BigTable里的定义:BigTable is a sparse, distributed, persistent mulitdimensional sorted map, indexed by a row key, column key, and a timestamp.
具体了解下这些定义,就可以了解HBase独特的数据模型。
- map 键值对
- sparse 稀疏
- distributed 分布式
- persistent 持久化
- multidimensional 多维度
- sorted 排序
- index by a row key, column key, a timestamp 索引
HBase的数据模型
HBase里面的结构层级主要有:
Namespace -> Table -> Row -> Column Family -> Column Qualifier -> Cell
Namespace:
Hbase默认有两张表:hbase, default。 hbase存储系统配置。所有不指定Namespace的表格都存储在default下。 当然可以自己创建Namespace, 并建立其下对应的表格。
Table:
一样的概念, 只不过table创建的时候只需要指定Column Family(列簇)
Column Family:
列簇, 列的最小存储单元
Column Qualifier:
列簇的列,每一行的列不需要一致
Cell:
由row key, column family, column Qualifier唯一索引的一个值,Cell拥有版本号,默认采用的是插入的时间戳。
-
用惯用的数据库表格表示下:
image.png -
更直观的键值对表示法:
image.png
特点
其实从以上定义里已经可以发现HBase的特点了,归纳一下
- 大,表存储不设限制,支持上亿行, 上百万列
- 列簇的概念,拥有面向列的存储和控制
- 稀疏,列簇中的列可以拥有不同的列,稀疏化的存储结社空间
- 版本控制, 默认插入时的时间戳为cell的版本
- 数据统一为不解析的byte数组,没有类型的概念。 包括存储的键和值都是byte
- 方便扩展,只需要扩展对应的regionserver就可以。关系型的数据库的扩展取决于server的上限,除非分库分表。
选择
什么时候适合?
- 当行级别达到一个亿或者十亿级别的时候,适合采用HBase做分布式存储。 其QPS查询性能非常高。
- 确定项目不需要考虑RDBMS提供的有用的特性(二级索引,类型化的列, 高级查询)的时候,可以采用。
部署运行参考官网
shell 操作
启动shell界面
bin/hbase shell
help可以查看支持的命令。 下面列举几个常用的命令:
- 查看数据表
list
- 创建数据表
hbase(main):004:0> create 'test2', 'test_cf'
0 row(s) in 2.7530 seconds
=> Hbase::Table - test2
- 插入数据
hbase(main):006:0> put 'test2','row1','test_cf:cq1','value1'
0 row(s) in 1.9330 seconds
hbase(main):008:0> scan 'test2'
ROW COLUMN+CELL
row1 column=test_cf:cq1, timestamp=1521603395109, value=value1
1 row(s) in 0.0400 seconds
hbase(main):009:0> get 'test2', 'row1'
COLUMN CELL
test_cf:cq1 timestamp=1521603395109, value=value1
1 row(s) in 0.1450 seconds
- 获取表数据
get
- 全表扫描
scan
scan 'hbase:meta'
scan 'hbase:meta',{COLUMNS => 'info:regioninfo'}
scan 'ns1:t1',{COLUMNS=>['c1','c2'],LIMIT=>10,STARTROW=>'xyz'}
scan 't1',{COLUMNS=>'c1',TIMERANGE=>[1303668804,1303668904]}
scan 't1',{REVERSED=>true}
scan 't1',{
ROWPREFIXFILTER=>'row2',
FILTER=>"(QualifierFilter(>=,'binary:xyz'))
AND (TimestampsFilter(123,456))"}
scan 't1',{FILTER => org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1,0)}
scan 't1',{CONSISTENCY=>'TIMELINE'}
设置操作属性:
scan 't1',{COLUMNS => ['c1','c2'],ATTRIBUTES=>{'mykey'=>'myvalue'}}
scan 't1',{COLUMNS=>['c1','c2'],AUTHORIZATIONS=>['PRIVATE','SECRET']}
有个额外的选项:CACHE_BLOCKS,默认为true
还有个选项:RAW,返回所有cells(包括删除的markers和uncollected deleted cells,不能用来选择特定的columns,默认为default)
如:scan 't1',{RAW=>true,VERSIONS=>10}
- 删除数据表
disable 'test'
#先要disable才能drop
drop 'test'
- 查看namespace
hbase(main):003:0> list_namespace
NAMESPACE
default
hbase
2 row(s) in 0.3480 seconds
案例学习
参考来自文章
假设社交网站有一个user表,包含user_id, user_name。 需要设计一个关注的功能。
该功能有以下几点操作
- 读操作
- user 关注了哪些人
- 给定的user A 是否关注user B
- 哪些人在关注user A
- 写操作
- 用户关注了一个用户
- 用户取消对一个用户的关注
传统的关系型数据库的设计一般如下:
设计一张user_follow表. (id, follower_id, folloee_id)。 一旦发生操作,更新或读取user_follower表,此表能满足所有场景。
那如果切换成HBase的思维呢? (此处例子不一定是最适合HBase的,只是用来查看设计思维)
设计一:
设计一个表user_follow, 简单点一个列簇(column family) follow。
使用userid作为row key , 使用什么作为列名呢? 假设直接使用被跟随者作为列名。格式如下:
image.png
此处的列中存储的cell值没有特别用途,直接存个1.
这个方案能适配读操作中的1,2, 却没法快速的查询3. 改进设计如设计二
设计二:
- 再建立一张新表,保存与设计一关系相反的数据, 即被跟随者作为row key, 保存跟随了他的用户。
- 在设计一的基础上再加一个对应的行,用 跟随者 + 被跟随者的名字作为row key.
这就是一个意识的改变,row key的存储是任意的,无类型的,可以做很多非结构的设计。 但是一般会存储row key的hash值,方便统一长度和计算性能。
经验法则(rules of thumb)
- 表设计
- region最好大小为10-50G
- cf大概一张表1-3个为好,不要用HBASE mimic 模仿关系型数据库
- 一个有1或者2个cf的表最好的region值为50-100, Remember that a region is a contiguous segment of a column family
- cf名字越短越好
网友评论