Hbase

1. 介绍

  HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建大规模结构化的存储集群。HBase的目标是存储并处理大型数据,具体来说是仅需使用普通的硬件配置,就能够处理由成千上万的行和列所组成的大型数据。

  HBase是建立在Hadoop文件系统之上的分布式面向列的数据库。它是一个开源项目,是横向扩展的。HBase是一个数据模型,类似于谷歌的大表设计,可以提供快速随机访问海量结构化数据。它利用了Hadoop的文件系统(HDFS)提供的容错能力。它是Hadoop的生态系统,提供对数据的随机实时读/写访问,是Hadoop文件系统的一部分。

人们可以直接或通过HBase的存储HDFS数据。使用HBase在HDFS读取消费/随机访问数据。 HBase在Hadoop的文件系统之上,并提供了读写访问。

hbase

HBase 和 HDFS

HDFS HBase
HDFS是适于存储大容量文件的分布式文件系统。 HBase是建立在HDFS之上的数据库。
HDFS不支持快速单独记录查找。 HBase提供在较大的表快速查找
它提供了高延迟批量处理;没有批处理概念。 它提供了数十亿条记录低延迟访问单个行记录(随机存取)。
它提供的数据只能顺序访问。 HBase内部使用哈希表和提供随机接入,并且其存储索引,可将在HDFS文件中的数据进行快速查找。

1.1 存储机制

  HBase是一个面向列的数据库,在表中它由行排序。表模式定义只能列族,也就是键值对。一个表有多个列族以及每一个列族可以有任意数量的列。后续列的值连续地存储在磁盘上。表中的每个单元格值都具有时间戳。总之,在一个HBase:

  • 表是行的集合。
  • 行是列族的集合。
  • 列族是列的集合。
  • 列是键值对的集合。

下面给出的表中是HBase模式的一个例子。

hbase

1.2 HBase 和 RDBMS

HBase RDBMS
HBase无模式,不具有固定列模式的概念;仅定义列族。 RDBMS有它的模式,描述表的整体结构的约束。
它专门创建为宽表。 HBase是横向扩展。 这些都是细而专为小表。很难形成规模。
没有任何事务存在于HBase。 RDBMS是事务性的。
它反规范化的数据。 它具有规范化的数据。
它用于半结构以及结构化数据是非常好的。 用于结构化数据非常好。

1.3 HBase架构

  在HBase中,表被分割成区域,并由区域服务器提供服务。区域被列族垂直分为“Stores”。Stores被保存在HDFS文件。下面显示的是HBase的结构。

**注意:**术语“store”是用于区域来解释存储结构。

hbase

HBase有三个主要组成部分:客户端库,主服务器和区域服务器。区域服务器可以按要求添加或删除。

主服务器

  • 分配区域给区域服务器并在Apache ZooKeeper的帮助下完成这个任务。
  • 处理跨区域的服务器区域的负载均衡。它卸载繁忙的服务器和转移区域较少占用的服务器。
  • 通过判定负载均衡以维护集群的状态。
  • 负责模式变化和其他元数据操作,如创建表和列。

区域

  • 区域只不过是表被拆分,并分布在区域服务器。

区域服务器

  • 与客户端进行通信并处理数据相关的操作。
  • 句柄读写的所有地区的请求。
  • 由以下的区域大小的阈值决定的区域的大小。

1.4 体系结构

  HBase的服务器体系结构遵从简单的主从服务器架构,它由HRegion Server群和HBase Master服务器构成。HBase Master负责管理所有的HRegion Server,而HBase中的所有RegionServer都是通过ZooKeeper来协调,并处理HBase服务器运行期间可能遇到的错误。HBase Master Server本身并不存储HBase中的任何数据,HBase逻辑上的表可能会被划分成多个Region,然后存储到HRegion Server群中。HBase Master Server中存储的是从数据到HRegion Server的映射。

  • Client

HBase Client使用HBase的RPC机制与HMaster和HRegion Server进行通信,对于管理类操作,Client与HMaster进行RPC;对于数据读写类操作,Client与HRegionServer进行RPC。

  • Zookeeper

Zookeeper Quorum中除了存储了-ROOT-表的地址和HMaster的地址,HRegionServer会把自己以Ephemeral方式注册到Zookeeper中,使得HMaster可以随时感知到各个HRegionServer的健康状态。此外,Zookeeper也避免了HMaster的单点问题。

  • HMaster

每台HRegionServer都会与HMaster进行通信,HMaster的主要任务就是要告诉每台HRegion Server它要维护哪些HRegion。 当一台新的HRegionServer登录到HMaster时,HMaster会告诉它等待分配数据。而当一台HRegion死机时,HMaster会把它负责的HRegion标记为未分配,然后再把它们分配到其他的HRegion Server中。 HBase已经解决了HMaster单点故障问题(SPFO),并且HBase中可以启动多个HMaster,那么它就能够通过Zookeeper来保证系统中总有一个Master在运行。HMaster在功能上主要负责Table和Region的管理工作,具体包括:

  • 管理用户对Table的增删改查操作
  • 管理HRegionServer的负载均衡,调整Region分布
  • 在Region Split后,负责新Region的分配
  • 在HRegionServer停机后,负责失效HRegionServer上的Region迁移

  • HRegion

当表的大小超过设置值得时候,HBase会自动地将表划分为不同的区域,每个区域包含所有行的一个子集。对用户来说,每个表是一堆数据的集合,靠主键来区分。从物理上来说,一张表被拆分成了多块,每一块就是一个HRegion。我们用表名+开始/结束主键来区分每一个HRegion,一个HRegion会保存一个表里面某段连续的数据,从开始主键到结束主键,一张完整的表格是保存在多个HRegion上面。

上图表示当Table随着记录数不断增加而变大后,会逐渐分裂成多份splits,成为regions,一个region由[startkey, endkey]表示,不同的region会被Master分配给响应的RegionServer进行管理。

  • HRegionServer

所有的数据库数据一般都是保存在Hadoop分布式文件系统上面的,用户通过一系列HRegion服务器获取这些数据,一台机器上面一般只运行一个HRegionServer,且每一个区段的HRegion也只会被一个HRegion服务器维护。如下图所示HRegion Server数据存储关系图。

HRegion Server主要负责响应用户的IO请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region,HRegion中由多个HStore组成。每个HStore对应了Table中的一个Column Family的存储,可以看出每个ColumnFamily其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。 HStore存储时HBas存储的核心了,其中由两部分组成,一部分是MemStore,一部分是StoreFiles。MemStore是Sorted Memory Buffer,用户写入数据首先会放入MemStore,当MemStore满了以后会flush成一个StoreFile(底层是HFile),当StoreFile文件数增长到一定阈值,会触发Compact合并操作,将多个StoreFile合并成一个StoreFile,合并过程中会进行版本合并和数据删除,因此可以看出HBase其实只有增加数据,所有的更新和删除操作都是后续的compact过程中进行的,这使得用户的写操作只要进入内存中就可以立刻返回,保证了HBase IO的高性能。当StoreFiles Compact后,会逐步形成越来越大的StoreFile,当单个StoreFile大小超过一定的阈值后,会触发Split操作,同时,会把当前的Region Split成2个Region,父Region会下线,新Split出的2个孩子Region会被HMaster分配到响应的HRegion Server上,使得原先1个Region的压力得以分流道2个Region上。

理解上述HStore的基本原理之后,必须了解一下HLog的功能,因为上述的HStore在系统正常工作的前提下是没有问题的,但是在分布式系统环境中,无法避免系统出错或者宕机,一次一旦HRegion Server意外退出,MemStore中的内存数据将会丢失,这就需要引入HLog了。每一个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中,HLog文件定期会滚动出新的,并删除旧的文件,当HRegionServer意外终止后,HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应Region的目录下,然后再将失效的Region重新分配,领取到这些Region的HRegionServer在LoadRegion过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。

  • HBase存储格式

HBase中的所有数据文件都存储在Hadoop HDFS文件系统上,包括上述提到的两种文件类型:

  • HFile HBase中的KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级的包装,即StoreFile底层就是HFile。
  • HLogFile,HBase中WAL(Write Ahead Log)的存储格式,物理上是Hadoop的Sequence File

  • ROOT表和META表

用户表的Regions元数据被存储在.META.表中,随着Region的增多,.META.表中的数据也会增大,并分裂成多个Regions。为了定位.META.表中各个Regions的位置,把.META.表中的所有Regions的元数据保存在-ROOT-表中,最后由Zookeeper记录-ROOT-表的位置信息。所有客户端访问用户数据前,需要首先访问Zookeeper获得-ROOT-的位置,然后方位-ROOT-表获得.META.表的位置,最后根据.META.表中的信息确定用户数据存放的位置,-ROOT-表永远不会被分割,它只有一个Region,这样可以保证最多需要三次跳转就可以定位任意一个Region。为了加快访问速度,.META.表的Regions全部保存在内存中,如果.META.表中的每一行在内存中占大约1KB,且每个Region限制为128M,下图中的三层结构可以保存Regions的数目为(128M/1KB)*(128/1KB)=2^34个。

2. 搭建

2.1 环境准备

序列号 IP地址 主机名 安装软件
1 192.168.186.10 master hbase
2 192.168.186.11 slave1 `hbase
3 192.168.186.12 slave2 hbase

仍然是这三台机器

2.2 安装jdk

  之前安装了,省略。

[root@master ~]# java -version
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)

[root@slave1 ~]# java -version
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)

[root@slave2 ~]# java -version
java version "1.8.0_172"
Java(TM) SE Runtime Environment (build 1.8.0_172-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.172-b11, mixed mode)

2.3 部署

[root@master ~]# cd /usr/local/src/
[root@master src]# rz -E
rz waiting to receive.
[root@master src]# tar xf hbase-1.3.1-bin.tar.gz

[root@master src]# mv hbase-1.3.1 /usr/local/
[root@master src]# cd /usr/local/
[root@master local]# ln -sf hbase-1.3.1 hbase

3.4 配置

  进入conf目录,复制zoo-sample.cfg重命名为zoo.cfg,通过修改zoo.cfg来对zookeeper进行配置。这个名字固定写死,因为zookeeper启动会检查这个文件,根据这个配置文件里的信息来启动服务。

[root@master local]# cd /usr/local/hbase/conf
[root@master conf]# vim hbase-site.xml 
[root@master conf]# cat  hbase-site.xml 
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!--
/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-->
<configuration>
    <property>
            <name>hbase.tmp.dir</name>
            <value>/var/hbase</value>
    </property>
    <property>
            <name>hbase.rootdir</name>
            <value>hdfs://master:9000/hbase</value>
    </property>
    <property>
            <name>hbase.cluster.distributed</name>
            <value>true</value>
    </property>
    <property>
            <name>hbase.zookeeper.quorum</name>
            <value>master,slave1,slave2</value>
    </property>
    <property>
            <name>hbase.zookeeper.property.dataDir</name>
            <value>/usr/local/src/hbase/zookeeper</value>
    </property>
    <property>
            <name>hbase.master.info.port</name>
            <value>60010</value>
    </property> 
    <property>
            <name>hbase.thrift.info.port</name>
            <value>9083</value>
    </property>
</configuration>
hbase默认配置文件生成的,文件源是 hbase-default.xml

[root@master conf]# egrep -v '#|^$' hbase-env.sh
export JAVA_HOME=/usr/local/jdk1.8.0_172
export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib
export HBASE_OPTS="-XX:+UseConcMarkSweepGC"
export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -XX:PermSize=128m -XX:MaxPermSize=128m"
export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER_OPTS -XX:PermSize=128m -XX:MaxPermSize=128m"
export HBASE_MANAGES_ZK=false

[root@master conf]# cat regionservers 
master
slave1
slave2

3.5 配置环境变量

[root@master conf]# tail -4 /etc/profile
export HBASE_HOME=/usr/local/hbase
export HBASE_CLASSPATH=$HBASE_HOME/conf
export HBASE_LOG_DIR=$HBASE_HOME/logs
export PATH=$PATH:$HBASE_HOME/bin
[root@master conf]# source /etc/profile

3.6 包分发和配置环境

[root@master ~]# rsync -az /usr/local/{hbase,hbase-1.3.1} slave1:/usr/local/
[root@master ~]# rsync -az /usr/local/{hbase,hbase-1.3.1} slave2:/usr/local/

[root@slave1 ~]# tail -4 /etc/profile
export HBASE_HOME=/usr/local//hbase
export HBASE_CLASSPATH=$HBASE_HOME/conf
export HBASE_LOG_DIR=$HBASE_HOME/logs
export PATH=$PATH:$HBASE_HOME/bin
[root@slave1 ~]# source /etc/profile

[root@slave2 ~]# tail -4 /etc/profile
export HBASE_HOME=/usr/local//hbase
export HBASE_CLASSPATH=$HBASE_HOME/conf
export HBASE_LOG_DIR=$HBASE_HOME/logs
export PATH=$PATH:$HBASE_HOME/bin
[root@slave2 ~]# source /etc/profile

3.7 启动

  在启动之前,我停止了storm和zookeeper。

[root@master sbin]# jps
16262 NameNode
16601 ResourceManager
16445 SecondaryNameNode
16877 Jps

[root@slave1 conf]# jps
25749 Jps
25260 DataNode
25374 NodeManager

[root@slave2 conf]# jps
14994 DataNode
15258 Jps
15099 NodeManager

[root@master local]# start-hbase.sh 
slave1: starting zookeeper, logging to /usr/local/hbase/bin/../logs/hbase-root-zookeeper-slave1.out
master: starting zookeeper, logging to /usr/local/hbase/bin/../logs/hbase-root-zookeeper-master.out
slave2: starting zookeeper, logging to /usr/local/hbase/bin/../logs/hbase-root-zookeeper-slave2.out
starting master, logging to /usr/local//hbase/logs/hbase-root-master-master.out
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
master: starting regionserver, logging to /usr/local/hbase/bin/../logs/hbase-root-regionserver-master.out
slave1: starting regionserver, logging to /usr/local/hbase/bin/../logs/hbase-root-regionserver-slave1.out
slave2: starting regionserver, logging to /usr/local/hbase/bin/../logs/hbase-root-regionserver-slave2.out
master: Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
master: Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
slave1: Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
slave1: Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
slave2: Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0
slave2: Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=128m; support was removed in 8.0
[root@master local]# jps
21699 NameNode
23941 HMaster
22039 ResourceManager
24073 HRegionServer
21882 SecondaryNameNode
23883 HQuorumPeer
24157 Jps

[root@slave1 local]# jps
29409 DataNode
29523 NodeManager
31591 HQuorumPeer
31931 Jps
31663 HRegionServer

[root@slave2 local]# jps
17186 HQuorumPeer
17491 Jps
16549 DataNode
17256 HRegionServer
16653 NodeManager
现象: HBASE HMaster起不来,报错如下:
[main] impl.MetricsSystemImpl: Source name ugi already exists!
[main] master.HMasterCommandLine: Master exiting

解决:
我百度一圈,各种尝试,最后竟然是hadoop的hdfs和hbase兼容问题,我升级版本后解决。

3.8 测试

[root@master local]# hbase shell
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/local/hbase-1.3.1/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
HBase Shell; enter 'help<RETURN>' for list of supported commands.
Type "exit<RETURN>" to leave the HBase Shell
Version 1.3.1, r930b9a55528fe45d8edce7af42fef2d35e77677a, Thu Apr  6 19:36:54 PDT 2017

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

hbase

  • 新建表

create 'cmz_music_table' ,'meta_data','action'
hbase(main):003:0> create 'cmz_music_table' ,'meta_data','action'
0 row(s) in 1.4330 seconds

=> Hbase::Table - cmz_music_table
hbase(main):004:0> list
TABLE                                                                                     
cmz_music_table                                                                           
1 row(s) in 0.0430 seconds

=> ["cmz_music_table"]

  • 查看表信息
describe 'cmz_music_table'

详细操作

hbase(main):008:0> describe 'cmz_music_table'
Table cmz_music_table is ENABLED                                                                                                                                                                     
cmz_music_table                                                                                                                                                                                      
COLUMN FAMILIES DESCRIPTION                                                                                                                                                                          
{NAME => 'action', 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 => 'meta_data', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSION
S => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}                                                                                                                      
2 row(s) in 0.0280 seconds