HBASE学习笔记

本文是对Hbase组件的一个学习总结,共包括如下章节的内容:

  • Hbase是什么
  • Hbase的数据模型
  • Hbase体系结构
  • 安装和运行Hbase
  • Hbase命令行

参考资料:

1、如果Hbase的数据要保存到hdfs上(一般生产环境下如此),需要确保有可用的hadoop运行环境,可参见《Hadoop运行环境搭建》一文。

2、因为Hbase运行依赖zookeeper服务,Hbase本身内置了zookeeper程序(往往用于开发和测试环境),如果希望独立部署zookeeper服务(一般生产环境下如此),可参见《Zookeeper学习笔记》一文。

一、Hbase是什么

HBase是Google Bigtable的克隆版。它是一个针对结构化数据的可伸缩、高可靠、高性能、分布式和面向列的动态模式数据库。和传统关系数据库不同,HBase采用了BigTable的数据模型:增强的稀疏排序映射表(Key/Value),其中,键由行关键字、列关键字和时间戳构成。HBase提供了对大规模数据的随机、实时读写访问,同时,HBase中保存的数据可以使用MapReduce来处理,它将数据存储和并行计算完美地结合在一起。

二、Hbase的数据模型

Hbase的数据逻辑上是存储在一张张表中。Hbase的表由行和列组成,行和列的交叉就是单元格,数据是存在单元格中的,单元格是有版本的,即一个单元格可存储多个版本的数据。

有几个重要的概念:

1、行键:
Hbase表的每行都有一个行健(类似关系表的主键),表中的行按照行键进行排序,对表中行的访问也是依据行健来访问的。

2、列族
行中的列被分成“列族”(column family)。同一个列族的所有成员(即列)具有相同的前缀。
表的列族是表模式的一部分,需要预先定义。但是列不是表模式的一部分。只要列族存在,客户端可以在更新时提供新的列,并存储它的值。
列名都以列族作为前缀,例如courses:history , courses:math 都属于 courses 这个列族。
这点与关系表不一样,关系表的列是表模式的一部分,关系表没有列族的概念。对于关系表,每行数据都有相同的列。但对于hbase表,每行数据都有相同的列族,但不一定有相同的列。

3、时间戳
HBase中通过行键和列确定的一个存贮单元称为单元格(cell)。每个 cell都保存着同一份数据的多个版本。默认情况下,版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由HBase (在数据写入时 )自动赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,HBase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。
说明:创建表时,默认情况下,每个列族只支持存储一个版本的数据。这个可以通过alter语句来更改。

4、单元(cell)
一个单元由{row key, column( =<family> + <label>), version} 唯一确定。cell中的数据是没有类型的,全部是字节码形式存储。

下面我们看一个例子。
假设有一张Hbase表,表名为webtable,该表有名为 contents、anchor 和 people 的三个列族。该表有两行数据,行健分别为cn 和 en。
对于第一行(cnn ),contents 列族包含一列(contents:html),anchor 包含两列(anchor:a,anchor:b),且第一行有5个版本。对于第二行(example),只有1个版本,contents 列族包含一列(contents:html),people列族包含一列(people:author)。
表中有些数据,下面通过表格的方式来展示下该表的数据。


此表中显示为空的单元格在 HBase 中不占用空间或实际上存在。这正是使 HBase “稀疏”的原因。表格视图并不是查看 HBase 数据的唯一可能的方法,对于 “稀疏”表,采用表格视图有时反而不是很方便。下面以类似json格式的视图来展示上面数据。

{
  "cn": {
    contents: {
      t6: contents:html: "内容"
      t5: contents:html: "内容"
      t3: contents:html: "内容"
    }
    anchor: {
      t9: anchor:a = "x"
      t8: anchor:b = "y"
    }
    people: {}
  }
  "en": {
    contents: {
      t5: contents:html: "内容"
    }
    anchor: {}
    people: {
      t5: people:author: "tom"
    }
  }
}

对于Hbase表,可以看作是key/value集合的nosql数据库,其中的key就是行键,value是一个单元格(cell)的列表,单元格通过“列族+列+版本”来唯一标识。

三、Hbase的物理存储结构

Hbase表中的所有行都按照行键的字典序排列,表在行的方向上分割为多个HRegion。如下图所示。


HRegion按大小分割。每一个表一开始只有一个HRegion,随着数据不断插入表,HRegion不断增大,当增大到一定阈值的时候,HRegion就会等分为两个新的HRegion。当表中的行不断增多,就会有越来越多的HRegion。

HRegion是HBase中分布式存储和负载均衡的最小单元。最小单元就表示不同的HRegion可以分布在不同的HRegion Server上。但是一个HRegion是不会拆分到多个HRegion Server上。

HRegion虽然是分布式存储的最小单元,但并不是存储的最小单元。事实上,HRegion由一个或者多个Store组成,每一个Store都保存一个列族。每一个Store又由一个memStore和多个StoreFile组成。StoreFile以HFile格式保存在HDFS上。如下图所示。


memStore位于HRegion Server的内存中,数据写入时,首先会写入到memStore中,然后当到达一定的阀值的时候,Memstore中的数据会被刷到HFile中。

四、Hbase体系结构

Hbase的架构与hdfs,yarn类似,采用主从的架构,即一个Hbase系统包含一个master服务,若干个regionserver服务(分布在集群不同的机器上)。另外因为Hbase依赖zookeeper,所以一个Hbase系统中还需要包含zookeeper服务(相对zookeeper服务来说,Hbase服务是zookeeper的客户端)。当然还有Hbase的客户端(终端用户或其它系统访问Hbase服务的界面)。

下图是Hbase集群系统的体系结构示意图。


因为Hbase的主节点master只有一个,存在单点故障风险。在实际的环境下,往往会给mater节点配置HA。

五、安装和运行Hbase

安装

1、下载Hbase安装压缩包,本文下载的是hbase-2.0.2-bin.tar.gz

2、解压到某个目录下,我们这里解压的位置是:
/home/hadoop/hbase2.0.2

3、修改hadoop用户的profile文件,设置环境变量

export HBASE_HOME=/home/hadoop/hbase-2.0.2
PATH=$PATH:$HBASE_HOME/bin

说明:Hbase的运行依赖java环境,需要确保安装运行Hbase的机器上有正常可用的java环境。

Hbase有三种运行模式:独立模式;伪分布式模式;分布式模式。下面分别介绍。

(一)独立模式

独立模式下,HBase系统的所有服务程序,Master、RegionServers 以及依赖的ZooKeeper服务都运行在一个jvm进程中,Hbase不依赖hdfs,其数据存在本地文件中。该模式,只能用于开发和测试环境,不能用于生产环境。
独立模式下,如果不修改Hbase的配置文件,Hbase和zookeeper数据会默认存储到本地的/tmp/hbase-当前用户名 目录下。但是如果所运行的机器上配置了hadoop环境,Hbase还是会去连接hdfs(这样如果Hadoop未启动,会报错)。所以最好能显示的进行配置。
这时修改Hbase安装目录下conf目录下的hbase-site.xml文件,配置文件的内容设置如下:

<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>file:///home/hadoop/hbasedata/hbase</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/home/hadoop/hbasedata/zk</value>
  </property>
</configuration>

配置文件中的habse.rootdir属性设置的是Hbase数据在本地的存储目录(使用本地磁盘存储,需要加file://前缀);habse.zookeeper.property.dataDir属性设置的是zookeeper数据的存储目录(因为zk的数据本身就是存储在本地,所以不用加file://前缀)。

然后在控制台运行 start-hbase.sh 脚本就可以启动Hbase服务,这时我们用jps命令去查看,可以看到有一个名称为HMaster的java进程(即包含hbase master,regionserver,zookeeper三个服务的合一进程)。如:

[hadoop@localhost ~]$ jps
......
24060 HMaster
.......

说明独立模式下的Hbase服务启动成功。

停止Hbase服务可以执行 stop-hbase.sh脚本。

实际上,在独立模式下,Hbase的数据也可以不存储在本地,而是存储到hdfs上,这时配置文件配置如下:

<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://namenode地址:8020/hbase</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>false</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/home/hadoop/hbasedata/zk</value>
  </property>
</configuration>

这种情况下,Hbase的各服务(包括zk服务)依然运行在同一个jvm进程中。只是Hbase的数据存储到hdfs文件系统中。配置文件中的hbase.rootdir属性的值是一个hdfs系统的目录。当然,这种情况下,要Hbase服务能正常运行,相应的hdfs服务得正常可用。

(二)伪分布式模式

这类似hadoop的伪分布式模式,所有的Hbase服务以多个进程的方式运行,但是运行在一台机器上。这种模式一样只适合开发和测试,不适合生产环境。
伪分布式模式的配置,只需将hbase.cluster.distributed属性值设为true。而Hbase的数据既可以设置存储在本地,也可以保存到hdfs上。如下面的配置(这里Hbase数据存储在本地):

<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>file:///home/hadoop/hbasedata/hbase</value>
  </property>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/home/hadoop/hbasedata/zk</value>
  </property>
</configuration>

在伪分布式模式下,通过bin目录下的hbase-daemon.sh来分别启动各个服务进程,操作如下:

hbase-daemon.sh start zookeeper
hbase-daemon.sh start master
hbase-daemon.sh start regionserver

通过上面的操作分别启动zookeeper服务进程,HBASE mater服务进程,HBASE regionserver服务进程。这时我们执行jps命令,会看到3个相关的进程:

[hadoop@localhost ~]$ jps
17585 HRegionServer
17349 HMaster
17212 HQuorumPeer

如果要关闭各个服务,可以依次执行下面三个操作:

hbase-daemon.sh stop regionserver
hbase-daemon.sh stop master
hbase-daemon.sh stop zookeeper

在伪分布式下,我们也可以不用Hbase自带的zookeeper,而是使用独立安装的zookeeper。关于独立zookeeper的安装,本文不再介绍,可参见《Zookeeper学习笔记》一文。

(三)分布式模式

在实际生产环境下,会采用分布式模式来启动Hbase。在分布式模式下,HBase守护进程的多个实例在集群中的多个服务器上运行。分布式的配置要求将hbase.cluster.distributed属性设置为true。通常情况下,hbase.rootdir被配置为指向高可用性的HDFS文件系统。这时集群系统将包含多个运行在不同服务器上的RegionServer,以及主要和备份Master和ZooKeeper守护程序(也是以集群方式部署)。

关于集群环境下的Hbase分布式部署,本文不作详细介绍。

六、Hbase命令行

Hbase服务启动后(最简单的方式就是使用本地文件系统以独立模式启动Hbase),就可以利用Hbase客户端程序访问Hbase服务了。
Hbase安装包中提供了一个命令行脚本hbase,位于bin目录下。在控制台下运行 hbase shell ,会出现交互式命令行程序(时间可能有点长,实际是启动了一个java进程),可以执行操作Hbase的各种命令,如:

[hadoop@localhost ~]$ hbase shell
...................................
Took 0.0042 seconds
hbase(main):001:0>

在提示符下输入help命令可以查看帮助信息。

1、查看用户空间下的所有表:

hbase(main):018:0> list
TABLE
0 row(s)
Took 0.0042 seconds

2、创建表:

hbase(main):063:0> create 'test','cf1','cf2'
Created table test
Took 0.7255 seconds

上面create命令创建了一个表,表名叫test,有2个列族cf1和cf2,属性采用默认的。注意hbase命令后的参数要用引号括起来。
这时我们如果再执行list命令,就能查到刚创建的test表。

3、查看表的信息

hbase(main):064:0> desc 'test'
Table test is ENABLED
test
COLUMN FAMILIES DESCRIPTION
{NAME => 'cf1', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DAT
A_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_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 => '65536'}
{NAME => 'cf2', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DAT
A_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_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 => '65536'}
2 row(s)
Took 0.0245 seconds

4、往表中插入数据:

hbase(main):066:0> put 'test','row1','cf1:a', 'a123'
Took 0.0244 seconds
hbase(main):067:0> put 'test','row1','cf1:b', 'b123'
Took 0.0045 seconds

上面操作,插入了两个数据,插入的是一行数据,行的关键字值为row1,列族cf1有两个成员,标示符分别是a和b。可以看出,put命令实际是往单元格中插入值。hbase表的列只是在数据插入时才确定。

5、查看表中所有数据

hbase(main):068:0> scan 'test'
ROW    COLUMN+CELL
 row1  column=cf1:a, timestamp=1544099621874, value=a123
 row1  column=cf1:b, timestamp=1544099630279, value=b123
1 row(s)
Took 0.0099 seconds

6、查看表中指定行、列族、列的数据

hbase(main):069:0> get 'test','row1'
COLUMN     CELL
 cf1:a     timestamp=1544099621874, value=a123
 cf1:b     timestamp=1544099630279, value=b123
1 row(s)
Took 0.0162 seconds
hbase(main):070:0>
hbase(main):071:0* get 'test','row1','cf1'
COLUMN     CELL
 cf1:a     timestamp=1544099621874, value=a123
 cf1:b     timestamp=1544099630279, value=b123
1 row(s)
Took 0.0118 seconds
hbase(main):072:0> get 'test','row1','cf1:b'
COLUMN     CELL
 cf1:b     timestamp=1544099630279, value=b123
1 row(s)
Took 0.0063 seconds

7、查看多版本数据
因为hbase表中的单元格可以允许存储多版本数据,但默认创建表的情况下,各列族允许的存储版本数的个数是1,可以通过desc命令能查看到。可以通过alter命令来重新修改,语法如:

alter '表名',{NAME=>'列族名',VERSIONS=>允许的版本数}

如下面例子:

hbase(main):073:0> alter 'test',{NAME=>'cf2',VERSIONS=>3}
Updating all regions with the new schema...
1/1 regions updated.
Done.
Took 1.8416 seconds

hbase(main):074:0> put 'test','row1','cf2:a','data1'
Took 0.0079 seconds
hbase(main):075:0> put 'test','row1','cf2:a','data2'
Took 0.0035 seconds
hbase(main):076:0> put 'test','row1','cf2:a','data3'
Took 0.0034 seconds

hbase(main):082:0> get 'test','row1','cf2:a'
COLUMN      CELL
 cf2:a      timestamp=1544104507106, value=data3
1 row(s)
Took 0.0143 seconds

hbase(main):084:0> get 'test','row1',{COLUMN=>'cf2:a',VERSIONS=>3}
COLUMN     CELL
 cf2:a     timestamp=1544104507106, value=data3
 cf2:a     timestamp=1544104503371, value=data2
 cf2:a     timestamp=1544104498175, value=data1
1 row(s)
Took 0.0091 seconds

可以看出,在get命令后加上 {COLUMN=>'cf2:a',VERSIONS=>3}参数可以返回多个版本的值。

8、删除数据
删除指定的行下的某个列族下的列(即某个单元格)
delete 'test','row1','data:a'
删除整行
deleteall 'test','row1'

9、禁用表

hbase(main):012:0> disable 'test'
Took 0.8346 seconds

在hbase中,删除表之前,必须先禁用表后才能删除。

10、删除表

hbase(main):012:0> drop 'test'
Took 0.4346 seconds

在实际应用中,我们一般会通过编写程序的方式去使用Hbase。最常见的是使用Hbase提供的java api来编写Hbase客户端程序。关于Hbase的java api的使用,在后面文章进行介绍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容