菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
97
0

HBase 基本入门篇

原创
05/13 14:22
阅读数 419

无论是 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 与传统关系数据库的区别,如下表所示:

特性HBaseRDBMS
硬件架构类似于 Hadoop 的分布式集群,硬件成本低廉传统的多核系统,硬件成本昂贵
容错性由软件架构实现,由于由多个节点组成,所以不担心一点或几点宕机一般需要额外硬件设备实现 HA 机制
数据库大小PBGB、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-KeyCF:Column-KeyTimestampCell Value
1DeviceState:设备名20190712 10:05:01空调
2DeviceState:设备名20190712 10:05:08电视机

列族2. 状态

Row-KeyCF:Column-KeyTimestampCell Value
1DeviceState:状态20190712 10:05:01打开
2DeviceState:状态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 -versionopenjdk 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.gztar -xzvf hbase-2.1.5-bin.tar.gzmkdir -p /opt/localmv hbase-2.1.5/opt/local/hbase

配置HBase执行命令路径:

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

3. 配置软件

vim conf/hbase-env.sh

#JDK安装目录export JAVA_HOME=/usr/local/jre1.8.0_201#配置hbase自己管理zookeeperexport 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 serialization2019-07-11 07:37:23,664 INFO  [localhost:33539.activeMasterManager] master.AssignmentManager: Clean cluster startup. Assigning user regions2019-07-11 07:37:23,665 INFO  [localhost:33539.activeMasterManager] master.AssignmentManager: Joined the cluster in 11ms, failover=false2019-07-11 07:37:23,672 INFO  [localhost:33539.activeMasterManager] master.TableNamespaceManager: Namespace table not found. Creating...

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

ps -ef |grep hadooproot     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 startroot     1890730747007:50 pts/100:00:00 grep --color=auto hadoop

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

# jps5701Jps4826HMaster1311 jar

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

host:/opt/local/hbase/data # ls -lh .total 36Kdrwx------. 4 root root 4.0KJul1108:08 datadrwx------. 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.versiondrwx------. 2 root root 4.0KJul1108:08MasterProcWALsdrwx------. 2 root root 4.0KJul1108:08 oldWALsdrwx------. 3 root root 4.0KJul1108:08.tmpdrwx------. 3 root root 4.0KJul1108:08WALsdrwx------. 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> status1 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> listTABLEDeviceState1 row(s) in0.0090 seconds
=> ["DeviceState"]
hbase(main):003:0> describe "DeviceState"TableDeviceStateis ENABLEDDeviceStateCOLUMN FAMILIES DESCRIPTION{NAME => 'name', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => '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', COMPRESSION => '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\xAD1 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\xBA1 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\xAD2 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/tempexport HBASE_OPTS="-XX:+UseConcMarkSweepGC -Djava.io.tmpdir=$HBASE_TMP_DIR"

本文公众号来源:美码师
作者:美码师

本文已收录至我的GitHub

发表评论

0/200
97 点赞
0 评论
收藏
为你推荐 换一批