转载地址:https://dxer.github.io/2016/03/18/hbase/
HBase一些基本概念
1、Row key 行主键,在对HBase进行查询时候只能依靠Row key,HBase不支持条件查询等类似于一些主流数据库的查询方式,读取记录只能依赖行主键以及进行全局扫面,可以将行主键想象成主流数据库查询过程中用到的主键(例如,id)。
2、Column Family 列族,可以将列族想象成日常主流数据库中的表结构的所有列的一个大管家,列族中存储了所有列的名称,整个表包括多少列,列族就包括多少(除去Row key和Timestamp列)。
3、Column 列,HBase的每个列都隶属于一个列族,以列族名称作为前缀,同一列族中的所有列会聚集在一个存储单元上,同时按照Column key进行排序。
4、Timestamp 在HBase中,通过row key 和 Colum Family确定一份数据,同一个row key和Colum Family可能有多份不同的数据,HBase通过时间戳来区分这些数据,同时按照时间戳对左右的数据进行排序,最新的数据排在最前面,时间戳默认为系统当前时间(精确到毫秒),同时也可以人为设置该值。
5、Value 我们在HBase表中精确查询数据时,通过TableName找到表,接着通过Row key找到对应的行,然后通过ColumnKey找到相应的列,最后根据时间戳找到最新的需要查询的值,这个值就是value。
6、存储类型 在HBase中,表名称是字符串,行键和列名称是二进制值(即就是Java中的Byte[]),时间戳是一个64为的整数(Java中的long类型),最后的查询结果Value是字节数组(Java中的byte[]类型)。
7、存储结构
在HBase中,整个数据表是按照行键进行排序,每行包括任意数量的列,列和列之间通过列键进行排序,每列包括若干的数据,整个HBase的存储结构可以理解如下:
123456789 |
Table( Row key,List( SortedMap( Column,list( Value,Timestamp ) ) )) |
HBase数据模型
- 表(table):HBase用表组织数据。表名是字符串(String),由可以在文件系统路径里使用的字符组成。
- 行(row):在表里,数据按行存储。行由行健(rowkey)唯一标识。行健没有数据类型,视为字节数组byte[]。
- 列族(column family):行里的数据按照列族进行分组,列族也影响到HBase数据的物理存放。因此,他们必须事前定义并且不轻易修改。表中每行拥有相同列族,尽管行不需要在每个列族里存储数据,列族名字是字符串(String),由可以在文件系统路径里使用的字符组成。
- 列限定符(column qualifier):列族里的数据通过列限定符或列来定位。列限定符不必事前定义。列限定符不必在不同行之间保持一致。就像行健一样,类限定符没有数据类型,视为字节数据byte[]。
- 单元(cell):行健、列族和列限定符一起确定一个单元。存储在单元里的数据成为单元值(value)。值没有数据类型,视为字节数组byte[]。
- 时间版本(version):单元值有时间版本。时间版本用时间戳标识,是一个long型。没有指定时间版本时,当前时间戳作为操作的基础。HBase保留单元值时间版本的数量基于列族进行配置。默认3个版本。
数据坐标
行健、列族、列限定符和时间版本
写
执行写入的时候会写到两个文件:预写式日志(write-ahead log,也称HLog)和MemStore。HBase的默认方式是把写入动作记录在这两个地方,以保证数据持久化。只有当这两个地方的变化信息都写入并确认后,才认为写动作完成。
MemStore是内存里的写入缓冲区,HBase中数据在永久写入硬盘之前在这里积累。当MemStore填满后,其中的数据会刷写到硬盘,生成一个HFile文件。HFile是HBase使用底层存储格式。HFile对应列族,一个列族可以有多个HFile,但一个HFile不能存储多个列族的数据。在集群的每个节点上,每个列族都有一个MemStore。
注:不写入WAL会在RegionServer故障时增加丢失数据的风险。关闭WAL,出现故障时HBase可能无法恢复数据,没有刷写到硬盘的所有写入数据都会丢失。
读
HBase在读操作上使用了LRU(最近最少使用算法)缓存技术。也叫作BlockCache。BlockCache设计用来保存从HFile里读入内存的频繁访问的数据,避免硬盘读。每个列族都有自己的BlockCache。
BlockCache中的Block是HBase从硬盘完成一次读取的数据单位。HFile物理存放形式是一个Block的序列外加这些Block的索引。从HBase中读取一个Block需要先将索引上查找一次改Block然后从硬盘读出、Block是建立索引的最小数据单位,也是从硬盘读取的最小数据单位。Block大小按照列族设定,默认是64kb。如果主要用于随机查询,可能需要细粒度的Block索引,小一点儿的Block更好一些。Block变小会导致索引变大,进而消耗更多内存。如果经常执行顺序扫描,一次读取多个Block,大一点的Block更好一些。Block变大意味着索引项变少,索引编写,因此节省内存。
从HBase总读出一行,首先会检查MemStore等待修改的队列,然后检查BlockCache看包含改行的Blocj是否最近被访问过,最后访问硬盘上对应的HFile。
删
执行HBase删除命令的时候,实际上数据并不会立即删除,只是会在该数据上打上删除的记录。被标记的记录不能在Get和Scan命令中返回结果。因为HFile文件是不能改变的,直到执行一次大合并,含有这些标记的数据才会被处理,被删除的数据占用的空间才会释放。
大合并(major compaction):处理给定region的一个列族的所有HFile。大合并完成后,这个列族的所有HFile合并成一个文件,可以从Shell中收工出发整个表(或者特定region)的大合并。大合并是HBase清理被删除记录的唯一机会
小合并(minor compaction):把多个小HFile合并成一个大HFile。
HBase Shell命令
Command | 描述 |
---|---|
alter | 修改列族模式 |
count | 统计表中行的数量 |
create | 创建表 |
describe | 显示表相关的详细信息 |
delete | 删除指定对象的值(可以为表,行,列对应的值,另外也可以指定时间戳的值) |
deleteall | 删除指定行的所有元素值 |
disable | 使表无效 |
enable | 使表有效 |
drop | 删除表 |
exists | 测试表是否存在 |
exit | 退出HBase Shell的值 |
get | 获取行或单元的值 |
incr | 增加指定表、行或列的值 |
list | 列出HBase中存在的所有表 |
put | 向指定的表单元添加值 |
tools | 列出HBase所支持的工具 |
scan | 通过对表的扫描来获取对应的值 |
status | 返回HBase集群的状态信息 |
shutdown | 关闭HBase集群(与exit不同) |
truncate | 重新创建指定表 |
version | 返回HBase版本信息 |
create
创建表
12345678 |
create ‘t1‘, {NAME => ‘f1‘, VERSIONS => 5} create ‘t1‘, {Name => ‘f1‘}, {NAME => ‘f2‘}, {NAME => ‘f3‘} #等价于: create ‘t1‘, ‘cf‘, ‘cf2‘, ‘cf3‘ |
list
列出HBase中包含的表名称
put
向指定表中添加值
12 |
put ‘t1‘, ‘rowkey‘, ‘cf:name‘, ‘test‘, ts#向t1表的rowkey,列cf:name添加值name,并指定时间戳为ts |
scan
对表的扫描来获取对应的值
123 |
scan ‘t1‘scan ‘t1‘, {COLUMNS => ‘cf‘}scan ‘t1‘, {COLUMNS => ‘cf‘, LIMIT => 10} |
get
获取行或者单元的值。
12 |
get ‘t1‘, ‘rowkey‘get ‘t1‘, ‘rowkey‘, {COLUMN => ‘cf:name‘} |
注:COLUMN和COLUMNS是不同的,scan操作中的COLUMNS指定的是表的列族,get操作中的COLUMN指定的是特定的列,COLUMN的值是指上是”列族+列修饰符”