HBase 基本入门篇

无论是 NoSQL,还是大数据领域,HBase 都是非常"炙热"的一门数据库。本文将对 HBase 做一些基础性的介绍,旨在入门。

一、简介

HBase 是一个开源的、面向列的非关系型分布式数据库,目前是Hadoop体系中非常关键的一部分。在最初,HBase是基于谷歌的 BigTable 原型实现的,许多技术来自于Fay Chang在2006年所撰写的Google论文"BigTable"。与 BigTable基于Google文件系统(File System)一样,HBase则是基于HDFS(Hadoop的分布式文件系统)之上而开发的。

HBase 采用 Java 语言实现,在其内部实现了BigTable论文提到的一些压缩算法、内存操作和布隆过滤器等,这些能力使得HBase 在海量数据存储、高性能读写场景中得到了大量应用,如 Facebook 在 2010年11 月开始便一直选用 HBase来作为消息平台的存储层技术。HBase 以 Apache License Version 2.0开源,这是一种对商业应用友好的协议,同时该项目当前也是Apache软件基金会的顶级项目之一。

有什么特性

  • 基于列式存储模型,对于数据实现了高度压缩,节省存储成本
  • 采用 LSM 机制而不是B(+)树,这使得HBase非常适合海量数据实时写入的场景
  • 高可靠,一个数据会包含多个副本(默认是3副本),这得益于HDFS的复制能力,由RegionServer提供自动故障转移的功能
  • 高扩展,支持分片扩展能力(基于Region),可实现自动、数据均衡
  • 强一致性读写,数据的读写都针对主Region上进行,属于CP型的系统
  • 易操作,HBase提供了Java API、RestAPI/Thrift API等接口
  • 查询优化,采用Block Cache 和 布隆过滤器来支持海量数据的快速查找

与RDBMS的区别

对于传统 RDBMS 来说,支持 ACID 事务是数据库的基本能力,而 HBase 则使用行级锁来保证写操作的原子性,但是不支持多行写操作的事务性,这主要是从灵活性和扩展性上做出的权衡。

ACID 要素包含 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability)

总体来说, HBase 与传统关系数据库的区别,如下表所示:

特性

HBase

RDBMS

硬件架构

类似于 Hadoop 的分布式集群,硬件成本低廉

传统的多核系统,硬件成本昂贵

容错性

由软件架构实现,由于由多个节点组成,所以不担心一点或几点宕机

一般需要额外硬件设备实现 HA 机制

数据库大小

PB

GB、TB

数据排布方式

稀疏的、分布的多维的 Map

以行和列组织

数据类型

Bytes

丰富的数据类型

事物支持

ACID 只支持单个 Row 级别

全面的 ACID 支持,对 Row 和表

查询语言

只支持 Java API (除非与其他框架一起使用,如 Phoenix、Hive)

SQL

索引

只支持 Row-key,除非与其他技术一起应用,如 Phoenix、Hive

支持

吞吐量

百万查询/每秒

数千查询/每秒

二、数据模型

下面,我们以关系型数据库的一个数据表来演示 HBase 的不同之处。

先来看下面这张表:

ID

设备名

状态

时间戳

1

空调

打开

20190712 10:05:01

2

电视机

关闭

20190712 10:05:08

这里记录的是一些家庭设备上报的状态数据(DeviceState),其中包括设备名、状态、时间戳这些字段。

在 HBase 中,数据是按照列族(Column Family,简称CF)来存储的,也就是说对于不同的列会被分开存储到不同的文件。那么对于上面的状态数据表来说,在HBase中会被存储为两份:

列族1. 设备名

Row-Key

CF:Column-Key

Timestamp

Cell Value

1

DeviceState:设备名

20190712 10:05:01

空调

2

DeviceState:设备名

20190712 10:05:08

电视机

列族2. 状态

Row-Key

CF:Column-Key

Timestamp

Cell Value

1

DeviceState:状态

20190712 10:05:01

打开

2

DeviceState:状态

20190712 10:05:08

关闭

这里Row-key是唯一定位数据行的ID字段,而Row-key 加上 CF、Column-Key,再加上一个时间戳才可以定位到一个单元格数据。其中时间戳用来表示数据行的版本, 在HBase中默认会有 3 个时间戳的版本数据,这意味着对同一条数据(同一个Rowkey关联的数据)进行写入时,最多可以保存3个版本。

在查询某一行的数据时,HBase需要同时从两个列族(文件)中进行查找,最终将结果合并后返回给客户端。 由此可见如果列族太多,则会影响读取的性能,在设计时就需要做一些权衡。

由此可见,HBase的使用方式与关系型数据库是大不相同的,在使用 HBase 时需要抛弃许多关系型数据库的思维及做法,比如强类型、二级索引、表连接、触发器等等。

然而 HBase 的灵活性及高度可伸缩性却是传统 RDBMS 无法比拟的。

三、安装HBase

单机环境安装

1. 准备JDK环境

确保环境上JDK已经装好,可执行java -version确认:

host:/home/hbase # java -version
openjdk version "1.8.0_201"
OpenJDKRuntimeEnvironment(build 1.8.0_201-Huawei_JDK_V100R001C00SPC060B003-b10)
OpenJDK64-BitServer VM (build 25.201-b10, mixed mode)

2. 下载软件

官网的下载地址页面:

http://archive.apache.org/dist/hbase/

选择合适的版本,比如1.4.10。 下载后解压:

wget http://archive.apache.org/dist/hbase/2.1.5/hbase-2.1.5-bin.tar.gz
tar -xzvf hbase-2.1.5-bin.tar.gz
mkdir -p /opt/local
mv hbase-2.1.5/opt/local/hbase

配置HBase执行命令路径:

export HBASE_HOME=/opt/local/hbase
export PATH=$PATH:$HBASE_HOME/bin

3. 配置软件

vim conf/hbase-env.sh

#JDK安装目录
export JAVA_HOME=/usr/local/jre1.8.0_201
#配置hbase自己管理zookeeper
export HBASE_MANAGES_ZK=true

vim conf/hbase-site.xml

<configuration>

<!-- zookeeper端口  -->
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2182</value>                                                                                                                                           
</property>

<!--  HBase 数据存储目录 -->
<property>
<name>hbase.rootdir</name>
<value>file:///opt/local/hbase/data</value>
</property>

<!-- 用于指定 ZooKeeper 数据存储目录 -->
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/opt/local/hbase/data/zookeeper</value>
</property>

<!-- 用于指定临时数据存储目录 -->
<property>
<name>hbase.tmp.dir</name>
<value>/opt/local/hbase/temp/hbase-${user.name}</value>
</property>
</configuration>

其中 hbase.rootdir 和 hbase.zookeeper.property.dataDir 都用来指定数据存放的目录,默认情况下hbase会使用/tmp目录,这显然是不合适的。配置了这两个路径之后,hbase会自动创建相应的目录。

关于更多的参数设定可参考这里

4. 启动软件

start-hbase.sh

此时查看 logs/hbase-root-master-host-xxx.log,如下:

2019-07-1107:37:23,654 INFO  [localhost:33539.activeMasterManager] hbase.MetaMigrationConvertingToPB: hbase:meta doesn't have any entries to update.
2019-07-11 07:37:23,654 INFO  [localhost:33539.activeMasterManager] hbase.MetaMigrationConvertingToPB: META already up-to date with PB serialization
2019-07-11 07:37:23,664 INFO  [localhost:33539.activeMasterManager] master.AssignmentManager: Clean cluster startup. Assigning user regions
2019-07-11 07:37:23,665 INFO  [localhost:33539.activeMasterManager] master.AssignmentManager: Joined the cluster in 11ms, failover=false
2019-07-11 07:37:23,672 INFO  [localhost:33539.activeMasterManager] master.TableNamespaceManager: Namespace table not found. Creating...

检查进程情况,发现进程已经启动

ps -ef |grep hadoop
root     1104911032207:37 pts/100:00:20/usr/local/jre1.8.0_201/bin/java -Dproc_master-XX:OnOutOfMemoryError=kill -9%p -XX:+UseConcMarkSweepGC-XX:PermSize=128m-XX:MaxPermSize=128m-XX:ReservedCodeCacheSize=256m-Dhbase.log.dir=/opt/local/hbase/logs -Dhbase.log.file=hbase-root-master-host-192-168-138-148.log-Dhbase.home.dir=/opt/local/hbase -Dhbase.id.str=root -Dhbase.root.logger=INFO,RFA -Dhbase.security.logger=INFO,RFAS org.apache.hadoop.hbase.master.HMaster start
root     1890730747007:50 pts/100:00:00 grep --color=auto hadoop

通过JPS(JDK自带的检查工具) 可以看到当前启动的Java进程:

# jps
5701Jps
4826HMaster
1311 jar

查看 data目录,发现生成了对应的文件:

host:/opt/local/hbase/data # ls -lh .
total 36K
drwx------. 4 root root 4.0KJul1108:08 data
drwx------. 4 root root 4.0KJul1108:08 hbase
-rw-r--r--. 1 root root   42Jul1108:08 hbase.id
-rw-r--r--. 1 root root    7Jul1108:08 hbase.version
drwx------. 2 root root 4.0KJul1108:08MasterProcWALs
drwx------. 2 root root 4.0KJul1108:08 oldWALs
drwx------. 3 root root 4.0KJul1108:08.tmp
drwx------. 3 root root 4.0KJul1108:08WALs
drwx------. 3 root root 4.0KJul1108:08 zookeeper

关于运行模式

HBase启动时默认会使用单机模式,此时 Zookeeper和 HMaster/RegionServer 会运行在同一个JVM中。以standalone模式启动的HBase会包含一个HMaster、RegionServer、Zookeeper实例,此时 HBase 会直接使用本地文件系统而不是HDFS。

通过将 conf/hbase-site.xml中的 hbase.cluster.distributed 配置为true,就是集群模式了。在这个模式下,你可以使用分布式环境进行部署,或者是"伪分布式"的多进程环境。

<configuration>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
</configuration>

需要注意的是,如果以standalone启动的话,HMaster、RegionServer端口都是随机的,无法通过配置文件指定。

四、基本使用

打开HBase Shell

hbase shell

执行status命令

Version2.1.5, r76ab087819fe82ccf6f531096e18ad1bed079651, WedJun516:48:11 PDT 2019

hbase(main):001:0> status
1 active master, 0 backup masters, 1 servers, 0 dead, 2.0000 average load

这表示有一个Master在运行,一个RegionServer,每个RegionServer包含2个Region。

表操作

  • 创建DeviceState表
hbase(main):002:0> create "DeviceState", "name:c1", "state:c2"

=> Hbase::Table- DeviceState

此时,已经创建了一个DeviceState表,包含name(设备名称)、state(状态)两个列。

查看表信息

hbase(main):003:0> list
TABLE
DeviceState
1 row(s) in0.0090 seconds

=> ["DeviceState"]

hbase(main):003:0> describe "DeviceState"
TableDeviceStateis ENABLED
DeviceState
COLUMN FAMILIES DESCRIPTION
{NAME => 'name', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSIO
N => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
{NAME => 'state', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSI
ON => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
2 row(s) in0.0870 seconds
  • 写入数据

通过下面的命令,向DeviceState写入两条记录。

由于有两个列族,因此需要写入四个单元格数据:

put "DeviceState", "row1", "name", "空调"
put "DeviceState", "row1", "state", "打开"
put "DeviceState", "row2", "name", "电视机"
put "DeviceState", "row2", "state", "关闭"
  • 查询数据

查询某行、某列

hbase(main):012:0> get"DeviceState","row1"
COLUMN                                      CELL
 name:                                      timestamp=1562834473008, value=\xE7\x94\xB5\xE8\xA7\x86\xE6\x9C\xBA
 state:                                     timestamp=1562834474630, value=\xE5\x85\xB3\xE9\x97\xAD
1 row(s) in0.0230 seconds

hbase(main):013:0> get"DeviceState","row1", "name"
COLUMN                                      CELL
 name:                                      timestamp=1562834473008, value=\xE7\x94\xB5\xE8\xA7\x86\xE6\x9C\xBA
1 row(s) in0.0200 seconds

扫描表

hbase(main):026:0> scan "DeviceState"
ROW                                         COLUMN+CELL
 row1                                       column=name:, timestamp=1562834999374, value=\xE7\xA9\xBA\xE8\xB0\x83
 row1                                       column=state:, timestamp=1562834999421, value=\xE6\x89\x93\xE5\xBC\x80
 row2                                       column=name:, timestamp=1562834999452, value=\xE7\x94\xB5\xE8\xA7\x86\xE6\x9C\xBA
 row2                                       column=state:, timestamp=1562835001064, value=\xE5\x85\xB3\xE9\x97\xAD
2 row(s) in0.0250 seconds

查询数量

hbase(main):014:0> count "DeviceState"
2 row(s) in0.0370 seconds

=> 1
  • 清除数据

删除某列、某行

delete"DeviceState", "row1", "name"
0 row(s) in0.0080 seconds

hbase(main):003:0> deleteall "DeviceState", "row2"
0 row(s) in0.1290 seconds

清空整个表数据

hbase(main):021:0> truncate "DeviceState"
Truncating'DeviceState' table (it may take a while):
- Disabling table...
- Truncating table...
0 row(s) in3.5060 seconds

删除表(需要先disable)

hbase(main):006:0> disable "DeviceState"
0 row(s) in2.2690 seconds

hbase(main):007:0> drop "DeviceState"
0 row(s) in1.2880 seconds

五、FAQ

  • A. 启动时提示 ZK 端口监听失败: Could not start ZK at requested port of 2181. ZK was started at port: 2182. Aborting as clients (e.g. shell) will not be able to find this ZK quorum

原因

HBase需要启动Zookeeper,而本地的2181端口已经被启用(可能有其他Zookeeper实例)

解决办法

conf/hbase-site.xml中修改hbase.zookeeper.property.clientPort的值,将其修改为2182,:

<configuration>
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2182</value>                                                                                                                                           
</property>
</configuration>
  • B. 启动HBase Shell 时提示 java.lang.UnsatisfiedLinkError

原因

在执行hbase shell期间,JRuby会在“java.io.tmpdir”路径下创建一个临时文件,该路径的默认值为“/tmp”。如果为“/tmp”目录设置NOEXEC权限,然后hbase shell会启动失败并抛出“java.lang.UnsatisfiedLinkError”错误。

解决办法

  1. 取消/tmp的noexec权限(不推荐)
  2. 设置java.io.tmpdir变量,指向可用的路径,编辑conf/hbase-env.sh文件:
export HBASE_TMP_DIR=/opt/local/hbase/temp
export HBASE_OPTS="-XX:+UseConcMarkSweepGC -Djava.io.tmpdir=$HBASE_TMP_DIR"

参考文档

HBase 官方权威指南 https://hbase.apache.org/book.html#quickstart

HBase 单机模式搭建 https://my.oschina.net/jackieyeah/blog/712019

HBase 深入浅出 较详细介绍了HBase的由来以及特性,文中提供了HBase集群、存储机制的一些简介,非常适合入门阅读 https://www.ibm.com/developerworks/cn/analytics/library/ba-cn-bigdata-hbase/index.html

本文分享自微信公众号 - 美码师(gracebuilding)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏无道编程

一个基于Node.js的小爬虫

9440
来自专栏前端资源

Linux下如何重置MySQL密码

linux mysql access denied for user ‘root’@’localhost'(using password:YES)

14720
来自专栏前端资源

MongoDB的简单配置和基本数据操作

1.下载安装mongodb,根据您的系统选择相应的版本,链接:https://www.mongodb.com/download-center#community

8330
来自专栏Java架构沉思录

详解 Redis 内存管理机制和实现

Redis是一个基于内存的键值数据库,其内存管理是非常重要的。本文内存管理的内容包括:过期键的懒性删除和过期删除以及内存溢出控制策略。

8610
来自专栏Java架构沉思录

基于Docker实现MYSQL主从复制

注意 server-id必须是一个唯一的数字,必须主从不一致, 且主从库必须设置项。

6920
来自专栏无道编程

jdbc连接sql server 2017(mssql)

地址:https://www.microsoft.com/zh-CN/download/details.aspx?id=57175

14020
来自专栏sktj

mysql 半同步复制

转载:https://www.cnblogs.com/zero-gg/p/9057092.html

13130
来自专栏志学Python

带你认识 flask 错误处理

在Flask应用中爆发错误时会发生什么?得到答案的最好的方法就是亲身体验一下。启动应用,并确保至少有两个用户注册,以其中一个用户身份登录,打开个人主页并单击“编...

6630
来自专栏sktj

mysql MHA高可用方案

1、1主1从,两台间建立主从。另外有一台额外的,安装MHA管理端 2、从库my.cnf配置 relay_log_purge=0 log_bin=/xx/x...

8430
来自专栏sktj

mysql 读写分离altas

1、altas2.2.1,只能安装在64位系统上 2、1台管理机,2台DB,1主1从。配置主从同步 3、主从配置管理机登录账号 GRANT ALL ON ...

8930

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励