Hbase的基本原理与使用

重点:HBase的基本数据模型、拓扑结构、部署配置方法,并介绍通过命令行和编程方式使用HBase的基本方法。

HBase:一种列存储模式与键值对相结合的NoSQL软件,但更多的是使用列存储模式,底层的数据文件采用HDFS存储,其文件结构和元数据等由自身维护.

HBase是Hadoop的重要成员,提供了分布式数据表和更高效的数据查询能力,弥补了HDFS只能进行文件管理以及MapReduce不适合完成实时任务的缺陷.

HBase利用HDFS实现数据分布式存储,数据分块以及多副本等,HBase在此基础上实现了对记录的更新和删除.

Hbase具有灵活的数据模型,不仅可以基于键进行快速查询,还可以实现基于值、列名等的全文遍历和检索。

1、HBase概述

HBase的优点:

  • 采用面向列加键值对的存储模式
  • 可以实现便捷的横向扩展,对于元数据管理能力的扩展,可以通过数据分片的方式进行.
  • 可以实现自动的数据分片.
  • 可以实现严格的读写一致性和自动的故障转移
  • 可以实现对全文的检索与过滤
  • 支持通过命令行或者java/python等语言来进行操作

2、HBase的数据结构模型

HBase逻辑数据模型:

 HBase物理存储方式,其中StuInfo列族的物理存储方式:

HBase采用的是一种面向列的键值对存储模式。

 

表4-1中有2行记录,行键:001和002,其他所有信息均可以看做是行内记录的字段,或者列。

表中有2个列族(Column Family),列族的名字必是可显示的字符串。每个列族中含有若干列(Columns)。列族可以看做HBase表结构(Schema)的一部分需要在建表时预先定义

eg,创建表:create‘表名',‘列族名1’, ‘列族名2’, ‘列族名N’

对于面向列的存储模式,列则不属于表结构,HBase不会预先定义列名及其数据类型和值域等内容。每一条记录中的每个字段必须记录自己的列名(也称列标识符,Column qualifier)以及值(Value)的时间戳(Timestamp)。这和关系型数据库有很大的不同,在关系型数据库中,表结构(Schema)是独立存储的。

在关系型数据库中可能会采用以下方式进行记录:

Hbase并不需要预先设计列的结构,当添加新的列时,只需要在新记录中记录这个列名即可,不会对已有的数据产生任何影响。由于Hbase每条记录都记录了自己的列名,如果某一行数据不存在某个列,则不会记录该键值对。因此HBase不需要对不存在的数据项记录null值,使HBase可以支持数以万计的列名,且并不会在数据稀疏的情况下为NULL值消耗存储空间。

eg,新增或修改表的值:put ‘表名’, ‘行键’, ‘列族名’, ‘列值’或者 put ‘表名’, ‘行键’, ‘列族名:列名’, ‘列值’

列族HBase的实际存储方式:

逻辑上的两行数据,在实际上被保存为8个键值对,或称为单元格(cell)。单元格是由行键、列名、值和时间戳来确定的最小存储单元。

键值对的实际存储方式:

 每一行数据,或者说每一个键值对包含了行键(Row)、列族名称(Column Family)和列标识符(Column Qualifier),即列名、时间戳、行键类型(Key Type)与值(Value)。

eg:

 1)Name Space

命名空间,类似于关系型数据库的database概念,每个命名空间下有多个表,HBASE有两个自带的命名空间,分别是HBASE和default,HBASE中存放的是HBASE内置的表(系统内建表,包含namespace和meta表:存的是用户表或系统表位置信息),default表是用户默认的使用的命名空间(用户建表时未指定namespace的表都创建在此)。

HBase中的数据以表的形式存储。表名作为HDFS存储路径的一部分来使用,在HDFS中可以看到每个表名都作为独立的目录结构。

2) Region(表的切片)

Hbase 表的分片,HBase 表会根据 RowKey值被切分成不同的 region 存储在 RegionServer 中,在一个 RegionServer 中可以有多个不同的 region。 

3)行( Row)

   在HBase表里,每一行数据代表一个数据对象,每一行都有一个行键(Row Key)来进行唯一标识[不可分割的字节数组,且按照字典排序[ASCII码]由低到高存储],每一行都有一个rowkey和多个column(列)组成。在HBase中针对行键建立索引,提高检索数据的速度。

scan ‘表名’
//扫描某个列族
scan ‘表名’, {COLUMN=>‘列族名’}
//扫描某个列族的某个列
scan ‘表名’, {COLUMN=>‘列族名:列名’}
//查询同一个列族的多个列
scan ‘表名’, {COLUMNS => [ ‘列族名1:列名1’, ‘列族名1:列名2’, …]}

4) Column

HBASE中的每个列都由column family(列族)和column qualifier(列限定符)进行限定,例如info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义。列族是列的集合,列族中所有列成员有相同的前缀,列族的名字必须是可显示的字符串。

5) Store

每一个region有一个或多个store组成,至少是一个store,hbase会把一起访问的数据放在一个store里面,即为每个ColumnFamily建一个store(即有几个ColumnFamily,也就有几个Store)。一个Store由一个memStore、0或多个StoreFile组成。

6)Time Stamp(时间戳)

    用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入HBASE的时间。

7)Cell(单元格)

    由{rowkey,column family:column qualifier,time stamp}唯一确定的单元,cell中的数据没有类型的,全部是字节码形式存储。

3、HBase的拓扑结构

HBase采用了主从式的拓扑结构。其主要组件包括一个主节点和若干个从节点(称为Reginsonserver或Hregionserver)。这里的主从节点都是服务器节点。HBase还需要借助Zookeeper集群来实现节点监控和容错。

 

 

1个Region Server 包含多个Region,每个Region里面包含一个或多个store(存储的实际数据)。

regionserver的作用:

  • 数据的增删改查
  • region的切分和合并,即使master挂掉也不影响查询数据。

hbase依赖于zookeeper,master的作用:表的增删改查、管理regionserver。

 

  HBASE底层依赖于hdfs,还依赖于zookeeper,hbasemaster(管理ddl操作)会将某一部分工作交给zookeeper(zookeeper分担hbasemaster与client的交互,client从zookeeper中获取表region相关信息)。Regionserver(管理dml操作)维护一个个region,多个HRegion共享HLog(预写入日志,防止内存中数据丢失,用来做灾难恢复)。每一个region里面包含一个或多个store(逻辑上是表的列族,store存储上是分离的,实际数据存储在Men store(内存)和store file(磁盘)里面),每个store包含与其对应的MemStore以及一个或多个StoreFile(到达刷写条件后,从内存到磁盘会刷写数据,刷写后就会生成一个store file),hfile是一种文件格式,最后store file 和hlog都要通过hdfs client 交互存到hdfs。

Client

  Client 包含了访问 Hbase 的接口,另外 Client 还维护了对应的 cache 来加速 Hbase 的访问,比如 cache 的.META.元数据的信息。

Zookeeper

  HBase 通过 Zookeeper 来做 master 的高可用、RegionServer 的监控、元数据的入口以及 集群配置的维护等工作。

具体工作如下:

  • 通过 Zoopkeeper 来保证集群中只有 1 个 master 在运行,如果 master 异常,会通过竞争机制产生新的master提供服务
  • 通过 Zoopkeeper 来监控 RegionServer 的状态,当 RegionSevrer 有异常的时候,通过回调的形式通知 Master RegionServer 上下线的信息
  • 通过 Zoopkeeper 存储元数据的统一入口地址

HMaster

HMaster的主要功能有:(分配region、管理regionserver)

  • 把HRegion分配到某一个RegionServer。
  • 有RegionServer宕机了,HMaster可以把这台机器上的Region迁移到active的RegionServer上。
  • 对HRegionServer进行负载均衡。

注:HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行。

HRegionServer(维护Hregion处理请求、拆分Hregion)

  • 维护HMaster分配给它的HRegion,处理对这些HRegion的IO请求,也就是说客户端直接和HRegionServer打交道。(从图中也能看出来)
  • 负责切分正在运行过程中变得过大的HRegion

HRegion

  Hbase 表的分片,HBase 表会根据 RowKey值被切分成不同的 region 存储在 RegionServer 中,在一个 RegionServer 中可以有多个不同的 region。

  每个HRegion由多个Store构成,每个Store保存一个列族(Columns Family),表有几个列族,则有几个Store,每个Store由一个MemStore和多个StoreFile组成,MemStore是Store在内存中的内容,写到文件后就是StoreFile。StoreFile底层是以HFile的格式保存。

HLog
    HLog(WAL log):WAL意为write ahead log(预写日志),用来做灾难恢复使用,HLog记录数据的变更,包括序列号和实际数据,所以一旦region server 宕机,就可以从log中回滚还没有持久化的数据。

Store = memstore + storefile

  一个 Store 对应 HBase 表中的一个列族。当一个列族的memstore触发持久化条件时,整个region里的store会全部进行持久化操作。Store中的数据持久化存储在HDFS上,其格式为Hfile。

Memstore

  每个store管理一块内存memstore,当用户写入键值对时,最终会将数据写入memstore,当memstore中的数据达到一定大小,或者一定时间,或者用户执行flush指令时,regionserver会将memstore中的数据按行键进行字典顺序排序,并持久化写入storefile中。

Storefile :包含Hfile

  当memstore中的数据不断持久化,形成多个storefile.每个storefile是有序的,但storefile之间是无序的。

HFile
    这是在磁盘上保存原始数据的实际的物理文件,是实际的存储文件。StoreFile 是以 Hfile 的形式存储在 HDFS 的。

4、水平分区原理

   HBase将大数据表水平分割,形成不同的region,并由不同的regionserver管理。原理:一个表刚建立时,只有一个数据分区,随着数据增多,根据一定规则将表进行水平拆分,形成2个分区或多个分区,这些分区交给不同的regionserver管理。

  分区的拆分是基于行键[行键按ASCII码进行排序]进行的,无论分区几次,属于哪个列族,相同的行键一定在一个region中。HBase的数据文件(HFile)是一种Map文件,即排序后的序列化文件。

4.1 Meta表

  表和分区的分级管理机制:用户进行读写数据时,会根据需要读写的表和行键,通过如下顺序寻找该行键对应的分区:Zookeeper->META->Regionserver->Region.

  META表的入口地址存储在Zookeeper集群,表的实体由若干个Regionserver进行管理(持久化在HDFS上)。Meta节点并不负责存储这些信息,客户端在寻址之后,可以将信息缓存。

 

4.2 读流程

首先往hbase写数据,client put一条数据,会先去zk里面找mete表所在的regionserver位置,假设返回meta表在regionserver102中,client再请求regionserver102返回要put数据的表的regionserver位置(此时客户端会把元数据缓存下来,下次先找缓存,没有再找zk)。再假设要put数据对应的表的在regionserver103上,此时client发送请求到regionsever103上,先写预写入日志,再写入内存,此时对于客户端来说,写就结束了,不需要等到flush,然后就通知下客户端写操作结束。

4.3 数据写入机制

  HBase通过Regionserver来管理写入。Regionserver负责向对应的表分区和列族中写入数据,管理缓存和排序,以及实现容错。

  每个Regionserver可能管理多个表和多个分区。Regionserver将用户请求的数据对应写到表分区(Hregion)中,每个分区中有一个或多个store,每个store对应当前分区中的一个列族。

比之前多了一个block cache(读缓存),缓存的是实际数据,client get查询一条数据,会先去zk里面找mete表所在的regionserver位置,假设返回meta表在regionserver102中,client再请求regionserver102返回要get数据的表的regionserver位置,再假设要get数据对应的表的在regionserver103上,此时client发送get请求到regionsever103上,读取内存、block cache以及磁盘,先将磁盘中的数据缓存至block cache中,方便下次查询,再比较时间戳选择时间戳最新的返回。

演示:

Test表已有中rowkey行info列族name列值为“zhangsan”,先刷写到磁盘:flush “test” 

查看磁盘中hfile:./hbase org.apache.hadoop.hbase.io.hfile.HFile -a -b -e -k -p -f /home/hbase/data/default/test/9cc2c91ace3d7a1d8f88aa95f4867206/info/ 

再修改zhangsan为lisi:put "test","rowkey","info:name","lisi",time stamp(小于修改数据的时间戳) 

再查看表中数据为张三还是李四:scan “test”。

数据写入机制的相关配置:通过hbase-site.xml中进行多种配置,可以实现memstore[大小]和持久化[阻塞系统]等机制的管理和优化。

5、HBase的基本操作(HBase shell)

命名

描述

语法

help ‘命令名’

查看命令的使用描述

help ‘命令名’

whoami

我是谁

whoami

version

返回hbase版本信息

version

status

返回hbase集群的状态信息

status

table_help

查看如何操作表

table_help

create

创建表

create ‘表名’, ‘列族名1’, ‘列族名2’, ‘列族名N’

alter

修改列族

添加一个列族:alter ‘表名’, ‘列族名’
删除列族:alter ‘表名’, {NAME=> ‘列族名’, METHOD=> ‘delete’}

describe

显示表相关的详细信息

describe ‘表名’

list

列出hbase中存在的所有表

list

exists

测试表是否存在

exists ‘表名’

put

添加或修改的表的值

put ‘表名’, ‘行键’, ‘列族名’, ‘列值’
put ‘表名’, ‘行键’, ‘列族名:列名’, ‘列值’

scan

通过对表的扫描来获取对用的值

scan ‘表名’
扫描某个列族: scan ‘表名’, {COLUMN=>‘列族名’}
扫描某个列族的某个列: scan ‘表名’, {COLUMN=>‘列族名:列名’}
查询同一个列族的多个列: scan ‘表名’, {COLUMNS => [ ‘列族名1:列名1’, ‘列族名1:列名2’, …]}

get

获取行或单元(cell)的值

get ‘表名’, ‘行键’
get ‘表名’, ‘行键’, ‘列族名’

count

统计表中行的数量

count ‘表名’

incr

增加指定表行或列的值

incr ‘表名’, ‘行键’, ‘列族:列名’, 步长值

get_counter

获取计数器

get_counter ‘表名’, ‘行键’, ‘列族:列名’

delete

删除指定对象的值(可以为表,行,列对应的值,另外也可以指定时间戳的值)

删除列族的某个列: delete ‘表名’, ‘行键’, ‘列族名:列名’

deleteall

删除指定行的所有元素值

deleteall ‘表名’, ‘行键’

truncate

重新创建指定表

truncate ‘表名’

enable

使表有效

enable ‘表名’

is_enabled

是否启用

is_enabled ‘表名’

disable

使表无效

disable ‘表名’

is_disabled

是否无效

is_disabled ‘表名’

drop

删除表

drop的表必须是disable的
disable ‘表名’
drop ‘表名’

shutdown

关闭hbase集群(与exit不同)

 

tools

列出hbase所支持的工具

 

exit

退出hbase shell

 

6、什么场景适合HBase

半结构化或非结构化数据:数据结构字段不够确定或杂乱无章很难按一个概念去进行抽取的数据。

记录非常稀疏:RDBMS的行有多少列是固定的,为null的列浪费了存储空间。HBase为null的Column不会被存储,节省空间的同时又提高了读性能。

多版本数据:如上文提到的根据Row key 和Column key定位到的Value可以有任意数量的版本值,因此对于需要存储变动历史记录的数据。

超大数据量:RDBMS数据库撑不住,就出现了读写分离策略,通过一个master专门负责写操作,多个Slave负责读操作,服务器成本倍增。随着压力增加,master撑不住,就需要分库,把关联不大的数据分开部署,join查询用不上,需要借助中间层。随着数据量的进一步增加,一个表的记录越来越大,查询就变得很慢,于是又得搞分表,比如按ID取模分成多个表以减少单个表的记录数。

 

猜你喜欢

转载自www.cnblogs.com/wendyw/p/12616694.html