美文网首页大数据
HBASE学习笔记

HBASE学习笔记

作者: 我是老薛 | 来源:发表于2018-12-09 09:23 被阅读0次

    本文是对Hbase组件的一个学习总结,共包括如下章节的内容:

    • Hbase是什么
    • Hbase的数据模型
    • Hbase体系结构
    • 安装和运行Hbase
    • Hbase命令行

    参考资料:

    1、如果Hbase的数据要保存到hdfs上(一般生产环境下如此),需要确保有可用的hadoop运行环境,可参见《Hadoop运行环境搭建》一文。

    2、因为Hbase运行依赖zookeeper服务,Hbase本身内置了zookeeper程序(往往用于开发和测试环境),如果希望独立部署zookeeper服务(一般生产环境下如此),可参见《Zookeeper学习笔记》一文。

    一、Hbase是什么

    HBase是Google Bigtable的克隆版。它是一个针对结构化数据的可伸缩、高可靠、高性能、分布式和面向列的动态模式数据库。和传统关系数据库不同,HBase采用了BigTable的数据模型:增强的稀疏排序映射表(Key/Value),其中,键由行关键字、列关键字和时间戳构成。HBase提供了对大规模数据的随机、实时读写访问,同时,HBase中保存的数据可以使用MapReduce来处理,它将数据存储和并行计算完美地结合在一起。

    二、Hbase的数据模型

    Hbase的数据逻辑上是存储在一张张表中。Hbase的表由行和列组成,行和列的交叉就是单元格,数据是存在单元格中的,单元格是有版本的,即一个单元格可存储多个版本的数据。

    有几个重要的概念:

    1、行键:
    Hbase表的每行都有一个行健(类似关系表的主键),表中的行按照行键进行排序,对表中行的访问也是依据行健来访问的。

    2、列族
    行中的列被分成“列族”(column family)。同一个列族的所有成员(即列)具有相同的前缀。
    表的列族是表模式的一部分,需要预先定义。但是列不是表模式的一部分。只要列族存在,客户端可以在更新时提供新的列,并存储它的值。
    列名都以列族作为前缀,例如courses:history , courses:math 都属于 courses 这个列族。
    这点与关系表不一样,关系表的列是表模式的一部分,关系表没有列族的概念。对于关系表,每行数据都有相同的列。但对于hbase表,每行数据都有相同的列族,但不一定有相同的列。

    3、时间戳
    HBase中通过行键和列确定的一个存贮单元称为单元格(cell)。每个 cell都保存着同一份数据的多个版本。默认情况下,版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由HBase (在数据写入时 )自动赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个 cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
    为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,HBase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。
    说明:创建表时,默认情况下,每个列族只支持存储一个版本的数据。这个可以通过alter语句来更改。

    4、单元(cell)
    一个单元由{row key, column( =<family> + <label>), version} 唯一确定。cell中的数据是没有类型的,全部是字节码形式存储。

    下面我们看一个例子。
    假设有一张Hbase表,表名为webtable,该表有名为 contents、anchor 和 people 的三个列族。该表有两行数据,行健分别为cn 和 en。
    对于第一行(cnn ),contents 列族包含一列(contents:html),anchor 包含两列(anchor:a,anchor:b),且第一行有5个版本。对于第二行(example),只有1个版本,contents 列族包含一列(contents:html),people列族包含一列(people:author)。
    表中有些数据,下面通过表格的方式来展示下该表的数据。


    此表中显示为空的单元格在 HBase 中不占用空间或实际上存在。这正是使 HBase “稀疏”的原因。表格视图并不是查看 HBase 数据的唯一可能的方法,对于 “稀疏”表,采用表格视图有时反而不是很方便。下面以类似json格式的视图来展示上面数据。

    {
      "cn": {
        contents: {
          t6: contents:html: "内容"
          t5: contents:html: "内容"
          t3: contents:html: "内容"
        }
        anchor: {
          t9: anchor:a = "x"
          t8: anchor:b = "y"
        }
        people: {}
      }
      "en": {
        contents: {
          t5: contents:html: "内容"
        }
        anchor: {}
        people: {
          t5: people:author: "tom"
        }
      }
    }
    

    对于Hbase表,可以看作是key/value集合的nosql数据库,其中的key就是行键,value是一个单元格(cell)的列表,单元格通过“列族+列+版本”来唯一标识。

    三、Hbase的物理存储结构

    Hbase表中的所有行都按照行键的字典序排列,表在行的方向上分割为多个HRegion。如下图所示。


    HRegion按大小分割。每一个表一开始只有一个HRegion,随着数据不断插入表,HRegion不断增大,当增大到一定阈值的时候,HRegion就会等分为两个新的HRegion。当表中的行不断增多,就会有越来越多的HRegion。

    HRegion是HBase中分布式存储和负载均衡的最小单元。最小单元就表示不同的HRegion可以分布在不同的HRegion Server上。但是一个HRegion是不会拆分到多个HRegion Server上。

    HRegion虽然是分布式存储的最小单元,但并不是存储的最小单元。事实上,HRegion由一个或者多个Store组成,每一个Store都保存一个列族。每一个Store又由一个memStore和多个StoreFile组成。StoreFile以HFile格式保存在HDFS上。如下图所示。


    memStore位于HRegion Server的内存中,数据写入时,首先会写入到memStore中,然后当到达一定的阀值的时候,Memstore中的数据会被刷到HFile中。

    四、Hbase体系结构

    Hbase的架构与hdfs,yarn类似,采用主从的架构,即一个Hbase系统包含一个master服务,若干个regionserver服务(分布在集群不同的机器上)。另外因为Hbase依赖zookeeper,所以一个Hbase系统中还需要包含zookeeper服务(相对zookeeper服务来说,Hbase服务是zookeeper的客户端)。当然还有Hbase的客户端(终端用户或其它系统访问Hbase服务的界面)。

    下图是Hbase集群系统的体系结构示意图。


    因为Hbase的主节点master只有一个,存在单点故障风险。在实际的环境下,往往会给mater节点配置HA。

    五、安装和运行Hbase

    安装

    1、下载Hbase安装压缩包,本文下载的是hbase-2.0.2-bin.tar.gz

    2、解压到某个目录下,我们这里解压的位置是:
    /home/hadoop/hbase2.0.2

    3、修改hadoop用户的profile文件,设置环境变量

    export HBASE_HOME=/home/hadoop/hbase-2.0.2
    PATH=$PATH:$HBASE_HOME/bin
    

    说明:Hbase的运行依赖java环境,需要确保安装运行Hbase的机器上有正常可用的java环境。

    Hbase有三种运行模式:独立模式;伪分布式模式;分布式模式。下面分别介绍。

    (一)独立模式

    独立模式下,HBase系统的所有服务程序,Master、RegionServers 以及依赖的ZooKeeper服务都运行在一个jvm进程中,Hbase不依赖hdfs,其数据存在本地文件中。该模式,只能用于开发和测试环境,不能用于生产环境。
    独立模式下,如果不修改Hbase的配置文件,Hbase和zookeeper数据会默认存储到本地的/tmp/hbase-当前用户名 目录下。但是如果所运行的机器上配置了hadoop环境,Hbase还是会去连接hdfs(这样如果Hadoop未启动,会报错)。所以最好能显示的进行配置。
    这时修改Hbase安装目录下conf目录下的hbase-site.xml文件,配置文件的内容设置如下:

    <configuration>
      <property>
        <name>hbase.rootdir</name>
        <value>file:///home/hadoop/hbasedata/hbase</value>
      </property>
      <property>
        <name>hbase.zookeeper.property.dataDir</name>
        <value>/home/hadoop/hbasedata/zk</value>
      </property>
    </configuration>
    

    配置文件中的habse.rootdir属性设置的是Hbase数据在本地的存储目录(使用本地磁盘存储,需要加file://前缀);habse.zookeeper.property.dataDir属性设置的是zookeeper数据的存储目录(因为zk的数据本身就是存储在本地,所以不用加file://前缀)。

    然后在控制台运行 start-hbase.sh 脚本就可以启动Hbase服务,这时我们用jps命令去查看,可以看到有一个名称为HMaster的java进程(即包含hbase master,regionserver,zookeeper三个服务的合一进程)。如:

    [hadoop@localhost ~]$ jps
    ......
    24060 HMaster
    .......
    

    说明独立模式下的Hbase服务启动成功。

    停止Hbase服务可以执行 stop-hbase.sh脚本。

    实际上,在独立模式下,Hbase的数据也可以不存储在本地,而是存储到hdfs上,这时配置文件配置如下:

    <configuration>
      <property>
        <name>hbase.rootdir</name>
        <value>hdfs://namenode地址:8020/hbase</value>
      </property>
      <property>
        <name>hbase.cluster.distributed</name>
        <value>false</value>
      </property>
      <property>
        <name>hbase.zookeeper.property.dataDir</name>
        <value>/home/hadoop/hbasedata/zk</value>
      </property>
    </configuration>
    

    这种情况下,Hbase的各服务(包括zk服务)依然运行在同一个jvm进程中。只是Hbase的数据存储到hdfs文件系统中。配置文件中的hbase.rootdir属性的值是一个hdfs系统的目录。当然,这种情况下,要Hbase服务能正常运行,相应的hdfs服务得正常可用。

    (二)伪分布式模式

    这类似hadoop的伪分布式模式,所有的Hbase服务以多个进程的方式运行,但是运行在一台机器上。这种模式一样只适合开发和测试,不适合生产环境。
    伪分布式模式的配置,只需将hbase.cluster.distributed属性值设为true。而Hbase的数据既可以设置存储在本地,也可以保存到hdfs上。如下面的配置(这里Hbase数据存储在本地):

    <configuration>
      <property>
        <name>hbase.rootdir</name>
        <value>file:///home/hadoop/hbasedata/hbase</value>
      </property>
      <property>
        <name>hbase.cluster.distributed</name>
        <value>true</value>
      </property>
      <property>
        <name>hbase.zookeeper.property.dataDir</name>
        <value>/home/hadoop/hbasedata/zk</value>
      </property>
    </configuration>
    

    在伪分布式模式下,通过bin目录下的hbase-daemon.sh来分别启动各个服务进程,操作如下:

    hbase-daemon.sh start zookeeper
    hbase-daemon.sh start master
    hbase-daemon.sh start regionserver
    

    通过上面的操作分别启动zookeeper服务进程,HBASE mater服务进程,HBASE regionserver服务进程。这时我们执行jps命令,会看到3个相关的进程:

    [hadoop@localhost ~]$ jps
    17585 HRegionServer
    17349 HMaster
    17212 HQuorumPeer
    

    如果要关闭各个服务,可以依次执行下面三个操作:

    hbase-daemon.sh stop regionserver
    hbase-daemon.sh stop master
    hbase-daemon.sh stop zookeeper
    

    在伪分布式下,我们也可以不用Hbase自带的zookeeper,而是使用独立安装的zookeeper。关于独立zookeeper的安装,本文不再介绍,可参见《Zookeeper学习笔记》一文。

    (三)分布式模式

    在实际生产环境下,会采用分布式模式来启动Hbase。在分布式模式下,HBase守护进程的多个实例在集群中的多个服务器上运行。分布式的配置要求将hbase.cluster.distributed属性设置为true。通常情况下,hbase.rootdir被配置为指向高可用性的HDFS文件系统。这时集群系统将包含多个运行在不同服务器上的RegionServer,以及主要和备份Master和ZooKeeper守护程序(也是以集群方式部署)。

    关于集群环境下的Hbase分布式部署,本文不作详细介绍。

    六、Hbase命令行

    Hbase服务启动后(最简单的方式就是使用本地文件系统以独立模式启动Hbase),就可以利用Hbase客户端程序访问Hbase服务了。
    Hbase安装包中提供了一个命令行脚本hbase,位于bin目录下。在控制台下运行 hbase shell ,会出现交互式命令行程序(时间可能有点长,实际是启动了一个java进程),可以执行操作Hbase的各种命令,如:

    [hadoop@localhost ~]$ hbase shell
    ...................................
    Took 0.0042 seconds
    hbase(main):001:0>
    

    在提示符下输入help命令可以查看帮助信息。

    1、查看用户空间下的所有表:

    hbase(main):018:0> list
    TABLE
    0 row(s)
    Took 0.0042 seconds
    

    2、创建表:

    hbase(main):063:0> create 'test','cf1','cf2'
    Created table test
    Took 0.7255 seconds
    

    上面create命令创建了一个表,表名叫test,有2个列族cf1和cf2,属性采用默认的。注意hbase命令后的参数要用引号括起来。
    这时我们如果再执行list命令,就能查到刚创建的test表。

    3、查看表的信息

    hbase(main):064:0> desc 'test'
    Table test is ENABLED
    test
    COLUMN FAMILIES DESCRIPTION
    {NAME => 'cf1', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DAT
    A_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER => 'ROW',
     CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION =>
     'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
    {NAME => 'cf2', VERSIONS => '1', EVICT_BLOCKS_ON_CLOSE => 'false', NEW_VERSION_BEHAVIOR => 'false', KEEP_DELETED_CELLS => 'FALSE', CACHE_DAT
    A_ON_WRITE => 'false', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', REPLICATION_SCOPE => '0', BLOOMFILTER => 'ROW',
     CACHE_INDEX_ON_WRITE => 'false', IN_MEMORY => 'false', CACHE_BLOOMS_ON_WRITE => 'false', PREFETCH_BLOCKS_ON_OPEN => 'false', COMPRESSION =>
     'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536'}
    2 row(s)
    Took 0.0245 seconds
    

    4、往表中插入数据:

    hbase(main):066:0> put 'test','row1','cf1:a', 'a123'
    Took 0.0244 seconds
    hbase(main):067:0> put 'test','row1','cf1:b', 'b123'
    Took 0.0045 seconds
    

    上面操作,插入了两个数据,插入的是一行数据,行的关键字值为row1,列族cf1有两个成员,标示符分别是a和b。可以看出,put命令实际是往单元格中插入值。hbase表的列只是在数据插入时才确定。

    5、查看表中所有数据

    hbase(main):068:0> scan 'test'
    ROW    COLUMN+CELL
     row1  column=cf1:a, timestamp=1544099621874, value=a123
     row1  column=cf1:b, timestamp=1544099630279, value=b123
    1 row(s)
    Took 0.0099 seconds
    

    6、查看表中指定行、列族、列的数据

    hbase(main):069:0> get 'test','row1'
    COLUMN     CELL
     cf1:a     timestamp=1544099621874, value=a123
     cf1:b     timestamp=1544099630279, value=b123
    1 row(s)
    Took 0.0162 seconds
    hbase(main):070:0>
    hbase(main):071:0* get 'test','row1','cf1'
    COLUMN     CELL
     cf1:a     timestamp=1544099621874, value=a123
     cf1:b     timestamp=1544099630279, value=b123
    1 row(s)
    Took 0.0118 seconds
    hbase(main):072:0> get 'test','row1','cf1:b'
    COLUMN     CELL
     cf1:b     timestamp=1544099630279, value=b123
    1 row(s)
    Took 0.0063 seconds
    

    7、查看多版本数据
    因为hbase表中的单元格可以允许存储多版本数据,但默认创建表的情况下,各列族允许的存储版本数的个数是1,可以通过desc命令能查看到。可以通过alter命令来重新修改,语法如:

    alter '表名',{NAME=>'列族名',VERSIONS=>允许的版本数}

    如下面例子:

    hbase(main):073:0> alter 'test',{NAME=>'cf2',VERSIONS=>3}
    Updating all regions with the new schema...
    1/1 regions updated.
    Done.
    Took 1.8416 seconds
    
    hbase(main):074:0> put 'test','row1','cf2:a','data1'
    Took 0.0079 seconds
    hbase(main):075:0> put 'test','row1','cf2:a','data2'
    Took 0.0035 seconds
    hbase(main):076:0> put 'test','row1','cf2:a','data3'
    Took 0.0034 seconds
    
    hbase(main):082:0> get 'test','row1','cf2:a'
    COLUMN      CELL
     cf2:a      timestamp=1544104507106, value=data3
    1 row(s)
    Took 0.0143 seconds
    
    hbase(main):084:0> get 'test','row1',{COLUMN=>'cf2:a',VERSIONS=>3}
    COLUMN     CELL
     cf2:a     timestamp=1544104507106, value=data3
     cf2:a     timestamp=1544104503371, value=data2
     cf2:a     timestamp=1544104498175, value=data1
    1 row(s)
    Took 0.0091 seconds
    

    可以看出,在get命令后加上 {COLUMN=>'cf2:a',VERSIONS=>3}参数可以返回多个版本的值。

    8、删除数据
    删除指定的行下的某个列族下的列(即某个单元格)
    delete 'test','row1','data:a'
    删除整行
    deleteall 'test','row1'

    9、禁用表

    hbase(main):012:0> disable 'test'
    Took 0.8346 seconds
    

    在hbase中,删除表之前,必须先禁用表后才能删除。

    10、删除表

    hbase(main):012:0> drop 'test'
    Took 0.4346 seconds
    

    在实际应用中,我们一般会通过编写程序的方式去使用Hbase。最常见的是使用Hbase提供的java api来编写Hbase客户端程序。关于Hbase的java api的使用,在后面文章进行介绍。

    相关文章

      网友评论

        本文标题:HBASE学习笔记

        本文链接:https://www.haomeiwen.com/subject/mldhhqtx.html