HBase,基于Google Bigtable实现的开源、分布式、可伸缩的列式存储数据库,诞生于Hadoop,也是Hadoop生态的重要一环,如今作为一个Apache顶级项目,早已经不能将其仅仅看作Hadoop的一部分,基于Storm,Spark等框架的数据处理方案中,都有它的身影,可以说它已经成为大数据工具箱中非常重要的一种数据存储工具,也因此必然会被很纳入很多人学习计划。
对于一个新技术的入门,我认为一种有效的学习方式是:
对其有简要认知后,通过Quick Start式的使用,获得直观的感知,消除距离感,然后再带着使用过程中的疑问去了解其背后的真相,最后支撑我们将其应用到实际工程。
我将消除距离感这一阶段,称之为 百闻不如一Run 。
本文分三部分带你完成对HBase的 百闻不如一Run :数据模型概述、环境部署和基本操作。
版本:本文基于HBase 1.2.2 –Release date: 11/Jul/16
HBase是对Bigtable的开源实现,所以先来认识一下Bigtabl概念,引用 Google’s BigTable Paper 中的精简描述:
A Bigtable is a sparse, distributed, persistent multidimensional sorted map.
The map is indexed by a row key, column key, and a timestamp; each value in the map is an uninterpreted array of bytes.
HBase的数据模型与此非常相似,用一张参考自上述论文的图来辅助理解:
图1 HBase表中某一行所存储数据的一种可视化呈现
HBase的结构:
Google论文中Bigtable描述为一个map,那么从Map的维度,用JSON格式,HBase的结构可以理解为:
{
// ...
"row1" : {
"family1" : {
"column1" : {
111 : "value1",
123 : "value2"
},
"column2" : {103 : "value3"}
},
"family2" : { ... }
},
"row2" : {
"family3" : { ... }
},
// ...
}
而关于其 稀疏 这一特性,可以用下图来辅助理解:
图2 HBase的行和列所构成的更像标签,而不是表格
对于我们熟悉的关系型数据库,如MySQL,一张表中每一行都有相同的列,即使部分行的某些列不存储数据,也有消耗,如图中的NULL。而HBase,各行是相对独立的,可以有完全不同的列。
如果最初阶段你需要HBase环境的主要目的是想熟悉对HBase的CRDU操作,那么看完 独立部署 后,可以直接跳到 三.基本操作 。
如果希望在部署环境过程中对HBase的架构也做一个简要了解,那么建议进行 伪分布式部署 ;如果伪分布式部署你能够很快完成,那么相信完全的分布式部署对你来说也并不困难,并且本文的主要目的是快速入门,因此不提供完全分布式部署的过程指引,如有需要,请参考官方指南 quickstart_fully_distributed 。
注:1.0.0版本开始,HBase内部组件(HMaster,HRegionServer)的默认端口从60xxx变更为16xxx
如果想要最快速的搭建供你练习HBase数据库操作的环境,那么这可能是你想要的。
独立部署模式下,HBase的所有进程都运行在一个JVM中,数据直接存储在本地磁盘。
a. 下载安装包并解压
wget https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/1.2.2/hbase-1.2.2-bin.tar.gz
tar zxvf hbase-1.2.2-bin.tar.gz -C target-dir
b. 配置
<configuration>
<property>
<name>hbase.rootdir</name>
<value>file:///home/hbase/hbase1.2.2</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/home/hbase/hbase1.2.2/zookeeper</value>
</property>
</configuration>
c. 启动和停止
可以直接在HBase安装目录运行 bin/start-hbase.sh 启动:
[hbase@iZ25n0dx8rxZh base]$ ./bin/start-hbase.sh
starting master, logging to /usr/local/hbase/bin/../logs/hbase-hbase-master-iZ25n0dx8rxZ.out
启动日志默认位于 ./logs/hbase-[username]-master-[yourhostname].log ,启动成功后,用 jps 命令可以看到名为HMaster的进程。接下来,你就可以使用hbase的shell来进行操作练习了。
要停止hbase,使用 bin/stop-hbase.sh 。
d. UI访问
Hbase内建了一个用Jetty提供服务的web UI页面来查看该HBase环境的各种信息,默认端口16010,尝试用 http://hostip:16010/ 来访问。
伪分布式模式下,HBase的所有组件还是运行在同一台主机,不同的是,每个组件独立运行在不同的JVM。更重要的是,我们可以在该模式下启动多个Regionserver和master,构成一个虚拟的分布式架构以供学习,这是很多 快速入门 文章所略过的重点。
该模式下,可以对接HDFS,但那涉及hadoop的部署,为以更短的时间达到当前阶段的目的,本文仍存储在本地磁盘。
a. HBase架构概要
图3 HBase架构概要图
作为入门阶段,先从粗粒度对HBase的架构进行简单了解:
HMaster:主要负责监控集群、管理RegionServers的负责均衡等,可以用主-备形式部署多个Master。
HRegionServers:负责响应用户的I/O操作请求,客户端对HBase读写数据是与RegionServer交互。
Zookeeper:负责选举Master的主节点;服务注册;保存RegionServers的状态等。可以使用系统内建的zookeeper,也可以使用独立的zookeeper,只需要在配置文件中调整即可。
HDFS:真正的数据持久层,并非必须是HDFS文件系统,但搭配HDFS是最佳选择,也是目前应用最广泛的选择。
b. 开始部署
伪分布式模式下,需要保证 ssh localhost 能够成功连接(将HBase所属用户的publickey追加到其自身的authorized_keys中)。如果你跟随本文启动了独立模式的HBase,先将其停止。
开启分布式配置
最基本的伪分布式配置,只需要在独立模式的配置基础上,追加开启分布式模式的配置,即将 hbase.cluster.distributed 配置为true,例如:
<configuration>
<property>
<name>hbase.rootdir</name>
<value>/home/hbase/hbase1.2.2</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>file:///home/hbase/hbase1.2.2/zookeeper</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
</configuration>
在安装目录运行 bin/start-hbase.sh
[hbase@iZ25n0dx8rxZ hbase]$ ./bin/start-hbase.sh
localhost: starting zookeeper, logging to /usr/local/hbase/bin/../logs/hbase-hbase-zookeeper-iZ25n0dx8rxZ.out
starting master, logging to /usr/local/hbase/bin/../logs/hbase-hbase-master-iZ25n0dx8rxZ.out
starting regionserver, logging to /usr/local/hbase/bin/../logs/hbase-hbase-1-regionserver-iZ25n0dx8rxZ.out
可以看到依次启动了zookeeper、master和regionserver,启动日志为 ./logs 路径下的 .log 文件。
查看启动的进程以及占用的端口:
[hbase@iZ25n0dx8rxZ logs]$ jps
4610 HRegionServer
4456 HQuorumPeer
5338 Jps
4522 HMaster
[hbase@iZ25n0dx8rxZ logs]$ netstat -lnp|grep 4522
tcp 0 0 172.16.5.23:16000 0.0.0.0:* LISTEN 4522/java
tcp 0 0 0.0.0.0:16010 0.0.0.0:* LISTEN 4522/java
[hbase@iZ25n0dx8rxZ logs]$ netstat -lnp|grep 4610
tcp 0 0 172.16.5.23:16201 0.0.0.0:* LISTEN 4610/java
tcp 0 0 0.0.0.0:16301 0.0.0.0:* LISTEN 4610/java
[root@iZ25n0dx8rxZ logs]$ netstat -lnp|grep 4456
tcp 0 0 0.0.0.0:2188 0.0.0.0:* LISTEN 4456/java
[hbase@iZ25n0dx8rxZ hbase]# ./bin/local-master-backup.sh start 1
starting master, logging to /usr/local/hbase/bin/../logs/hbase-hbase-1-master-iZ25n0dx8rxZ.out
启动成功后, jps 命令可以看到总共有两个HMaster进程。
日志:启动日志在 ./logs/hbase-[username]-n-master-[hostname].log ,在上例的日志中,可以看到这样一行日志说明该节点目前是作为备用节点:
master.ActiveMasterManager: Another master is the active master, iz25n0dx8rxz,16000,1469262015657; waiting to become the next active master
主节点切换:要观察HBase的Master组件主节点切换,可以使用 kill -9 PID 停止当前主节点 (即最初启动的HMaster) ,此时刚启动的备份节点将切换为主节点,可以在备份节点的日志 (./logs/hbase-[username]-1-master-[hostname].log) 中看到如下内容:
INFO [iZ25n0dx8rxZ:16001.activeMasterManager] master.ActiveMasterManager: Deleting ZNode for /hbase/backup-masters/iz25n0dx8rxz,16001,1469267021567 from backup master directory
INFO [iZ25n0dx8rxZ:16001.activeMasterManager] master.ActiveMasterManager: Registered Active Master=iz25n0dx8rxz,16001,1469267021567
停止:使用 ./bin/local-master-backup.sh stop n 来停止你的备份节点。
本节介绍使用HBase shell在直接在服务器上对HBase进行基本操作,HBase shell是在(J)Ruby的IRB的基础上增加了HBase特有的命令,遵循IRB的操作。
连接: ./bin/hbase shell
[hbase@iZ25n0dx8rxZ hbase]$ ./bin/hbase shell
HBase Shell; enter 'help<RETURN>' for list of supported commands.
Type "exit<RETURN>" to leave the HBase Shell
Version 1.2.2, r3f671c1ead70d249ea4598f1bbcc5151322b3a13, Fri Jul 1 08:28:55 CDT 2016
hbase(main):001:0>
建表: create ‘test’, ‘cf1’, ‘cf2’ ,即[create ‘表名’, ‘列族名’,..],列族名可以有多个, list 用于查看有哪些表
hbase(main):008:0> create 'test','cf1','cf2'
0 row(s) in 1.2280 seconds
=> Hbase::Table - test
hbase(main):009:0>
写数据: put ‘test’, ‘row1’, ‘cf1:c1’, ‘value1’ ,即[put ‘表名’,’行键’,’列族名:列名’,’数据’]
hbase(main):001:0> put 'test','row1','cf1:c1','value1'
0 row(s) in 0.3160 seconds
hbase(main):002:0> put 'test','row1','cf1:c1','value2'
0 row(s) in 0.3020 seconds
查看数据:
hbase(main):001:0> scan 'test'
ROW COLUMN+CELL
row1 column=cf1:c1, timestamp=1469277197280, value=value2
1 row(s) in 0.2710 seconds
hbase(main):002:0>
可以看到在put时指定的属性之外,有一个 timestamp 属性来作为版本标识,我们查看全表数据时,row1的cf1:c1列中展示的值是我们后一次写入的value2,sacn和get在不指定版本时,得到的是最近版本的数据
hbase(main):005:0> get 'test','row1',{COLUMN=>'cf1:c1',TIMESTAMP=>1469277197280}
COLUMN CELL
cf1:c1 timestamp=1469277197280, value=value1
1 row(s) in 0.0270 seconds
hbase(main):006:0>
版本数量:每个列族有一个单独的VERSIONS属性,默认为1,可以在建表时指定: create 'test1',{NAME=>'cf1',VERSIONS=>3}
,代表该列族的每个列最多保存最近3个版本的数据,也可以通过 alter 来更新: alter 'test1',NAME=>'cf1',VERSIONS=>3
。查询数据时,可以通过设置VERSIONS来指定显示最近几个版本的数据 (最大范围不超过该列族的VERSIONS属性值) : get 'test','row1',{COLUMN=>'cf1:c1',VERSIONS=>2}
本文简要介绍了HBase的数据模型、快速搭建基本操作环境的步骤以及基于HBase shell的HBase数据库基本操作,旨在协助想要学习HBase的朋友快速进入到对HBase的操作和使用阶段,消除陌生感和距离感。在这之后,我们可能想问,真正应用在工程上的操作HBase的方式有哪些,HBase存取数据的完整过程是怎样的,怎样去设计一个适合的表结构,等等,那么,请带着这些问题继续你的HBase之路。
Apache HBase ™ Reference Guide
Google’s BigTable Paper
Understanding HBase and BigTable