HBase详解

1 Hbase是什么

Hbase它是一个数据库,一个支持大容量存储且支持高效率实时查询的数据库。在这个数据爆炸的时代,面临海量数据实时高效查询是不可避免的,Hadoop支持海量数据存储,但它不支持低延迟高效查询,于是乎有了Hbase。
专业一点定义,HBase是Google BigTable的开源实现版,是建立在Hadoop HDFS之上,提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统。它介于NoSql和RDBMS之间,仅能通过主键(rowKey)和主键的range来检索数据,仅支持单行事务,主要用来存储非结构化和半结构化的松散数据。
与hadoop一样,Hbase可以依靠横向扩展,通过不断增加廉价的商用服务器,来增加计算和存储能力。

2 Hbase特点

2.1 优点

  1. 大:一个表可以有上亿+、10亿+行,上百万列;
  2. 写入性能高,适用于插入比查询操作更频繁的情况;
  3. 查询性能好,海量数据下(100TB级别表)的查询(rowKey)依然能保持在ms级别;
  4. 面向列:面向列表(簇)的存储和权限控制,列(簇)独立检索。
  5. 稀疏:对于为空(NULL)的列,并不占用存储空间,因此,表可以设计的非常稀疏;
  6. 无模式:每一行都有一个可以排序的主键和任意多的列,列可以根据需要动态增加,同一张表中不同的行可以有截然不同的列;
  7. 数据多版本:每个单元中的数据可以有多个版本,默认情况下,版本号自动分配,版本号就是单元格插入时的时间戳;
  8. 数据类型单一:HBase中的数据都是字符串,没有类型。

2.2 缺点

  1. 只支持单一rowKey或rowKey range查询,不支持多条件复杂查询;
  2. 不适合于大范围扫描查询
  3. 不直接支持 SQL 的语句查询,学习和开发成本高;
  4. 不支持索引
    对于3)、4)缺陷后面文《phoenix使用详解》中将给出解决方案
  5. 并不能保证100%时间可用,宕机恢复时间根据写入流量不同在几秒到几十秒甚至更高
  6. 可能存在数据丢失

3 Hbase架构

3.1 架构图

HBase架构图

3.2 基础组件说明

3.2.1 Client

客户端包含访问Hbase的接口,同时在缓存中维护着已经访问过的Region位置信息,用来加快后续数据访问过程。

  1. HBase 有两张特殊表:
    .META.:记录了用户所有表拆分出来的的 Region 映射信息,.META.可以有多个 Regoin
    -ROOT-:记录了.META.表的 Region 信息,-ROOT-只有一个 Region,无论如何不会分裂
  2. Client 访问用户数据前需要首先访问 ZooKeeper,找到-ROOT-表的 Region 所在的位置,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,中间需要多次网络操作,不过 client 端会做 cache 缓存。

3.2.2 Zookeeper

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

  1. ZooKeeper 为 HBase 提供 Failover 机制,选举 Master,避免单点 Master 单点故障问题;
  2. 存储所有 Region 的寻址入口:-ROOT-表在哪台服务器上,-ROOT-这张表的位置信息;
  3. 实时监控Region Server的状态,将Region server的上线和下线信息实时通知给Master;
  4. 存储Hbase的schema,包括有哪些table,每个table有哪些column family。

3.2.3 Master:(是所有 Region Server 的管理者)

  1. 为 RegionServer 分配 Region
  2. 负责 RegionServer 的负载均衡
  3. 发现失效的 RegionServer 并重新分配其上的 Region
  4. HDFS 上的垃圾文件(HBase)回收
  5. 处理 Schema 更新请求(表的创建,删除,修改,列簇的增加等等)

3.2.4 RegionServer:(为 Region 的管理者)

  1. RegionServer 维护 Master 分配给它的 Region,处理对这些 Region 的 IO 请求
  2. RegionServer 负责 Split 在运行过程中变得过大的 Region,负责 Compact 操作
  3. 刷新缓存到HDFS
  4. 维护Hlog
    可以看到,client 访问 HBase 上数据的过程并不需要 master 参与(寻址访问 zookeeper 和 RegioneServer,数据读写访问 RegioneServer),Master 仅仅维护者 Table 和 Region 的元数据信息,负载很低。
    .META. 存的是所有的 Region 的位置信息,那么 RegioneServer 当中 Region 在进行分裂之后的新产生的 Region,是由 Master 来决定发到哪个 RegioneServer,这就意味着,只有 Master 知道 new Region 的位置信息,所以,由 Master 来管理.META.这个表当中的数据的 CRUD
    所以结合以上两点表明,在没有 Region 分裂的情况,Master 宕机一段时间是可以忍受的。

3.2.5 Region

table在行的方向上分隔为多个Region。Region是HBase中分布式存储和负载均衡的最小单元(但不是存储的最小单元),即不同的region可以分别在不同的RegionServer上,但同一个Region是不会拆分到多个server上。
Region按大小分隔,每个表开始只有一个region。随着数据不断插入表,region不断增大,当region的某个列族达到一个阈值时就会分成两个新的region。
每个region由以下信息标识:< 表名,startRowkey,创建时间>
由目录表(-ROOT-和.META.)记录该region的endRowkey。
Region

3.2.6 Store

每一个region由一个或多个store组成,至少是一个store,hbase会把一起访问的数据放在一个store里面,即为每个 ColumnFamily建一个store,如果有几个ColumnFamily,也就有几个Store。一个Store由一个memStore和0或者多个StoreFile组成。 HBase以store的大小来判断是否需要切分region。

3.2.7 MemStore

memStore 是放在内存里的。保存修改的数据即keyValues。当memStore的大小达到一个阀值(默认128MB)时,memStore会被flush到文件,即生成一个快照。目前hbase 会有一个线程来负责memStore的flush操作。

3.2.8 StoreFile

memStore内存中的数据写到文件后就是StoreFile,StoreFile底层是以HFile的格式保存。当storefile文件的数量增长到一定阈值后,系统会进行合并(minor、major compaction),在合并过程中会进行版本合并和删除工作(majar),形成更大的storefile。

3.2.9 HFile

HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对Hfile做了轻量级包装,即StoreFile底层就是HFile。

3.2.10 HLog

HLog(WAL log):WAL意为write ahead log,用来做灾难恢复使用,HLog记录数据的所有变更,一旦region server 宕机,就可以从log中进行恢复。
HLog文件就是一个普通的Hadoop Sequence File, Sequence File的key是HLogKey对象,其中记录了写入数据的归属信息,除了table和region名字外,还同时包括sequence number和timestamp,timestamp是写入时间,sequence number的起始值为0,或者是最近一次存入文件系统中的sequence number。 Sequence File的value是HBase的KeyValue对象,即对应HFile中的KeyValue。

4 Data Model数据模型

简单来说,应用程序是以表的方式在HBase存储数据的。表是由行和列构成的,所有的列是从属于某一个列族的。行和列的交叉点称之为cell,cell是版本化的。cell的内容是不可分割的字节数组。表的行键也是一段字节数组,所以任何东西都可以保存进去,不论是字符串或者数字。HBase的表是按key排序的,排序方式之针对字节的。所有的表都必须要有主键-key.

4.1 逻辑结构图

逻辑图

4.2 物理存储结构
物理图
1. Name Space
命名空间,类似于关系型数据库的 DatabBase 概念,每个命名空间下有多个表。HBase有两个自带的命名空间,分别是 hbase 和 default,hbase 中存放的是 HBase 内置的表,default 表是用户默认使用的命名空间。
2. Row
HBase 表中的每行数据都由一个 RowKey 和多个 Column(列)组成,数据是按照 RowKey的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索,所以 RowKey 的设计十分重要。
3. Column
Hbase表中的每个列都属于某个列族,列族必须作为表模式定义的一部分预先给出。如:create ‘table’, ‘family’。
列名以列族作为前缀,每个"列簇"都可以是多个列成员,如course:math, course:english。
权限控制、存储、调优都是在列簇层面进行。
Hbase把同一列簇里面的数据存储在同一个目录下
4. TimeStamp
用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会自动为其加上该字段,其值为写入 HBase 的时间。
5. Cell
由{rowkey, column Family:column Qualifier, time Stamp} 唯一确定的单元。cell 中的数据是没有类型的,全部是字节码形式存贮(byte[]数组)。

5 Hbase工作流程

5.1 Region 寻址

1、老的 Region 寻址方式
在 HBase-0.96 版本以前,HBase 有两个特殊的表,分别是-ROOT-表和.META.表,其中-ROOT的位置存储在 ZooKeeper 中,-ROOT-本身存储了.META. Table 的 RegionInfo 信息,并且-ROOT不会分裂,只有一个 Region。而.META.表可以被切分成多个 Region。读取的流程如下图所示:
寻址

详细步骤:
第 1 步:Client 请求 ZooKeeper 获得-ROOT-所在的 RegionServer 地址
第 2 步:Client 请求-ROOT-所在的 RS 地址,获取.META.表的地址,Client 会将-ROOT-的相关 信息 cache 下来,以便下一次快速访问
第 3 步:Client 请求.META.表的 RegionServer 地址,获取访问数据所在 RegionServer 的地址, Client 会将.META.的相关信息 cache 下来,以便下一次快速访问
第 4 步:Client 请求访问数据所在 RegionServer 的地址,获取对应的数据

从上面的路径我们可以看出,用户需要 3 次请求才能直到用户 Table 真正的位置,这在一定 程序带来了性能的下降。在 0.96 之前使用 3 层设计的主要原因是考虑到元数据可能需要很大。但是真正集群运行,元数据的大小其实很容易计算出来。

2、新的 Region 寻址方式
如上面,2 层结构其实完全能满足业务的需求,因此 0.96 版本以后将-ROOT-表去掉了。 如下图所示:
新寻址

访问路径变成了 3 步:
第 1 步:Client 请求 ZooKeeper 获取.META.所在的 RegionServer 的地址。
第 2 步:Client 请求.META.所在的 RegionServer 获取访问数据所在的 RegionServer 地址,Client 会将.META.的相关信息 cache 下来,以便下一次快速访问。
第 3 步:Client 请求数据所在的 RegionServer,获取所需要的数据。
总结去掉-ROOT-的原因有如下 2 点:
  其一:提高性能
  其二:2 层结构已经足以满足集群的需求
  这里还有一个问题需要说明,那就是 Client 会缓存.META.的数据,用来加快访问,既然有缓存,那它什么时候更新?如果.META.更新了,比如 Region1 不在 RerverServer2 上了,被转移 到了 RerverServer3 上。Client 的缓存没有更新会有什么情况?
  其实,Client 的元数据缓存不更新,当.META.的数据发生更新。如上面的例子,由于 Region1 的位置发生了变化,Client 再次根据缓存去访问的时候,会出现错误,当出现异常达到重试次数后就会去.META.所在的 RegionServer 获取最新的数据,如果.META.所在的 RegionServer 也变了,Client 就会去 ZooKeeper 上获取.META.所在的 RegionServer 的最新地址。

5.2 读请求过程

  1. 客户端访问ZooKeeper 获取-ROOT-表或.META.表找到目标数据所在的 RegionServer(就是数据所在的 Region 的主机地址)

  2. 联系 RegionServer 查询目标数据

  3. RegionServer 定位到目标数据所在的 Region,发出查询请求

  4. Region 先在 Memstore 中查找,命中则返回

  5. 如果在 Memstore 中找不到,则在 Storefile 中扫描 为了能快速的判断要查询的数据在不在这个 StoreFile 中,应用了 BloomFilter
    (BloomFilter,布隆过滤器:迅速判断一个元素是不是在一个庞大的集合内,但是他有一个弱点:它有一定的误判率)
    (误判率:原本不存在与该集合的元素,布隆过滤器有可能会判断说它存在,但是,如果布隆过滤器,判断说某一个元素不存在该集合,那么该元素就一定不在该集合内)

5.3 写请求过程

HBase数据写入序列图

  1. Client访问ZooKeeper 获取-ROOT-表或.META.表,根据 RowKey 找到对应的 Region 所在的 RegionServer

  2. Client 向 RegionServer 提交写请求

  3. RegionServer 找到目标 Region

  4. Region 检查数据是否与 Schema 一致

  5. 如果客户端没有指定版本,则获取当前系统时间作为数据版本

  6. 将更新写入HLog

  7. 将更新写入 Memstore

  8. 如果 Hlog 和 Memstore 均写入成功,则这条数据写入成功。在此过程中,如果 Memstore达到阈值,会新开启一个Memstore,把旧的Memstore 中的数据放到一个队列(MapReduce中的实现是环形缓冲区)里面,按先进先出的原则将旧的Memstore依次flush 到 StoreFile(底层是HFile)中。

  9. 当 Storefile 越来越多,会触发 Compact 合并操作,把过多的 Storefile 合并成一个大的Storefile。当 Storefile 越来越大,Region 也会越来越大,达到阈值后,会触发 Split 操作,将 Region 一分为二。

StoreFile 是只读的,一旦创建后就不可以再修改。因此 HBase 的更新/修改其实是不断追加 的操作。
Client 写入 -> 存入 MemStore,一直到 MemStore 满 -> Flush 成一个 StoreFile,直至增长到 一定阈值 -> 触发 Compact 合并操作 -> 多个 StoreFile 合并成一个 StoreFile,同时进行版本 合并和数据删除 -> 当 StoreFiles Compact 后,逐步形成越来越大的 StoreFile -> 单个 StoreFile 大小超过一定阈值后,触发 Split 操作,把当前 Region Split 成 2 个 Region,Region 会下线, 新 Split 出的 2 个孩子 Region 会被 Master 分配到相应的 RegionServer 上,使得原先 1 个 Region 的压力得以分流到 2 个 Region 上由此过程可知,HBase 只是增加数据,有所得更新和删除操作,都是在 Compact 阶段做的,所以,用户写操作只需要进入到内存即可立即返回,从而保证 I/O 高性能。

6 使用Hbase注意点

6.1 Hbase的一些局限性

  1. 在hbase的region迁移过程中,如果发生在hbase节点宕机或者负载均衡时,region从一个region server迁移到另外一个region server,在这个过程中该region不可用。
  2. Hbase发生永久RIT问题
    Hbase节点异常关机导致hdfs上的文件块损坏和丢失,大量Regions 处于Offline状态,无法上线。比较暴力的解决方式是将损坏的文件删除,对系统进系统进行恢复。
  3. hbase的region拆分操作(split)
    region发生split操作时,当前的region会关闭,处于offline状态,客户端到该region的请求都会失败。
  4. 单个region数据过热
    某个region数据被频繁访问,造成单节点资源消耗过高,影响查询性能。

6.2 使用hbase需要注意点

  1. hbase适用的场景通常为非结构化的日志记录,通常写多读少;
  2. 合理设计rowKey和进行预分区,避免单个region数据过热或者频繁的compact和split操作,影响整体性能;
  3. 对于重要的业务数据建议不要只放在Hbase里面,可以在关系型数据库或者ES、Hive里面也存一份,保证数据不丢;
  4. 查询时,禁止使用全表scan,全表scan容易导致内存和cup高升,使节点不可响应甚至异常宕机,亲踩坑,血的教训;
  5. 在做大量数据的插入操作,避免出现递增 rowkey 的 put 操作,如果 put 操作的所有 RowKey 都是递增的,那么试想,当插入一部分数据的时候刚好进行分裂,那么之后的所有数据都开始往分裂后的第二个 Region 插入,就造成了数据热点现象。

7 附录Hbase Shell语法

Hbase Shell

命名描述语法
help‘命名名’查看命令的使用描述help ‘命令名’
whoami我是谁whoami
version返回hbase版本信息version
status返回hbase集群的状态信息
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 ‘表名’, ‘行键’, ‘列族名’
ount统计表中行的数量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

命令例子参考
https://blog.csdn.net/m0_37809146/article/details/91128061

Hbase详细信息可查看其官网
Hbase官网:https://hbase.apache.org/
Hbase中文文档:http://abloz.com/hbase/book.html#shell_tricks

参考文档:
https://blog.csdn.net/lukabruce/article/details/80624619
https://blog.csdn.net/u010270403/article/details/51648462
https://www.cnblogs.com/frankdeng/p/9310278.html

  • 6
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值