1. 概述

HBase是Apache下的一个顶级项目,是Hadoop Database的简写。虽然也是数据库,但它不同于传统的关系型数据库,也不同于很多NoSQL,它的诞生就是为了解决海量数据的存储查询.官方对于HBase项目的说明如下:

Use Apache HBase™ when you need random, realtime read/write access to your Big Data. This project's goal is the hosting of very large tables -- billions of rows X millions of columns -- atop clusters of commodity hardware. Apache HBase is an open-source, distributed, versioned, non-relational database modeled after Google's Bigtable: A Distributed Storage System for Structured Data by Chang et al. Just as Bigtable leverages the distributed data storage provided by the Google File System, Apache HBase provides Bigtable-like capabilities on top of Hadoop and HDFS.

概述就到此为止,细节内容我们后面介绍。

2. 安装

任何理论介绍都不如先实际使用一下来的实在,所以我们先介绍如何安装HBase。安装过程和之前的《Hadoop系列一——安装部署》类似,非常简单,步骤如下(安装环境为Linux,发行版选择自己熟悉的就行):

  1. 安装Java环境,推荐JDK 1.8+。
  2. 去官网https://hbase.apache.org下载最新稳定版HBase安装包(我安装的是1.2.6,后面也以此版本为例说明),注意要下载二进制的包,而不是源码包。二进制包名字里面带bin关键字,比如hbase-1.2.6-bin.tar.gz,源码包类似hbase-1.2.6-src.tar.gz这样。
  3. 解压下载的安装包到某个目录,假设解压后目录为/opt/hbase-1.2.6目录。为了使用方便,可以将/opt/hbase-1.2.6/bin目录加到PATH环境变量里面。

安装就完成了,理论上不需要进行任何其他配置就可以使用了。

在bin目录下有两个脚本,用于启停HBase:

  • start-hbase.sh:启动HBase;
  • stop-hbase.sh:停止HBase。

启动HBase之后,如果通过jps命令看到了HBase的进程HMaster,那么恭喜你,你的HBase已经安装并且启动成功了,你已经可以进行简单的使用了。我们输入hbase shell命令就可以通过shell命令行连接HBase:

➜  ~ hbase shell
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/hbase-1.2.6/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/hadoop-2.7.3/share/hadoop/common/lib/slf4j-log4j12-1.7.10.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.2.6, rUnknown, Mon May 29 02:25:32 CDT 2017

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

hbase(main):002:0>

连接到HBase后,我们可以输入status命令来查看HBase集群的状态(当然我们现在还不是集群)。虽然这样已经算安装好了,但要真正使用,还是要做一些简单的配置。HBase的配置在conf目录下,比较重要的有两个:

  • hbase-env.sh:这个里面主要有两个点比较重要:(1)JAVA_HOME:可以在这里指定你的java,特别是你使用非系统默认的java或者系统没有设置JAVA_HOME的时候该选项就非常重要了。(2)HBASE\_MANAGES\_ZK:HBase依赖于ZooKeeper,这个选项表示是否由HBase自己管理ZK,默认为True,表示HBase自己管理。换句话说,如果你单独部署了ZooKeeper,想让HBase使用你部署的这个,那就把该选项置为False,并在下面要介绍的配置文件里面配上你的ZK信息;否则的话置为True就行了,HBase自己内部会创建ZooKeeper供自己使用。
  • hbase-site.xml:这个文件是HBase的核心配置文件,极大多数配置都是配在该文件里面的,默认这个文件是空的。这里我们增加如下配置:

    <configuration>
        <property>
            <name>hbase.rootdir</name>
            <value>/your/path/data</value>
        </property>
        <property>
            <name>hbase.zookeeper.property.dataDir</name>
            <value>/your/path/zookeeper</value>
        </property>
    </configuration>

这里我们配置了HBase和ZooKeeper的数据存储路径,默认是存储在/tmp目录下的,我们知道OS重启后,/tmp目录就会被清空,也就是我们的数据会丢失,所以我们需要配置一下数据存储目录。

至此,HBase的安装...还没有完...(^_^)。从前面的介绍中我们知道HBase是分布式的,但刚才的部署过程完全是单机的;另外HBase是构建与HDFS之上的,我们似乎也没用到HDFS。是的,刚才我们的部署过程的确是单机的,而且也没有用到HDFS,用的是本地文件系统。我们现在的部署模式称之为Standalone模式,也就是单机模式,主要用于本地开发测试,这种模式下,HBase所依赖的所有东西都包在一个JVM进程里面,其实和Hadoop的单机模式类似。不过,对于我们平时的一些开发测试,这样部署基本上就够用了。但是对于生产环境,分布式的部署则是必须的了。下面我们介绍分布式部署。

分布式部署里面又分为伪分布式(pseudo-distributed)和真的分布式两种,其实质区别就是看所有的HBase进程是运行在一台主机上(伪分布式)还是多台主机上。但配置方式无实质区别,这里以伪分布式为例。其实也比较简单,只需要将刚才的hbase-site.xml修改如下即可:

<configuration>
  <property>
      <name>hbase.cluster.distributed</name>
      <value>true</value>
  </property>
  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://localhost:8020/hbase</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/your/path/zookeeper</value>
  </property>
</configuration>

可以看到,首先需要将hbase.cluster.distributed置为true,表示我们处于分布式模式,另外需要将hbase数据目录改为分布式目录,这里使用HDFS(如果你还没有部署Hadoop,请参照我之前的文章部署)。当然,HBase也支持其他分布式系统,比如S3等。配置完成后,然后重启HBase,通过jps命令可以看到相比于之前多了几个进程:

10.9.1.13➜  jps
15952 SecondaryNameNode        # HDFS 进程
27761 HRegionServer            # HBase 进程
15137 NodeManager            # YARN进程
27538 HQuorumPeer            # HBase ZK进程
15714 DataNode                # HDFS Slave进程
15002 ResourceManager        # YARN Master进程
15580 NameNode                # HDFS Master进程
28204 Jps
27612 HMaster                    # HBase Master进程

可以看到HBase现在有了3个进程,其他几个是Hadoop的进程,并不是由start-hbase.sh启动的。除了部署以外,其他的使用单机和分布式没有区别。需要注意一点的是在真正的分布式环境里面,我们使用hbase shell的时候往往要指定配置文件(hbase-site.xml)的目录,比如hbase --config /etc/hbase/conf shell,不然可能hbase会因为连接不到ZK而报错。

HBase提供了WebUI可以查看集群的信息:

  • Master:"http://<ip:16010>"
  • RegionServer: "http://<ip:16301>"

至此,HBase的安装就介绍完了。

3. 数据模型

HBase虽然也称之为数据库,但它和我们所熟知的关系型数据库还是差异非常大的,甚至可以说没有什么相似的。另外,我们知道关系型数据库(RDBMS)一般都是行存储,而HBase和很多其他面向大数据的数据库一般都是列式存储,这两种存储的核心区别就在于它们对数据的物理存储方式不同,这里用HBase:The Definitive Guide(HBase权威指南)上面的一幅图来说明:

行式存储与列式存储

而这两种不同的存储方式也决定了它们许多截然不同的特性,有兴趣的可以看下这篇文章:行式数据库与列式数据库的对比

下面我们介绍HBase里面的数据模型,虽然HBase与关系型数据库有着很大的差异,但为了方便理解,我们会做一些类比,方便读者理解。

3.1 基本概念

3.1.1 Namespace

Namespace从逻辑上将表分组,类似于RDBMS里面的数据库实例。HBase的Namespace主要是为了实现多租户的特性,可以从Namespace上面做一些资源分配、资源隔离、安全管理等功能。HBase有两个内置的Namespace:

  • hbase:系统Namespace,包含HBase内置的一些表;
  • default:默认Namespace,创建表时没有显式指定Namespace的表都在该Namespace下面。

HBase有一些和Namespace相关的命令:

# 列出所有namespace
hbase(main):001:0> list_namespace
NAMESPACE
default
hbase
2 row(s) in 0.4030 seconds

# 创建namespace
hbase(main):002:0> create_namespace 'test_ns'
0 row(s) in 0.0730 seconds

hbase(main):003:0> list_namespace
NAMESPACE
default
hbase
test_ns
3 row(s) in 0.0220 seconds

# 修改namespace:增加一个属性
hbase(main):006:0> alter_namespace 'test_ns', {METHOD=> 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
0 row(s) in 0.0840 seconds

# 查看namespace
hbase(main):007:0> describe_namespace 'test_ns'
DESCRIPTION
{NAME => 'test_ns', PROPERTY_NAME => 'PROPERTY_VALUE'}
1 row(s) in 0.0070 seconds

# 修改namespace:删除某个属性
hbase(main):009:0> alter_namespace 'test_ns', {METHOD=> 'unset', NAME=>'PROPERTY_NAME'}
0 row(s) in 0.0410 seconds

hbase(main):010:0> describe_namespace 'test_ns'
DESCRIPTION
{NAME => 'test_ns'}
1 row(s) in 0.0110 seconds

# 在某个namespace下创建表
hbase(main):011:0> create 'test_ns:test_table', 'col_fam'
0 row(s) in 2.4850 seconds

=> Hbase::Table - test_ns:test_table

# 列举某个namespace下的所有表
hbase(main):014:0> list_namespace_tables 'test_ns'
TABLE
test_table
1 row(s) in 0.0130 seconds

### 删除namespace: 只有空的namespace才可以删除
# disable表
hbase(main):020:0> disable 'test_ns:test_table'
0 row(s) in 2.3380 seconds
# 删除表:表必须处于disabled状态才可以删除
hbase(main):021:0> drop 'test_ns:test_table'
0 row(s) in 1.3290 seconds
# 删除namespace
hbase(main):023:0> drop_namespace 'test_ns'
0 row(s) in 0.0520 seconds

上面的例子基本覆盖了极大多数Namespace相关的命令。注意,Namespace到后台HDFS上实质就是一个目录。

3.1.2 Table & Row & Column Family & Column Qualifier & Cell & Timestamp

  1. Table:和RDBMS里面表的概念类似,表名到后台实质是一个目录,所以表名必须是合法的目录名字符串。
  2. Row:和RDBMS里面的行类似,但HBase里面每一行都要有一个唯一的row key标识,类似于RDBMS里面的主键。row key有两大特点:(1)没有类型,一般认为是字节流(byte[]),也就是说任何字节流可以表示的对象(比如二进制文件)都可以作为row key。(2)row key是按照字典序(lexicographically)排序的。row key设计是HBase表设计里面的最关键的一个点,后面介绍常见设计方式。
  3. Column Family:一般译为“列簇”,是HBase里面特有的一个非常重要的概念。若干个列组成一个列簇,比如有一个列簇叫courses,它里面包含mathhistory两个列,在HBase里面这个关系写为:courses:mathcourses:history,冒号后面的部分称之为Column qualifier。二者有如下一些特性:

    • Column Family后台实质是目录名,所以名称必须是合法的路径名;而Column qualifier则可以是任意字节流。
    • Column Family必须在表定义的时候就指定,而Column qualifier在插入数据的时候指定即可,甚至也可以不指定,比如courses:也是合法的。
    • 很多调优和存储属性设置都是基于Column Family的。
    • 物理上,Column Family里面的数据是存储在一起的,所以一般而言,同一个Column Family的数据列应该具有相同的访问特点,以及存储大小也应该相近。Column Family的使用对于HBase也至关重要,见后文。
  4. Cell:cell就是存储数据的地方,对应到RDBMS里面就是某行的某个字段,在HBase里面三元组{row key,Column Family,Column qualifier}唯一指定了一个cell。Cell里面存储的数据也是没有类型的,任何字节流可以表示的对象都可以。
  5. Versions:Cell里面存储的数据是有版本的,默认使用时间戳,保留三个版本。如果写入数据的时候没有指定版本,就会用当前时间作为版本号。读取数据时,如果没有指定版本号,默认获取最新版本的数据。

以上就是HBase数据模型里面的一些关键概念,这里看一张图(该图来自Amandeep khurana的Introduction to hbase Schema Design):

hbase Schema Design

这里展示了HBase中的一张表以及里面的一些数据。可以看到,该表的row key是“0001”、“0002”、...,按字典序排的;表里面有两个Column FamilyPersonalOfficePersonal里面包含两个列或者叫Column qualifierNameResidence phoneOffice里面包含两个列:PhoneAddress。每一个Cell里面是具体的数据,并且可能有多个版本。再附一张**上面的图:

hbase_table_design.png

我们可以将HBase的表看成是一个多维map(multidimensional map),比如上面的表其实就是下面一个多维map:

multidimensional map

当然,也可以将HBase的表看成是一个KeyValue存储系统,比如:

Key Value Store

上面列了5种情况,我们可以将row key当做key,也可以和其他属性一起作为key。

3.2 基本操作

了解了HBase数据模型的一些概念后,我们来看下HBase表的增删改查操作。

# 创建表
hbase(main):001:0> create 'tablename', 'colfam'
0 row(s) in 2.7860 seconds

=> Hbase::Table - tablename

# 查看表信息
hbase(main):003:0> desc 'tablename'
Table tablename is ENABLED
tablename
COLUMN FAMILIES DESCRIPTION
{NAME => 'colfam', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'false', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', T
TL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'}
1 row(s) in 0.2260 seconds

# 增加几条数据
hbase(main):004:0> put 'tablename', 'row1', 'colfam:q1', 'data1'
0 row(s) in 0.1990 seconds

hbase(main):005:0> put 'tablename', 'row2', 'colfam:q2', 'data2'
0 row(s) in 0.0210 seconds

hbase(main):006:0> put 'tablename', 'row3', 'colfam:q2', 'data3'
0 row(s) in 0.0170 seconds

hbase(main):007:0> put 'tablename', 'row4', 'colfam:', 'data4'
0 row(s) in 0.2040 seconds

# 查看表内所有数据
hbase(main):008:0> scan 'tablename'
ROW                                  COLUMN+CELL
 row1                                column=colfam:q1, timestamp=1524301718825, value=data1
 row2                                column=colfam:q2, timestamp=1524301742009, value=data2
 row3                                column=colfam:q2, timestamp=1524301761977, value=data3
 row4                                column=colfam:, timestamp=1524301779956, value=data4
4 row(s) in 0.0560 seconds

# 查看某条数据
hbase(main):009:0> get 'tablename', 'row3'
COLUMN                               CELL
 colfam:q2                           timestamp=1524301761977, value=data3
1 row(s) in 0.0420 seconds

hbase(main):010:0> disable 'tablename'
0 row(s) in 2.3340 seconds

# 删除表
hbase(main):011:0> drop 'tablename'
0 row(s) in 1.3210 seconds

下面我们简单介绍下上面的操作:

  1. 首先我们创建了一个表:tablename。创建表的时候必须指定表名和Column Family,如果未指定Namespace,默认在default这个Namespace下面。使用desc可以查看表信息。
  2. 往表里面插数据使用put命令,插数据的时候必须指定表名、row key、Column Family、数据。Column qualifier可选择性指定。如果row key相同,则HBase认为是Update操作,而不是插入新数据。
  3. 使用scan命令可以查看表里面所有的数据,使用get命令可以查看某条数据。
  4. 删除表使用drop命令,只有处于disabled状态的表才可以删除。

使用help "<command>"命令可以查看某个命令的详细使用方法,里面一般都有大量的例子,这里就不赘述了。

4. 架构简析

HBase的架构细说起来还是比较复杂的,有兴趣的可以去看下官方的参考手册,这里只对一些个人认为比较关键的点进行说明。

4.1 主从关系

HBase作为一个分布式系统,也是主从模式:一个Master(HMaster进程)和多个RegionServer(HRegionServer)。

Master负责监控集群内所有的RegionServer,所有和元数据相关的操作也由Master负责,比如RegionServer的负载均衡、故障切换、自动分片等均由Master负责。但因为Master并不存储具体数据,只负责管理,所以相对于RegionServer,Master的负载一般是比较低的。在分布式环境里面,往往和HDFS的Namenode部署在一起。为了HA,一个HBase集群中可以有多个Master,这些Master是相互竞争的(通过ZooKeeper选举)。更多关于HBase Master的信息可以看官方手册和这篇文章:HBase HMaster Architecture.

RegionServer是HBase中真正存储数据的地方,我们先来了解下Region这个概念。在HBase里面,region是实现表的可用性(availability)和分布式特性(distribution)的最基本单元,也是HBase可扩展(scalability)和负载均衡(load balance)的基础。刚开始的时候,一个表只有一个region,数据都存在这个region里面。随着数据量的增大,超出一个region的最大限制值(可设置:hbase.hregion.max.filesize)的时候,region就会从中间的row key处自动分裂成两个region,每个region保存一半的数据,这个过程叫自动分片(auto sharding)。而每个RegionServer上包含若干个region,这也是RegionServer名字的由来。HBase的数据是存储在HDFS上面的,所以分布式环境中,一般RegionServer和HDFS的Datanode部署在一起。相比于Master,RegionServer的负载一般是比较重的,因为它不光要负责管理和存储region外,还要响应客户端的请求。这里需要注意,客户端获取数据的时候,是直接和RegionServer交互的,而不是和Master。具体见下节。

4.2 读写操作

4.2.1 hbase:meta

hbase:meta(老版本里面叫.META.)是HBase里面的系统表(hbase时namespace名,meta是表名),从名字就能看出来,该表是存储元数据的。这个表的位置存储在ZooKeeper里面,表的具体内容存在HDFS上面:

# 在ZooKeeper里面查看hbase:meta的位置
➜  ~ zkCli.sh -server 127.0.0.1:2181
...
# 位置信息存储在/hbase/meta-region-server节点
[zk: 127.0.0.1:2181(CONNECTED) 5] get /hbase/meta-region-server
?regionserver:162018?n6m?QPBUF

ubuntu?~?????,
cZxid = 0x157
ctime = Fri Apr 20 15:57:28 CST 2018
mZxid = 0x157
mtime = Fri Apr 20 15:57:28 CST 2018
pZxid = 0x157
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 59
numChildren = 0

# 在Hbase里面查看
hbase(main):019:0> scan 'hbase:meta'
ROW                                  COLUMN+CELL
 hbase:namespace,,1522381563209.ab55 column=info:regioninfo, timestamp=1524211050206, value={ENCODED => ab558a3f1c03149e92a71cfcc02d66c7, NAME
 8a3f1c03149e92a71cfcc02d66c7.       => 'hbase:namespace,,1522381563209.ab558a3f1c03149e92a71cfcc02d66c7.', STARTKEY => '', ENDKEY => ''}
 hbase:namespace,,1522381563209.ab55 column=info:seqnumDuringOpen, timestamp=1524211050206, value=\x00\x00\x00\x00\x00\x00\x00\x12
 8a3f1c03149e92a71cfcc02d66c7.
 hbase:namespace,,1522381563209.ab55 column=info:server, timestamp=1524211050206, value=ubuntu:16201
 8a3f1c03149e92a71cfcc02d66c7.
 hbase:namespace,,1522381563209.ab55 column=info:serverstartcode, timestamp=1524211050206, value=1524211032085
 8a3f1c03149e92a71cfcc02d66c7.
 test,,1523524790332.8dbea38c5 column=info:regioninfo, timestamp=1524211049936, value={ENCODED => 8dbea38c5ae8e0e4126afa4215000f6c, NAME
 ae8e0e4126afa4215000f6c.            => 'test,,1523524790332.8dbea38c5ae8e0e4126afa4215000f6c.', STARTKEY => '', ENDKEY => ''}
 test,,1523524790332.8dbea38c5 column=info:seqnumDuringOpen, timestamp=1524211049936, value=\x00\x00\x00\x00\x00\x00\x00\x11
 ae8e0e4126afa4215000f6c.
 test,,1523524790332.8dbea38c5 column=info:server, timestamp=1524211049936, value=ubuntu:16201
 ae8e0e4126afa4215000f6c.
 ...

hbase:meta的表结构如下:

Row key格式:

[table],[region start key],[region id],即表名,起始row key值,region id

Column格式:

  • info:regioninfo: region信息;
  • info:server:RegionServer的信息,server:port;
  • info:serverstartcode:包含该region的RegionServer的进程启动时间。

hbase:meta包含了当前集群内所有region的信息及相关状态。

4.2.2 读写过程

了解了hbase:meta之后,客户端读写HBase的整个操作就非常简单了:

  1. 连接ZooKeeper,获取hbase:meta的地址;
  2. hbase:meta中获取需要读的数据分布在哪些region(RegionServer)上的信息;
  3. 直接与RegionServer交互,进行读写。

读操作比较简单,写操作的话HBase里面有一块内存区域叫Memstore,数据到达服务器后是“先”写到这块内存区域的,只有当内存区域满的时候,数据才会写到(flush)磁盘上面,落地为文件,这个文件称之为Hfile。当然这样就会有个问题,如果数据还未落地,服务器挂了,那内存里面的数据就丢了。这个不是HBase才有的问题,传统的很多数据库也有这个问题。解决方案也早已经比较成熟了,那就是预写日志(WAL, write ahead log),有时也叫commit log,也就是数据来了以后,先写日志,日志写成功之后才给客户端返回成功,这样就算宕机等内存数据丢了,依旧WAL是可以找回数据的。在HBase里面,该日志是存在HDFS上面的,所以可靠性是有保证的。等数据落盘之后,相关的预写日志也就会删掉了。

读写操作理解起来比较简单,这里需要注意三个点:

  • 客户端在第2步会缓存hbase:meta里面的信息,这样可以避免频繁读取hbase:meta,当遇到错误等一些情况时,才会重新读取hbase:meta
  • 读操作会优先在Memstore里面读,如果读到了,就不会去磁盘上扫描了。
  • 客户端的整个交互过程是没有涉及到Master的,这样在客户端请求比较多的情况下,Master不会成为系统的瓶颈,这是和很多其他主从式分布式系统的一个区别。

4.3 存储

HBase里面的存储层次在其官方参考手册里面有这样一处说明:

hbase storage

这里再附一张HBase:The Definitive Guide上面的图:

hbase storage architecture

结合这两个图,我们就看的比较清楚了:

  • 每个表包含一到多个region(图中的HRegion);
  • 每个RegionServer上面有多个region;
  • 每个region里面包含一到多个Store,每个Store对应一个Column Family,所以一般说到Store,就认为是Column Family即可;
  • 每个Store对应一个Memstore,Memstore里面的数据写文件后就是StoreFile,而Storefile底层就是HFile,很多时候我们不区分Storefile和HFile;
  • 最终不论是HLog(WAL或commit log)还是HFile,都会存储在HDFS上面。

总结一下:一个region里面有多个store,而一个store对应于一个Column Family,也就是说store、Column Family、MemStore三者是一对一的关系,Column Family落盘后就是多个Storefile,或者HFile。也就是上面region里面的一个方块就是一个Column Family。所以Column Family是HBase里面是非常重要的一个概念。

这里我们再重复强调一下Column Family,从上面的分析可以看出,Column Family的数据是存储在一起的,这也是为什么推荐将经常一起读写、大小相似的字段放在同一Column Family里面,我们能看到在HBase里面,Column(列)的概念被弱化了,取而代之的是Column Family,所以与其说HBase是面向列的数据库,不如说是面向Column Family的数据库。

上面的图都是逻辑图,那实际在HDFS上面是怎么存储的呢?HBase官方参考手册上面也有说明:

数据目录:

hbase data path on HDFS

但是在我安装的HBase 1.2.6上面,目录结构并不是这样的,正确的应该是:

/hbase/data/\<Namespace>/\<Table>/\<ColumnFamily>/\<StoreFile>

以前面示例代码中的testname表为例,如果你已经删了,重新创建回来,插入数据。put完数据之后,记得执行一下flush "testname",让数据落地,不然数据可能存储在Memstore里面,你看不到落地文件:

➜  ~ hadoop fs -ls /hbase/data/default/tablename/e010bb04332e265603d26b62778ba0fb/colfam
Found 1 items
-rw-r--r--   1 root supergroup       5033 2018-04-21 21:09 /hbase/data/default/tablename/e010bb04332e265603d26b62778ba0fb/colfam/41d86b3a845f4b2782cdd19b70d3c59a

HLog目录官方给的目录结构如下hbase-wal-log-path.png:

hbase data path on HDFS

但实际也也不是这样,正确的应该是:

/hbase/WALs/\<RegionServer>/\<WAL>
➜  ~ hadoop fs -ls /hbase/WALs/ubuntu,16201,1524211032085
Found 2 items
-rw-r--r--   1 root supergroup         83 2018-04-21 20:57 /hbase/WALs/ubuntu,16201,1524211032085/ubuntu%2C16201%2C1524211032085..meta.1524315453910.meta
-rw-r--r--   1 root supergroup         83 2018-04-21 20:57 /hbase/WALs/ubuntu,16201,1524211032085/ubuntu%2C16201%2C1524211032085.default.1524315451627

HBase是开源的、分布式、多版本的NoSQL数据库,其设计理念来自于Google的"Bigtable: A Distributed Storage System for Structured Data"论文,有兴趣的可以看看Google的这篇论文。本文涉及到的大都是一些基础的操作和理论,如何才能比较好的使用HBase,还是有非常多的技巧的,这方面我也才处于积累阶段,后续我会写一些类似最佳实践或者结合具体场景的东西,有兴趣的可以关注一下。

References

  1. Apache HBase Reference Guide(Version3.0.0-SNAPSHOT).
  2. HBase:The Definitive Guide.
  3. Hadoop The Definitive Guide(4th Edition).