hbase timestamp获取key_大数据行业从业者需要了解的HBase数据模型相关的几个概念...

1 术语

Table

一个表包含多行

Row

一行包含:行键,一到多个列,列关联了值。

行是按行键(Row key)的字典顺序排序的,即按照字母顺序,或者数字大小顺序,由小到大排序。这样做是为了相关行的数据彼此相邻地存储。

行键是未解释的字节。空字节数组用来指示表名称空间的开始和结束。

Column

由Column Family和Column Qualifier构成,以:分隔。

Column Family

列族物理地组合一组列和它们的值。

每个列族有一系列存储属性,例如它的值是否应该被缓存到内存中,数据如何压缩,行键如何编码。

表中的每一行都有相同的列族,即使那行的指定列族没有存储任何值。在文件系统中,列族的所有成员都存储在一起。列族名被添加到文件系统路径。由于调谐和存储规范是在列族级完成的,因此建议所有列族成员具有基本相同的访问模式和大小特性。

Column Family必须由可打印字符组成。

Column Qualifier

可由任意二进制字符组成。

将列限定符添加到列族中,以提供给定数据块的索引。

列族是在表创建时定义的,而列限定符是可变的并且行之间的列限定符差别可以很大。

Cell

row key,Column Family、Column Qualifier构成的元组唯一确定一个Cell,Cell包含了这个元组和cell中存储的内容以及代表数据版本的时间戳(timestamp)。

Timestamp

时间戳与每个值一起写入,并且是给定版本的值的标识符。默认情况下,时间戳表示数据写入时RegionServer的时间,但当将数据放入到单元格中时,也可以指定不同的时间戳值。

2 概念视图

我们通过一个表格来展示概念视图。

532c3a8f15f097b677e342cfbfaf1ce3.png

表中涉及三个列族:contents,anchor,people

第3,4,5,6行都有列contents:html,第1行有列anchor:cnnsi.com,第2行有列anchor:my.look.ca,最后一行有列contents:html和people:author。

Amandeep Khurana的文章Introduction to hbase Schema Design概要

HBase的数据模型是稀疏的、分布式的、持久稳固的多维map。这个map是a row key, column key, 和a timestamp索引的。人们认为HBase是一种键值型存储,面向列族的数据库,版本map的map。

HBase也有行和列的概念,这是与RDBMS相同的地方,但却又不同。给出一些概念:

Table:HBase将数据组织成表,表名是字符和字符的组合,表名可以被用于文件系统路径中。

Raw:一个表中数据按行存储,每一行被row key 唯一标识。Row key没有数据类型,总是被做为byte[]来对待。

Column Family:每一行内的数据按Column Family分组。Column Family名称由字符和字符的组合,表名可以被用于文件系统路径中。

Column Qualifier:Column Qualifier定位了Column Family中的数据。同Row key一样没有类型,总是被做为byte[]来对待。

Cell:ow key, column family, 和column qualifier一起标识一个Cell,数据作为Cell的值被存储在Cell中,值也是byte[]。

Timestamp:一个Cell的版本,版本由版本号标识,默认为数据写入Cell时的时间戳。如果写入数据时不指定时间戳,那么默认为当前时间的时间戳。读取数据的时候如果不指定时间戳,那么默认返回最新的一个时间戳。可以为每个列族设置单元格时间戳的数量,默认是三个。

68e90c46b9254c946333f3ef96c600d8.png

HBase API中同样包括上述概念,提供三种数据操作:Get,Put,Scan。Get和Put操作需要指定row key。

可将HBase理解为多维的Map:

73ed1cc669f1ec8bac21157c5a3e6d20.png

row key 映射为列族表,column family映射为column qualifier表,column qualifier映射为timestamp表,每一个timestamp映射为值。row key等价于RDBMS中的主键。

可以将HBase理解为键值对的集合。

46a120d2c158689a758fae1fafe95133.png

这里键就是 row key,值就是其余的值,包括列族名,列分隔符等。

还可以将键认为是row key, column family, column qualifier, timestamp的组合,值就是实际存储在Cell中的数据。如果深入底层存储的话,就会看到,当读取指定一行的一个Cell时,最终读取的是一块数据,这块数据包含了这个cell,但同时很可能也包含了其他cell。这体现了,在HBase内部,Key被认为是[row key, column family, column qualifier, timestamp],值就是实际存储在Cell中的数据。

HBase表设计原理

设计HBase表就是回答如下问题:

1)row key的结构是怎样的,包含什么。

2)应该有多少个列族

3)列族包含什么样的数据

4)每个列族多少个列

5)列名是什么,尽管不必事先定义好列名。

6)Cell中的值是什么

7)每个cell有几个版本

需要注意的几点:

1)索引仅存在于Key上,这里的key就是上文说的[row key, column family, column qualifier, timestamp]。

2)按row key键排序的,表的每个Region负责row key空间的一部分,并有开始row key 和结束row key指定范围。

3)HBase中存储的任何值都是byte[]。除此之外无别的类型。

4)只有行级的原子性,没有跨行的原子性,意味着不支持多行事物。

5)表创建的时候就要定义列族。

3 物理视图

ColumnFamily anchor

37253e166f10022f3968b0136f26b807.png

ColumnFamily contents

875837de7d3dee74a7528e7c60ecdb28.png

在概念视图中的空单元不会被存储,一个列族的数据会存储在一起。

4 Namespace(名称空间)

名称空间从逻辑上将表分组,与RDBMS中的数据库概念相似。这种抽象概念为即将实现的多租户相关特性(multi-tenancy related features)奠定了基础:

· 配额管理(HBASE-8410)-限制命名空间可消耗的资源量(即Regions、Tables)

· 命名空间安全管理(Hbase9206)-为租户提供另一级别的安全管理。

· Region服务器分组(HBASE-6721)-一个名称空间或表可被限制在RegionServer的子集范围内,这样能够确保粗粒度的隔离。

命名空间可以被创建,删除,修改。

创建名称空间my_ns:create_namespace 'my_ns'

在指定的空间my_ns中建表my_table:create 'my_ns:my_table', 'fam'

删除名称空间:drop_namespace 'my_ns'

修改名称空间:

alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}

有两类预定义的Namespace:

hbase:系统命名称空间,用于包含HBase内部表。

default:创建表时,如果没有为表指定命名空间,系统会指定一个默认的命名空间,即default。

5 Versions(版本)

版本是一个指定的长整型数。例如使用方法java.util.Date.getTime() 或System.currentTimeMillis()获得的值。这两个方法返回值格式为:

the number of milliseconds since January 1, 1970, 00:00:00 GMT。

所以和本地时间是不同的。

HBase版本是降序排列的,因此访问HBase时,最新的数据首先被找到。

如果对一个Cell的多个写操作使用了相同的版本,最后执行的写操作结果可访问。

执行对一个Cell的写操作时,版本可以不是增大的。

指定版本数量

一列可包含的版本的最大数量是列模式的一部分,并且在创建表的时候指定,或者使用alter修改,或者使用HColumnDescriptor.DEFAULT_VERSIONS(3.0版本将要移除,使用ColumnFamilyDescriptorBuilder)修改。0.96及之后的版本默认为1,之前的版本默认为3。

hbase> alter ‘t1′, NAME => ‘f1′, VERSIONS => 5

可以为一个列族指定版本的最小数量,HBase 0.98.2起,可以为新创建的列指定全局默认的版本数量的最大值,即配置hbase-site.xml中的hbase.column.max.version。

版本与操作

Get/Scan

使用Table.get

Get操作是在Scan操作基础上实现的。

执行Get操作而没有明确指定版本,那么返回的是拥有最大值版本号的Cell,但这个Cell值可能不是最新写入的数据。

通过以下设置可以改变默认的行为:

Get.setMaxVersions()设置返回多个版本。

Get.setTimeRange()设置不返回最新版本。

例:

public static final byte[] CF = "cf".getBytes();

public static final byte[] ATTR = "attr".getBytes();

...

Get get = new Get(Bytes.toBytes("row1"));

get.setMaxVersions(3); // 将返回最新的三个版本

Result r = table.get(get);

byte[] b = r.getValue(CF, ATTR); //返回当前版本的值

List kv = r.getColumn(CF, ATTR);//返回所以版本的值

Put

如果键(由行、列族、列限定符、版本号共同定位一个键)存在就更新,不存在就插入新行。使用Table.put或Table.batch。

Put操作总是产生新的版本号,即某个时间戳。默认地Put操作使用服务器的System.currentTimeMillis()值作为版本号。可以自己指定版本(一个长整型),这意味着可以指定过去或者将来的时间,或使用一个和时间无关的长整型。

最好不要自己指定时间戳,因为HBase内部使用会使用这个时间戳,例如用他计算生命周期。

Delete

从表中删除一行,使用Table.delete。

HBase没有修改指定值的操作,因此处理删除操作的策略是通过创建一个被称为墓碑的标记实现的。这些墓碑联同已删除的数据会在执行大合并(major compactions)时被清除。

当删除一行数据时,HBase会为这一行的每一个列族设置一个墓碑标记。删除一行同时指定了版本或者使用System.currentTimeMillis(),意味着会删除所有小于等于此指定版本的Cell。如果指定的版本比任何版本都大,那么整行会被删掉。

有三种内部删除标识:

删除一列的指定版本,删除一列的所有版本,删除指定列族(列族被删除了,意味着属于这个列族的所有列都被删除了)。

如果为列族设置KEEP_DELETED_CELLS选项,那么删掉的Cell会被保留而不会真正删除。

通过hbase.hstore.time.to.purge.deletes设置可配置时间量,如果没有设置这个值或者将其设置为0,下次发生大合并时数据和标记都会被清除。否则当大合并发生在(毫秒为单位)

deletetime = timestamp +hbase.hstore.time.to.purge.deletes

之后时,数据会被删除。其中timestamp 为墓碑标记。

当前的限制

下面这些限制在hbase-2.0.0中已经解决。

Delete操作覆盖Put操作

即使Put操作在Delete之后发生,那么起作用的还是Delete。删除操作会写一个墓碑标识,只有下次大合并的时候才会处理墓碑和数据。一个put操作即使是在delete之后提交的,那么当put操作成功后,使用Get依然无法访问数据。这样只有在大合并发生以后Put操作才又起作用。如果你总是使用增大的版本号,那么Put操作总会起作用的。

大合并改变查询结果

创建一个Cell,有三个版本t1,t2,t3,最大版本数设置为2,那么只会返回t2,t3,如果删除t2或t3,t1才会出现。

可选的新版本和在HBase-2.0.0中删除的特性

在hbase-2.0.0中可以通过设置列的NEW_VERSION_BEHAVIOR属性为true 指定备用版本和删除操作(为了设置column family descriptor的属性,一定要先对表disable,然后再改变column family descriptor的属性)。

hbase-2.0.0版本消除了之前的一些限制,hbase-2.0.0的新特性如下:

Delete操作总是覆盖Put操作

如果Delete和Put这两个操作作用于同一个位置,即:相同的row, column family, qualifier 和timestamp ,不论哪一个先到达服务器,总是Delete起作用。

大合并不会改变查询结果

版本记帐也会因为版本被删除而考虑到版本总数的变化。这是为了确保在大合并(major compaction)情况下不会改变结果。

考虑到Cell MVCC,会耗费更多的CPU,测试来看会慢0%-25%。

如果进行复制,建议运行新的串行复制特性(hbase-2.0.0中没有这个特性,以后的版本或许会添加)。

文章Bending time in HBase选读

可以认为时间是HBase数据版本自动化控制机制。

在BigTable这篇论文中使用{row key, column key}来映射一个cell。每个cell包含了多个版本,由timestamp索引。

HBase基本不会重写数据,而仅仅是追加。通过压缩处理过程,数据文件偶尔会重写。数据文件是基本的键值对集合,键是{row key, column key, time}(column key应该包含两部分:Column Family和Column Qualifier)。每次当使用Put向已有cell中写数据时,新的键值对被追加到存储文件,即使指定已有时间戳也是如此。依赖于垃圾收集设置,废弃的数据将在大合并期间被清除。

有两种自动的版本清理机制:

如果指定最大版本,那么当数据版本超过这个设置时,最老的版本会被删除(标记删除)

指定TTL,如果版本比TTL老,那么会被删除。

6 Sort Order(排序)

所有的对HBase数据模型的操作返回值都是经过排序的。排序顺序依次为:Row(RowKey),ColumnFamily,Column Qualifier,Timestamp。

7 Column Metadata(列元数据)

不会在列族内部键值对实例之外存储任何列元数据。获得一个列族的所有列的方式就是访问所有行。

8 Joins(联接)

HBase不支持如同RDBMS一样的联接特性,但可以通过其他的方式实现相似的功能。

有两种策略:

一是将关联数据写入一张表,形成一张“宽表”。

二是在应用层实现表联接,例如使用MapReduce。

9 ACID

原子性(Atomicity):一个操作要么全成功,要么全失败。

一致性(Consistency):所有操作导致表直接从一个有效状态转换到另一个有效的状态。

隔离性(Isolation):数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

持久性(Durability):一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

可见性(Visibility):对于一个update操作,如果后续的读操作可以获得update已提交的数据,那么这个update就是可见的。

HBase不是一种遵从ACID的数据,但他具有一些特性。

涉及到的API

Read APIs:get,scan

Write APIs:put,batch put,delete

Combination (read-modify-write) APIs:incrementColumnValue,checkAndPut

Atomicity

1)所有的改变都是具有行原子性。操作返回success那么操作全部成功;返回failure操作全部失败;如果操作超时,要么全成功,要么全失败。

2)即使改变涉及到一行的多个列族,依然具有行原子性。

3)不具有多行原子性。例如一个插入多条数据的操作,可能只成功修改了部分行。这种与批量插入操作相关的API会返回一个成功表示成功代码的列表,但其实有的记录插入成功,有的失败,有的超时。

4)checkAndPut和compareAndSet (CAS)操作很像。

5)每一行的突变有明确的顺序,而不会出现交叉的情形。例如,写入a=1,b=1,c=1,另一个写入操作为a=2,b=2,c=2,那么对此行来说,要么是a=1,b=1,c=1,要么是a=2,b=2,c=2,但一定不会类似于a=1,b=2,c=1这种情形。要注意,这种特性只是针对单行,对于多行不适用。

Consistency和Isolation

1)通过API访问会获得整行数据。当调用API返回多行时,只获取了某行的一部分数据这种情况是不可能发生的。

2)对于列族亦是如此。例如获得整行数据的get操作执行的同时,发生了许多突变1,2,3,4,5(可以理解为突变的序号是1,2,3,4,5),此get操作会返回完整的一行,这行数据已经存在于突变i与突变i+1之间的某一时间点,i取值范围是从1到5。

3)在整个的编辑历史中,行的状态之后向前移动。

Scans的Consistency

Scan不是表的一致性视图,也不会展示快照隔离。但其具有如下特性:

1)通过Scan返回的任何行都是一个一致视图(例如,整行的版本存在于某个时间点)

2)Scan所体现的数据的视图总是和Scan开始执行的时候一样新。为实现这一特性,必须满足一下规则:

A) 例如,如果客户端A插入数据X,然后客户端B与服务器通信,客户端B发起的任何Scan包含的数据和X一样新。

B) 一个scan必须能够反映scanner创建之前提交的所有突变,并可能会反映scanner创建之后提交的突变。

C) Scan必须包括scan之前所有写入的数据(除了scan之后数据发生了改变,这种情况下,反映的可能是数据的变化)。

这和关系型数据库的读隔离级别相似。

Visibility

1) 当某一客户端的对突变的响应为success,那么随后这一客户端和所有通过旁通道与HBase通信的客户端都能看到这一突变。

2) 一行一定不能展现被称为时间旅行的特性。意思就是,如果一系列的突变使一行的状态连续地变化,那么任何一系列并发读都将返回这些状态的子序列。例如使用incrementColumnValue操作一行的多个cell,那么客户端一定不能看到任何被删掉的cell,不论在突变发生后使用API的哪个读操作。

3) 读操作返回的一个cell的任何版本保证是持久化的。

Durability

1)所有可见的数据都是持久化数据,也就是说永远不会读取不在磁盘上的数据。

4) 任何返回success的操作(增删改,且操作不抛异常)都会被持久化。

5) 任何返回failure的操作都不会被持久化。

6) 所有合理的失败情景都不会影响到本文档的其他保证。

Tunability

有时处于性能的考虑,hbase提供了几个调节参数:

1)Visibility被调整为每次读取都可以stale reads或time travel。

2)Durability可能被调整为周期性的。

注解

1)intra-row scanning不保证一致视图,例如一个RPC调用获取一行的一部分,接下来的RPC调用获得另一部分。当你设置一个限制Scan.next(Scan.setBatch(int batch)设置)能返回多少值时,Intra-row scanning就会发生。

2)在HBase的上下文中,持久化到磁盘意味着hflush()调用了事物日志。实际上并不意味着数据被刷写到磁性介质上了,而仅仅是数据被写入操系统缓存在所有日志副本上。整个数据中心停电的情况下,编辑的内容可能没有真正被持久化。

3)Puts操作要么全成功要么全失败,假如他们真的被发送给RegionServer。如果使用了writebuffer,直到writebuffer被填满或者明确地执行flushed,那么Puts才会被发送给RegionServer。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值