HBase
安装单机
环境
Centos7 Hbase
安装JDK
代码语言:txt复制yum install java-1.8.0-openjdk* -y
下载HBASE
http://mirror.bit.edu.cn/apache/hbase/2.2.6/
解压到Linux
代码语言:txt复制tar -xf hbase-1.2.8-bin.tar.gz
cd hbase-2.2.6
修改JAVA_HOME配置文件
代码语言:txt复制vim conf/hbase-env.sh
// 注意这个是在CentOS上的java位置
export JAVA_HOME=/etc/alternatives/java_sdk_1.8.0/
启动
代码语言:txt复制./bin/start-hbase.sh
查看Web-UI
http://localhost:16010
查看Hbase的Web UI,以便查看是否启动成功。
Client
自带的Client
代码语言:txt复制./hbase shell
# 查看帮助
help
创建表
需指定表名称
和列簇名
hbase(main):105:0> create 'mytest', 'lt'
Created table mytest
Took 0.7247 seconds
=> Hbase::Table - mytest
查看当前表信息
代码语言:txt复制hbase(main):001:0> list 'mytest'
TABLE
mytest
1 row(s)
Took 0.2895 seconds
=> ["mytest"]
查看表详细信息
代码语言:txt复制hbase(main):002:0> describe 'mytest'
Table mytest is ENABLED
mytest
COLUMN FAMILIES DESCRIPTION
{NAME => 'lt', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS
=> 'FALSE', CACHE_DATA_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', RE
PLICATION_SCOPE => '0', BLOOMFILTER => 'ROW', CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_
WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION => 'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '6553
6'}
1 row(s)
QUOTAS
0 row(s)
Took 0.1686 seconds
写入数据
随便写入4条数据
其实并不随便,对应的解释,可以看后面的数据模型
部分。
hbase(main):003:0> put 'mytest','row1','lt:a','value1'
Took 0.0392 seconds
hbase(main):004:0> put 'mytest','row2','lt:b','value2'
Took 0.0042 seconds
hbase(main):005:0> put 'mytest','row3','lt:c','value3'
Took 0.0025 seconds
hbase(main):006:0> put 'mytest','row3','lt:d','value4'
Took 0.0054 seconds
查看表中所有数据
代码语言:txt复制hbase(main):007:0> scan 'mytest'
ROW COLUMN CELL
row1 column=lt:a, timestamp=1609210379880, value=value1
row2 column=lt:b, timestamp=1609210387527, value=value2
row3 column=lt:c, timestamp=1609210396636, value=value3
row3 column=lt:d, timestamp=1609210494696, value=value4
3 row(s)
Took 0.0188 seconds
查看一条信息
案例1
代码语言:txt复制get 'mytest' , 'row1'
COLUMN CELL
lt:a timestamp=1609210379880, value=value1
1 row(s)
Took 0.0202 seconds
案例2
代码语言:txt复制hbase(main):009:0> get 'mytest' , 'row3'
COLUMN CELL
lt:c timestamp=1609210396636, value=value3
lt:d timestamp=1609210494696, value=value4
1 row(s)
Took 0.0059 seconds
可以看到,row1
,row2
实则是key
。
而获取到的数据,也不太一样,这是因为,在写入时,为row3
多写入了一条属性。
其他
可输入help
,查看更多命令。
HBASE的数据模型
Table
对应上面的案例mytest
Hbase的table由多个行组成
Row
对应上面的案例row1
...
一个行在Hbase中由一个或多个有值的列组成。Row按照字母进行排序,因此行健的设计非常重要。这种设计方式可以让有关系的行非常的近,通常行健的设计是网站的域名反转,比如(org.apache.www, org.apache.mail, org.apache.jira),这样的话所有的Apache的域名就很接近。
Column
对应上面的案例lt:
列由列簇加上列的标识组成,一般是“列簇:列标识”,创建表的时候不用指定列标识
Column Family
对应上面的案例lt:a
、lt:b
....
列簇在物理上包含了许多的列与列的值,每个列簇都有一些存储的属性可配置。例如是否使用缓存,压缩类型,存储版本数等。在表中,每一行都有相同的列簇,尽管有些列簇什么东西也没有存。
Column Qualifier
列簇的限定词,理解为列的唯一标识。但是列标识是可以改变的,因此每一行可能有不同的列标识
Cell
Cell是由row,column family,column qualifier包含时间戳与值组成的{row key,column(=<family> <qualifier>),version}
,一般表达唯一确定的单元.
一般get出来的为最新版本,也可以指定,如下为
显示最新的2个版本的数据
代码语言:txt复制hbase(main):004:0> get 'mytest','row3',{COLUMNS=>['lt:c','lt:d'],VERSIONS=>2}
COLUMN CELL
lt:c timestamp=1609210396636, value=value3
lt:d timestamp=1609210494696, value=value4
1 row(s)
Took 0.0050 seconds
Timestamp
对应上面的案例timestamp=1609210494696
...
时间戳一般写在value的旁边,代表某个值的版本号,默认的时间戳是你写入数据的那一刻,但是你也可以在写入数据的时候指定不同的时间戳
关于索引
HBase 是一个稀疏的、分布式、持久、多维、排序的映射,它以行键(row key),列键(column key)和时间戳(timestamp)为索引。
关于排序
Hbase在存储数据的时候,有两个SortedMap,首先按照rowkey进行字典排序,然后再对Column进行字典排序。
代码语言:txt复制hbase(main):009:0> get 'mytest' , 'row3'
COLUMN CELL
lt:c timestamp=1609210396636, value=value3
lt:d timestamp=1609210494696, value=value4
1 row(s)
Took 0.0059 seconds
所以,刚刚的查询单条数据时,可以看到是,先根据 row*
,进行字典排序,在把row3
的属性,也就是lt:*
进行字典排序。
Hbase与关系型数据库对比
属性 | Hbase | RDBMS |
---|---|---|
数据类型 | 只有字符串 | 丰富的数据类型 |
数据操作 | 增删改查,不支持join | 各种各样的函数与表连接 |
存储模式 | 基于列式存储 | 基于表结构和行式存储 |
数据保护 | 更新后仍然保留旧版本 | 替换 |
可伸缩性 | 轻易增加节点 | 需要中间层,牺牲性能 |
Hbase设计时要考虑的因素
Hbase关键概念:表
,rowkey
,列簇
,时间戳
- 这个表应该有多少列簇
- 列簇使用什么数据
- 每个列簇有有多少列
- 列名是什么,尽管列名不必在建表时定义,但读写数据是要知道的
- 单元应该存放什么数据
- 每个单元存储多少时间版本
- 行健(rowKey)结构是什么,应该包含什么信息
设计要点
行键设计
关键部分,直接关系到后续服务的访问性能。如果行健设计不合理,后续查询服务效率会成倍的递减。
- 避免单调的递增行健,因为Hbase的行健是有序排列的,这样可能导致一段时间内大部分写入集中在某一个Region上进行操作,负载都在一台节点上。可以设计成: metric_type,不同的metric_type可以将压力分散到不同的region上
- 行健短到可读即可,因为查询短键不必长键性能好多少,所以设计时要权衡长度。
- 行健不能改变,唯一可以改变的方式是先删除后插入
列簇设计
列簇是一些列的集合,一个列簇的成员有相同的前缀,以冒号(:)作为分隔符。
- 现在Hbase不能很好处理2~3个以上的列簇,所以尽可能让列簇少一些,如果表有多个列簇,列簇A有100万行数据,列簇B有10亿行,那么列簇A会分散到很多的Region导致扫描列簇A的时候效率底下。
- 列簇名的长度要尽量小,一个为了节省空间,另外加快效率,比如d表示data,v表示value
列簇属性配置
HFile数据块,默认是64KB
,数据库的大小影响数据块索引的大小。数据块大的话一次加载进内存的数据越多,扫描查询效果越好。但是数据块小的话,随机查询性能更好。
> create 'mytable',{NAME => 'lt1', BLOCKSIZE => '65536'}
数据块缓存,数据块缓存默认是打开的,如果一些比较少访问的数据可以选择关闭缓存
代码语言:txt复制> create 'mytable',{NAME => 'lt1', BLOCKCACHE => 'FALSE'}
数据压缩,压缩会提高磁盘利用率,但是会增加CPU的负载,看情况进行控制
代码语言:txt复制> create 'mytable',{NAME => 'lt1', COMPRESSION => 'SNAPPY'}
Hbase表设计是和需求相关的,但是遵守表设计的一些硬性指标对性能的提升还是很有帮助的,这里整理了一些设计时用到的要点。