图片 9

HBase简介

Posted by

参考 

Chapter 5. 数据模型

Architecture

Table of Contents

65. Overview

5.1. 概念视图
5.2. 物理视图
5.3. 表
5.4. 行
5.5. 列族
5.6. Cells
5.7. 版本号

65.1. NoSQL?

HBase是一种”NoSQL”数据库。“NoSQL”一般指的是非关系型数据库,我们知道,关系型数据库支持SQL,也就是说HBase不支持SQL。非关系型数据库有许多种,BerkeleyDB是一种本地非关系型数据库,然而,HBase是分布式数据库。从技术上来讲,HBase更像是“Data
Store”,而不是“Data
Base”,因为它缺少许多关系型数据库的特性,比如:列类型、辅助索引、触发器、查询语言等等。(PS:意思是,从技术的角度讲,HBase更像一个数据存储,而不像数据库)

HBase集群扩展通过增加RegionServer来实现。如果一个集群从10扩展到20个RegionServer,那么,不仅仅是存储容量增加一倍,连处理能力也会增加一倍。对于关系型数据库而言,也可以用scale做到这样,但是需要指出的是,这需要特别的硬件和存储设备。HBase特性如下:

  • 强一致性读写:HBase不是一个“最终一致性”的数据存储。这使得它更适合高速度的聚集任务。
  • 自动分区:HBase的表通过region被分布在集群中,而region是自动拆分并重新分布数据行的。
  • 自动RegionServer容灾
  • Hadoop/HDFS集成:HBase支持HDFS作为它的分布式文件系统
  • MapReduce:HBase支持通过MapReduce基于HBase作为数据源的大量的并行处理
  • Java Client API:HBase支持通过Java
    API编程的方式来访问
  • Thrift/REST
    API:HBase也支持Thrift和REST这样的非Java的客户端
  • Block Cache and Bloom Filters
  • Operational
    Management:HBase提供web界面
5.7.1. HBase的操作(包括版本号操作)
5.7.2. 现有的限制

65.2. When Should I Use HBase?

并不是所有的问题都适合用HBase

第一、确保你有足够的数据。如果你有数以亿计的数据行,那么HBase是一个不错的选择。如果你只有数千或者百万的数据,那么使用传统的关系型数据库可能更好,因为事实上你的这些数据可能只需要一个或者两个节点就能处理得完,这样的话集群中的其它的节点就处于空闲状态。

第二、确保你不需要用到关系型数据库的特性(比如:固定类型的列、辅助索引、事务、查询语言等等)。基于关系型数据库构建的应用不能通过简单的改变JDBC驱动来传输到HBase中。从RDBMS到HBase是完全相反的两套设计。

第三、确保你有足够的硬件。因为当DataNode数量小于5的时候HDFS将不能正常工作了。

简单来说,应用程序是以表的方式在HBase存储数据的。表是由行和列构成的,全部的列是从属于某一个列族的。

65.3. What Is The Difference Between HBase and Hadoop/HDFS?

HDFS是一个分布式的文件系统,适合存储大文件,但它不能提供快速的个性化的在文件中查找。HBase是构建于HDFS基础之上的,并且它支持对大表的中的记录进行快速查找和更新。HBase内部将数据存放在HDFS中被索引的“StoreFiles”上以供快速查找。

行和列的交叉点称之为cell,cell是版本号化的。

69. Master

HMaster是Master Server的一个实现。Master
Server负责监视集群中所有的RegionServer实例,并且它也是所有元数据改变的一个对外接口。在分布式集群中,典型的Master运行在NameNode那台机器上。

cell的内容是不可切割的字节数组。

69.3. Interface

HMasterInterface接口是操作元数据的主要接口,提供以下操作:

  • Table (createTable, modifyTable,
    removeTable, enable, disable)
  • ColumnFamily (addColumn, modifyColumn,
    removeColumn)
  • Region (move, assign, unassign)

表的行键也是一段字节数组,所以不论什么东西都能够保存进去,不论是字符串或者数字。HBase的表是按key排序的,排序方式之针对字节的。全部的表都必需要有主键-key.
5.1. 概念视图

70. RegionServer

HRegionServer是RegionServer的实现,它负责服务并管理regions。在分布式集群中,一个RegionServer通常运行在一个DataNode上。

以下是依据BigTable 论文稍加改动的样例。

70.1. Interface

HRegionRegionInterface既包含数据的操作也包含region维护的操作

  • Data (get, put, delete, next,
    etc.)
  • Region (splitRegion, compactRegion,
    etc.)

有一个名为webtable的表,包括两个列族:contents和anchor.在这个样例里面,anchor有两个列
(anchor:cssnsi.com,
anchor:my.look.ca),contents仅有一列(contents:html)
列名

70.5. RegionServer Splitting Implementation

region
server处理写请求,它们被累积在内存中一个叫memstore的地方。一旦memstore文件满了,内容将被写到磁盘上作为store
file。这个事件叫做memstore flush。随着store
file的不断累积,RegionServer将合并它们成大文件,以减少store
file的数量。在每次刷新或者合并以后,region中数据的数量会发生改变。RegionServer根据切分策略来查看是否region太大了或者应该被切分。

逻辑上,region切分的操作很简单。找一个合适的位置,将region中的数据切分成两个新的region。然而,这个处理的过程并不简单。当切分发生的时候,数据并不是立刻被重写到这个心创建的女儿region上。

 

 

一个列名是由它的列族前缀和修饰符(qualifier)连接而成。比如列contents:html是列族
contents加冒号(:)加 修饰符 html组成的。

71. Regions

图片 1

Table 5.1. 表 webtable
Row Key Time Stamp ColumnFamily contents ColumnFamily anchor
“com.cnn.www” t9 anchor:cnnsi.com = “CNN”
“com.cnn.www” t8 anchor:my.look.ca = “CNN.com”
“com.cnn.www” t6 contents:html = “…”
“com.cnn.www” t5 contents:html = “…”
“com.cnn.www” t3 contents:html = “…”

73. HDFS

图片 2

5.2. 物理视图

Data Model

在HBase中,数据被存储在表中,有行和列。这些术语和关系型数据有一些重叠,当然这不是一个很好的类比,但是它对我们思考HBase的表示一个多维的map很有帮助。

Table

  由多行组成

Row

  HBase中的行由一个row
key和一个或多个列组成。Rows在存储的时候按照row
key的字典序存储。正因为如此,row
key的设计就显得非常重要。基于这一点,相关连的行相互之间存在附近。通常,row
key是一个网站的域名。如果你的row
key是域名,你应该以倒置的方式存储它们(比如:org.apache.www,org.apache.mail,org.apache.jira等等)。这样的话,所有的apache域名在表中是相近的位置,而不是被子域名的第一部分分开。

Column

  HBase中的列由一个列簇和一个列修饰符组成,它们之间用冒号分隔(:)

Column Family

  列簇由一系列的列和它们的值组成,这是基于性能考虑的。每一个列簇都有一系列的存储属性,比如:是否它们的值应该被缓存到内存中,它们的数据怎样被压缩,它们的row
key怎样被编码,等等。表中的每一行都有相同的列簇,即使一个给定的行在给定的列簇上没有存储任何数据。

Column Qualifier

  一个列修饰符被添加到列簇中为了给指定的数据片段提供索引。假设,给定的列簇是content,那么,一个列修饰符可能是content:html,其它的还有可能是content:pdf。虽然,列簇在表创建的时候就固定了,但是列修饰符是不确定的,而且不同的行可能有不通的列修饰符。

Cell

图片 3

Timestamp

  一个timestamp被写在每个value的旁边,它是一个value的版本修饰符。默认的,timestamp代表数据被RegionServer写入的时间,你也可以在写数据的时候指定一个不同的timestamp值

虽然在概念视图里。表能够被看成是一个稀疏的行的集合。但在物理上,它的是区分列族
存储的。新的columns能够不经过声明直接添加一个列族.

20. Conceptual View

图片 4

在这个例子中,有一个表叫“webtable”,它包含两行数据(com.cnn.www和com.example.www)和三个列簇(contents,anchor,people)。对于第一行(com.cnn.www),anchor包含两列(anchor:cssnsi.com,anchor:my.look.ca),contents包含一列(contents:html)。row
key为“com.cnn.www”的行有5个版本,而row
key为“com.example.www”的行有1个版本。contents:html列包含整个网站的HTML。

在这个表格中的空的单元格并不占用空间

下图是一个模拟,目的在于解释说明上面我们所说的,便于我们理解:

图片 5

Table 5.2. ColumnFamily anchor
Row Key Time Stamp Column Family anchor
“com.cnn.www” t9 anchor:cnnsi.com = “CNN”
“com.cnn.www” t8 anchor:my.look.ca = “CNN.com”

21. Physical View

虽然,在概念上,表看起来像是一行一行的,但物理上,它们是按照列簇被存储的。一个新的列修饰符可以在任意时刻被添加到列簇中。

图片 6

在前面的概念视图中的空的单元格是不被存储的。因此,请求contents:html列并且timestamp为t8将返回没有值。然而,如果不指定timestamp,那么某个列的大部分值都会被返回。如果指定多个版本,只有找到的第一个会被返回,因为数据是按照timestamp降序存储的。

Table 5.3. ColumnFamily contents
Row Key Time Stamp ColumnFamily “contents:”
“com.cnn.www” t6 contents:html = “…”
“com.cnn.www” t5 contents:html = “…”
“com.cnn.www” t3 contents:html = “…”

22. Namespace

一个命名空间是表的一个逻辑分组

值得注意的是在上面的概念视图中空白cell在物理上是不存储的,由于根本没有必要存储。

23. Table

因此若一个请求为要获取t8时间的contents:html。他的结果就是空。类似的。若请求为获取t9时间的anchor:my.look.ca。结果也是空。可是。假设不指明时间,将会返回最新时间的行,每一个最新的都会返回。比如,假设请求为获取行键为”com.cnn.www”。没有指明时间戳的话,活动的结果是t6下的contents:html,t9下的anchor:cnnsi.com和t8下anchor:my.look.ca。

24. Row

行按照row key字典升序存储

For more information about the internals of how HBase stores data, see
Section 9.7, “Regions”.
5.3. 表

25. Column Family

Columns in Apache HBase
are grouped into column
families.

列簇中所有的列成员都有相同的前缀。例如,列courses:history和courses:math都是courses这个列簇的成员。用冒号分隔列簇和列修饰符。列簇前缀必须由可以打印输出的字符组成。列修饰符可以由任意字节组成。列簇必须在表被定义的时候就声明好,因此列就不需要在表创建的时候定义了,并且可以随时新增。

物理上,所有的列簇成员被存储在一起。

表是在schema声明的时候定义的。
5.4. 行

26. Cells

A {row, column, version} tuple exactly specifies a cell in
HBase.

行键是不可切割的字节数组。

27. Data Model Operations

数据模型有4个主要操作,分别是Get、Put、Scan和Delete。这些操作是应用在表上的。

行是按字典排序由低到高存储在表中的。一个空的数组是用来标识表空间的起始或者结尾。
5.5. 列族

27.1. Get

返回指定行的属性

在HBase是列族一些列的集合。

27.2. Put

添加新的行到表中,或者更新已经存在的行

一个列族全部列成员是有着同样的前缀。比方,列courses:history 和
courses:math都是 列族
courses的成员.冒号(:)是列族的分隔符。用来区分前缀和列名。

27.3. Scans

扫描特定属性的多行

column
前缀必须是可打印的字符,剩下的部分(称为qualify),能够又随意字节数组组成。列族必须在表建立的时候声明。column就不需要了。随时能够新建。

27.4. Delete

从表中删除一行

在物理上,一个的列族成员在文件系统上都是存储在一起。

28. Versions

在HBase中,{row,column,version}可以确定一个单元格。当行和列被压缩成字节的时候,版本用long类型指定。在HBase中,版本以降序存储,所以,最近的值总是最先被发现。

由于存储优化都是针对列族级别的,这就意味着。一个colimn
family的全部成员的是用同样的方式訪问的。

29. Sort Order

对于所有的数据模型操作,HBase以数据被存储时的顺序返回。首先按行排序,其次按列簇,再其次按列修饰符,最后是timestamp。(PS:前是三个是字典升序,最后一个timestamp是降序)

5.6. Cells

30. Column Metadata

不存储列的元数据,因此,HBase可以支持每一行有许多列,行与行之间可以有多种不同的列。

A {row, column, version} 元组就是一个HBase中的一个
cell。Cell的内容是不可切割的字节数组。
5.7. 数据模型操作

31. Joins

HBase不直接join操作,至少不支持关系型数据库那种join。在HBase中,读取数据通过Get和Scan。

四个基本的数据模型操作是 Get, Put, Scan, 和 Delete. 通过 HTable
实例进行操作.
5.7.1. Get

33. Schema Creation

图片 7

Get 返回特定行的属性。

34. Table Schema Rules Of Thumb

  • regions的大小在10~50GB之间
  • cells的大小不超过10MB
  • 典型的,每个表的列簇在1~3个之间。HBase的表不应该被设计成模仿关系型数据库的表
  • 一个有1~2个列簇的表所拥有的regions大约在50~100个左右
  • 保持你的列簇名字尽可能的短

Gets 通过 HTable.get 运行。
5.7.2. Put

50. HBase as a MapReduce Job Data Source and Data Sink

HBase可以作为MapReduce作业的数据源。对于读写HBase的MapReduce作业,建议使用TableMapper和TableReducer。

如果你运行HBase作为数据源的MapReduce作业,你需要在配置文件中指定表和列名。

当你从HBase读取数据的时候,TableInputFormat请求regions的列表并且作为一个map。

 

Put 要么向表添加新行 (假设key是新的) 或更新行 (假设key已经存在)。 Puts
通过 HTable.put (writeBuffer) 或 HTable.batch (non-writeBuffer)运行。
5.7.3. Scans

54. HBase MapReduce Examples

 

Scan 同意多行特定属性迭代。

以下是一个在 HTable 表实例上的演示样例。 假设表有几行键值为 “row1”,
“row2”, “row3”, 另一些行有键值 “abc1”, “abc2”, 和 “abc3”.
以下的演示样例展示startRow 和 stopRow 能够应用到一个Scan
实例。以返回”row”打头的行。

HTable htable = … // instantiate HTable

Scan scan = new Scan();
scan.addColumn(Bytes.toBytes(“cf”),Bytes.toBytes(“attr”));
scan.setStartRow( Bytes.toBytes(“row”)); // start key is inclusive
scan.setStopRow( Bytes.toBytes(“row” + (char)0)); // stop key is
exclusive
ResultScanner rs = htable.getScanner(scan);
try {
for (Result r = rs.next(); r != null; r = rs.next()) {
// process result…
} finally {
rs.close(); // always close the ResultScanner!
}

5.7.4. Delete

Delete 从表中删除一行. 删除通过HTable.delete 运行。

HBase
没有改动数据的合适方法。所以通过创建名为墓碑(tombstones)的新标志进行处理。这些墓碑和死去的值。在主紧缩时清除。

參考 Section 5.8.1.5, “Delete”
获取删除列版本号的很多其它信息。參考Section 9.7.5.5, “Compaction”
获取很多其它有关紧缩的信息。
5.8. 版本号

一个 {row, column, version}
元组是HBase中的一个单元(cell).可是有可能会有非常多的单元的行和列是同样的,能够使用版本号来区分不同的单元.

rows和column
key是用字节数组表示的,version则是用一个长整型表示。这个long的值使用
java.util.Date.getTime() 或者 System.currentTimeMillis()产生的。

这就意味着他的含义是“当前时间和1970-01-01 UTC的时间差,单位毫秒。

在HBase中,版本号是按倒序排列的,因此当读取这个文件的时候,最先找到的是近期的版本号。

有些人不是非常理解HBase单元(cell)的意思。

一个常见的问题是:

假设有多个包括版本号写操作同一时候发起,HBase会保存全部还是会保持最新的一个?[16]

能够发起包括版本号的写操作。可是他们的版本号顺序和操作顺序相反吗?[17]

以下我们介绍下在HBase中版本号是怎样工作的。[18].
5.8.1. HBase的操作(包括版本号操作)

在这一章我们来细致看看在HBase的各个主要操作中版本号起到了什么作用。
5.8.1.1. Get/Scan

Gets实在Scan的基础上实现的。

能够具体參见以下的讨论 Get 同样能够用 Scan来描写叙述.

默认情况下。假设你没有指定版本号。当你使用Get操作的时候,会返回近期版本号的Cell(该Cell可能是最新写入的,但不能保证)。默认的操作能够这样改动:

假设想要返回返回两个以上的把版本号,參见Get.setMaxVersions()

假设想要返回的版本号不仅仅是近期的,參见 Get.setTimeRange()

要向查询的最新版本号要小于或等于给定的这个值,这就意味着给定的'近期'的值能够是某一个时间点。能够使用0到你想要的时间来设置。还要把max versions设置为1.

5.8.1.2. 默认 Get 样例

以下的Get操作会仅仅获得最新的一个版本号。

    Get get = new Get(Bytes.toBytes("row1"));
    Result r = htable.get(get);
    byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr"));  // returns current version of value          

5.8.1.3. 含有的版本号的Get样例

以下的Get操作会获得近期的3个版本号。

    Get get = new Get(Bytes.toBytes("row1"));
    get.setMaxVersions(3);  // will return last 3 versions of row
    Result r = htable.get(get);
    byte[] b = r.getValue(Bytes.toBytes("cf"), Bytes.toBytes("attr"));  // returns current version of value
    List<KeyValue> kv = r.getColumn(Bytes.toBytes("cf"), Bytes.toBytes("attr"));  // returns all versions of this column       

5.8.1.4. Put

一个Put操作会给一个cell,创建一个版本号,默认使用当前时间戳。当然你也能够自己设置时间戳。这就意味着你能够把时间设置在过去或者未来,或者随意使用一个Long值。

要想覆盖一个现有的值,就意味着你的row,column和版本号必须全然相等。
5.8.1.4.1. 不指明版本号的样例

以下的Put操作不指明版本号,所以HBase会用当前时间作为版本号。

      Put put = new Put(Bytes.toBytes(row));
      put.add(Bytes.toBytes("cf"), Bytes.toBytes("attr1"), Bytes.toBytes( data));
      htable.put(put);

5.8.1.4.2. 指明版本号的样例

以下的Put操作,指明了版本号。

      Put put = new Put( Bytes.toBytes(row ));
      long explicitTimeInMs = 555;  // just an example
      put.add(Bytes.toBytes("cf"), Bytes.toBytes("attr1"), explicitTimeInMs, Bytes.toBytes(data));
      htable.put(put);

5.8.1.5. Delete

有三种不同类型的内部删除标记 [19]:

Delete: 删除列的指定版本号.

Delete column: 删除列的全部版本号.

Delete family: 删除特定列族全部列

当删除一行,HBase将内部对每一个列族创建墓碑(非每一个单独列)。

删除操作的实现是创建一个墓碑标记。比如,我们想要删除一个版本号,或者默认是currentTimeMillis。就意味着“删除比这个版本号更早的全部版本号”.HBase不会去改那些数据,数据不会马上从文件里删除。

他使用删除标记来屏蔽掉这些值。[20]若你知道的版本号比数据中的版本号晚,就意味着这一行中的全部数据都会被删除。

參考 Section 9.7.5.4, “KeyValue” 获取内部 KeyValue 格式很多其它信息。
5.8.2. 现有的限制

关于版本号另一些bug(或者称之为未实现的功能),计划在下个版本号实现。
5.8.2.1. 删除标记误标新Put 的数据

删除标记操作可能会标记其后put的数据。

[21]记住,当写下一个墓碑标记后,仅仅有下一个主紧缩操作发起之后,墓碑才会清除。

假设你删除全部<=
时间T的数据。但之后,你又运行了一个Put操作,时间戳<=
T。就算这个Put发生在删除操作之后,他的数据也打上了墓碑标记。这个Put并不会失败,但你做Get操作时,会注意到Put没有产生影响。仅仅有一个主紧缩运行后。一切才会恢复正常。

假设你的Put操作一直使用升序的版本号,这个问题不会有影响。可是即使你不关心时间,也可能出现该情况。仅仅需删除和插入迅速相互尾随,就有机会在同一毫秒中遇到。

5.8.2.2. 主紧缩改变查询的结果

“设想一下,你一个cell有三个版本号t1,t2和t3。你的maximun-version设置是2.当你请求获取全部版本号的时候。仅仅会返回两个,t2和t3。假设你将t2和t3删除,就会返回t1。可是假设在删除之前,发生了major
compaction操作。那么什么值都不好返回了。[22]”

5.9. 排序

全部数据模型操作 HBase 返回排序的数据。

先是行。再是列族。然后是列修饰(column qualifier),
最后是时间戳(反向排序,所以最新的在前).
5.10. 列的元数据

对列族,没有内部的KeyValue之外的元数据保存。这样。HBase不仅在一行中支持非常多列。并且支持行之间不同的列。
由你自己负责跟踪列名。

唯一获取列族的完整列名的方法是处理全部行。HBase内部保存数据很多其它信息,请參考
Section 9.7.5.4, “KeyValue”.
5.11. 联合查询(Join)

HBase是否支持联合是一个网上常问问题。简单来说 :
不支持。至少不想传统RDBMS那样支持(如 SQL中带 equi-joins 或 outer-joins).
正如本章描写叙述的,读数据模型是 Get 和 Scan.

但并不表示等价联合不能在应用程序中支持。仅仅是必须自己做。
两种方法,要么指示要写到HBase的数据,要么查询表并在应用或MapReduce代码中做联合(如
RDBMS所展示,有几种步骤来实现。依赖于表的大小。如 nested loops vs.
hash-joins).
哪个更好?依赖于你准备做什么,所以没有一个单一的回答适合全部方面。


个人笔记
图片 8
Client
• 包括訪问HBase的接口并维护cache来加快对HBase的訪问
Zookeeper
保证不论什么时候,集群中仅仅有一个master
存贮全部Region的寻址入口。
实时监控Region server的上线和下线信息。并实时通知Master
存储HBase的schema和table元数据
Master
为Region server分配region
负责Region server的负载均衡
发现失效的Region server并又一次分配其上的region
管理用户对table的增删改操作
RegionServer
• Region server维护region,处理对这些region的IO请求
• Region server负责切分在运行过程中变得过大的region
Region
HBase自己主动把表水平划分成多个区域(region),每一个region会保存一个表
里面某段连续的数据;每一个表一開始仅仅有一个region,随着数据不断插
入表,region不断增大,当增大到一个阀值的时候,region就会等分会
两个新的region(裂变);
当table中的行不断增多,就会有越来越多的region。这样一张完整的表
被保存在多个Regionserver 上。
Memstore 与 storefile
一个region由多个store组成,一个store相应一个CF(列族)
store包括位于内存中的memstore和位于磁盘的storefile写操作先写入memstore,当memstore中的数据达到某个阈值,hregionserver会启动flashcache进程写入storefile,每次写入形成单独的一个storefile
当storefile文件的数量增长到一定阈值后,系统会进行合并(minor、major
compaction),在合并过程中会进行版本号合并和删除工作(majar),形成更大的storefile当一个region全部storefile的大小和超过一定阈值后,会把当前的region切割为两个,并由hmaster分配到相应的regionserver服务器,实现负载均衡

client检索数据,先在memstore找,找不到再找storefileHRegion是HBase中分布式存储和负载均衡的最小单元。最小单元就表示不同的HRegion能够分布在不同的
HRegion server上。
– HRegion由一个或者多个Store组成,每一个store保存一个columns family。


每一个Strore又由一个memStore和0至多个StoreFile组成。如图:StoreFile以HFile格式保存在HDFS上。
图片 9
图片 10

相关文章

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注