前言

本文隶属于专栏《1000个问题搞定大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见1000个问题搞定大数据技术体系

正文

HBase 是构建在 HDFS 之上的,它利用 HDFS 可靠地存储数据文件,其内部则包含 Region 定位、读写流程管理和文件管理等实现,本文从以下几个方面剖析 HBase 内部原理。

1 . Region 定位

HBase 支持 put , get , delete 和 scan 等基础操作,所有这些操作的基础是 region 定位

给定一个 rowkey 或 rowkey 区间,如何获取 rowkey 所在的 RegionServer 地址?

region 定位基本步骤如下:

  1. 客户端与 ZooKeeper 交互,查找 hbase:meta 系统表所在的 Regionserver , hbase:meta 表维护了每个用户表中 rowkey 区间与 Region 存放位置的映射关系,具体如下:
    rowkey : table name , start key , region id
    value : RegionServer 对象(保存了 RegionServer 位置信息等)
  2. 客户端与 hbase:meta 系统表所在 RegionServer 交互,获取 rowley 所在的 RegionServer
  3. 客户端与 rowkey 所在的 RegionServer 交互,执行该 rowkey 相关操作。

在这里插入图片描述

需要注意的是,客户端首次执行读写操作时才需要定位 hbase:meta 表的位置,之后会
将其缓存到本地,除非因 region 移动导致缓存失效,客户端才会重新读取 hbase:meta 表位置,并更新缓存。

2. RegionServer 内部关键组件

关键组件 名称解释 主要功能
BlockCache 读缓存 负责缓存频繁读取的数据,采用了 LRU 置换策略。
MemStore 写缓存 负责暂时缓存未写入磁盘的数据,并在写入磁盘前对数据排序。每个 region 内的每个 columnfamily 拥有一个 MemStore 。
HFile 一种支持多级索引的数据存储格式 用于保存 HBase 表中实际的数据,所有 HFile 均保存在 HDFS 中。
WAL WriteAheadLog ,保存在 HDFS 上的日志文件 用于保存那些未持久化到 HDFS 中的 HBase 数据,以便 RegionServer 宕机后恢复这些数据。

3. RegionServer 读写操作

HBase中最重要的两个操作是写操作和读操作。

写流程

为了提到 HBase 写效率,避免随机写性能低下, RegionServer 将所有收到的写请求暂时写入内存,之后再顺序刷新到磁盘上,进而将随机写转化成顺序写以提升性能,具体流程如下:

  1. RegionServer 收到写请求后,将写入的数据以追加的方式写入 HDFS 上的日志文件,该日志被称为 WriteAheadLog ( WAL )。WAL 主要作用是当 RegionServer 突然宕机后重新恢复丢失的数据。
  2. RegionServer 将数据写入内存数据结构 MemStore 中,之后通知客户端数据写入成功。
  3. 当 MemStore 所占内存达到一定阈值后, RegionServer 会将数据顺序刷新到 HDFS 中,保存成 HFile (一种带多级索引的文件格式)格式的文件。

读流程

由于写流程可能使得数据位于内存中或者磁盘上,因此读取数据时,需要从多个数据存放位置中寻找数据,包括读缓存 BlockCache 、写缓存 MemStore ,以及磁盘上的 HFile 文件(可能有多个),并将读到的数据合并在一起返回给用户,具体流程如下:

  1. 扫描器査找写缓存 MemCache ,它内部缓存了最近写入的数据。
  2. 扫描器查找读缓存 BlockCache ,它内部缓存了最近读取过的数据
  3. 如果在 BlockCache 和 MemCache 中未找到目标数据, HBase 将读取 HFile 中的数据,以获取需要的数据。

4 . MemStore 与 HFile

MemStore

MemStore 负责将最近写入的数据缓存到内存中,它是一个有序 Key / Value 内存存储格式,每个 colum family 拥有一个 MemStore。

在这里插入图片描述
当 RegionServer 收到写请求的时候(write request),RegionServer会将请求转至相应的Region。

每一个Region都存储着一些列(a set of rows)。

根据其列族的不同,将这些列数据存储在相应的列族中(Column Family)。

不同的Column Family中的数据存储在各自的HStore中,HStore由一个MemStore及一系列HFile组成。

MemStore位于RegionServer的主内存中,而HFiles 被写入到HDFS中。

当RegionServer处理写请求的时候,数据首先写入到MemStore,然后当到达一定的阀值的时候,MemStore中的数据会被刷到HFile中。

用到 MemStore 最主要的原因是:

存储在HDFS上的数据需要按照row key 排序。

而HDFS本身被设计为顺序读写(sequential reads/writes),不允许修改。

这样的话,HBase就不能够高效的写数据,因为要写入到HBase的数据不会被排序,这也就意味着没有为将来的检索优化。

为了解决这个问题,HBase将最近接收到的数据缓存在内存中(in MemStore),在持久化到HDFS之前完成排序,然后再快速的顺序写入HDFS。

需要注意的一点是实际的HFile中,不仅仅只是简单地排序的列数据的列表

除了解决“无序”问题外,Memstore还有一些其他的好处,例如:

  1. 作为一个内存级缓存,缓存最近增加数据。一种显而易见的场合是,新插入数据总是比老数据频繁使用。
  2. 在持久化写入之前,在内存中对Rows/Cells可以做某些优化。比如,当数据的version被设为1的时候,对于某些Column Family的一些数据,Memstore缓存了数个对该Cell的更新,在写入HFile的时候,仅需要保存一个最新的版本就好了,其他的都可以直接抛弃。

有一点需要特别注意:每一次Memstore的flush,会为每一个Column Family创建一个新的HFile。 在读方面相对来说就会简单一些:HBase首先检查请求的数据是否在Memstore,不在的话就到HFile中查找,最终返回merged的一个结果给用户。

HBase MemStore关注要点:

迫于以下几个原因,HBase用户或者管理员需要关注Memstore并且要熟悉它是如何被使用的:

  1. Memstore有许多配置可以调整以取得好的性能和避免一些问题。HBase不会根据用户自己的使用模式来调整这些配置,你需要自己来调整。
  2. 频繁的Memstore flush会严重影响HBase集群读性能,并有可能带来一些额外的负载。
  3. Memstore flush的方式有可能影响你的HBase schema设计

HFile

MemStore 中的数据量达到一定阈值后,会被刷新到 HDFS 文件中,保存成 HFile 格式。

HFile 是 GoogleSSTable ( Sorted String Table , Google BigTable 中用到的存储格式)的开源实现,它是一种有序 Key / Value 磁盘存储格式,带有多级索引,以方便定位数据, HFile 中的多级索引类似于 B +树。

HFile 格式如图所示。

在这里插入图片描述

Block 段 说明 是否可选
Data Block 段 用来保存表中的数据,这部分可以被压缩。
Meta Block 段 用来保存用户自定义的kv段,可以被压缩。
File Info 段 用来保存HFile的元信息,本能被压缩,用户也可以在这一部分添加自己的元信息。
Data Block Index段 用来保存Meta Blcok的索引。Data Block Index采用LRU机制淘汰。
Trailer 这一段是定长的。保存了每一段的偏移量,读取一个HFile时,会首先读取Trailer,Trailer保存了每个段的起始位置(段的Magic Number用来做安全check),然后,DataBlock Index会被读取到内存中,这样,当检索某个key时,不需要扫描整个HFile,而只需从内存中找到key所在的block,通过一次磁盘io将整个 block读取到内存中,再找到需要的key。

HFile的Data Block,Meta Block通常采用压缩方式存储,压缩之后可以大大减少网络IO和磁盘IO,随之而来的开销当然是需要花费cpu进行压缩和解压缩。目标HFile的压缩支持两种方式:gzip、lzo。

参考文献

《大数据技术体系详解:原理、架构与实战》董西成著

hbase存储结构介绍及hbase各种概念

深入理解HBase Memstore

上一篇 下一篇