1.LSMTree

LSM 树(log-structured merge-tree)。输入数据首先被存储在日志文件(HLog), 这些文件内的数据完全有序。当有日志文件被修改时,对应的更新会被先保存在内存中来加 速查询。当系统经历过许多次数据修改,且内存(存放数据)空间被逐渐被占满后,LSM 树会把有序的“键-记录”对写到磁盘中,同时创建一个新的数据存储文件(storefile)。 此时,因为最近的修改都被持久化了,内存中保存的最近更新就可以被丢弃了。
HBase 读写流程_b树
存储文件的组织与 B 树相似,不过其为磁盘顺序读取做了优化,所有节点都是满的并 按页存储。修改数据文件的操作通过滚动合并完成,也就是说,系统将现有的页与内存刷写 数据混合在一起进行管理,直到数据块达到它的容量(region 的阈值,达到阈值进行 region 的切割,重新分配 hregionserver)。 多次数据刷写之后会创建许多数据存储文件,后台线程就会自动将小文件聚合成大文 件,这样磁盘查找就会被限制在少数几个数据存储文件中。磁盘上的树结构也可以拆分成独 立的小单元,这样更新就可以被分散到多个数据存储文件中。所有的数据存储文件都按键排 序,所以没有必要在存储文件中为新的键预留位置。 查询时先查找内存中的存储,然后再查找磁盘上的文件。这样在客户端看来数据存储文 件的位置是透明的。
HBase 读写流程_b树_02

2.大合并(major)和小合并(minor)

随着 memstore 的刷写会生成很多磁盘文件。如果文件的数目达到阈值,合并 (compaction)过程将把它们合并成数量更少的体积更大的文件。这个过程持续到这些文 件中最大的文件超过配置的最大存储文件大小,此时会触发一个 region 拆分。 minor 合并负责重写最后生成的几个文件到一个更大的文件中。文件数量是由 hbase.hstore.compaction.min 属性设置的。它的默认值为 3,并且最小值需要大于或等 于 2。过大的数字将会延迟 minor 合并的执行,同时也会增加执行时消耗的资源及执行的 时 间 。 minor 合 并 可 以 处 理 的 最 大 文 件 数 量 默 认 为 10 , 用 户 可 以 通 过 hbase.hstore.compaction.max 来配置。(课后思考?) hbase.hstore.compaction.min.size(默认设置为 region 的 memstore 刷写大小)和 hbase.hstore.compaction.max.size(默认设置为 Long.MAX_VALUE)配置项属性进一步 减少了需要合并的文件列表。任何比最大合并大小大的文件都会被排除在外。 major 合并:它们把所有文件压缩成一个单独的文件。默认情况下,major 合并间隔是 7 天,看情况随机的加上或减去 4.8 小时.
如果要删除数据,不会直接修改 storefile,因为 hadoop 不允许修改。hbase 会将删 除的数据标志为已删除(给该数据添加墓碑标记),如果添加了墓碑标记,查询不到该数据。 在大合并的时候,将标记了墓碑标记的数据真正删除

3.写流程

当用户向 HRegionServer 发起 HTable.put(Put)请求时,其会将请求交给对应的 HRegion 实例来处理。
HBase 读写流程_hbase_03
第一步是要决定数据是否需要写到由 HLog 类实现的预写日志中。WAL 是标准的 Hadoop SequenceFile,并且存储了 HLogKey 实例。这些键包括序列号和实际数据, 所以在服务器崩溃时可以回滚还没有持久化的数据。

一旦数据被写入到 WAL 中,数据就会被放到 MemStore 中。同时还会检查 MemStore 是 否 已 经 满 了 , 如 果 满 了 , 就 会 被 请 求 刷 写 到 磁 盘 中 去 。 刷 写 请 求 由 另 外 一 个 HRegionServer 的线程处理,它会把数据写成 HDFS 中的一个新 HFile。同时也会保存 最后写入的序号,系统就知道哪些数据现在被持久化了。

4.读流程

HBase 读写流程_数据存储_04

  1. Client 访问 Zookeeper,查找 hbase:meta 表位置,看他在哪个 regionserverR 上。
  2. Client 访问 regionserverR 上 hbase:meta 表中的数据,查找要操作 rowkey 的所在 表对应 region 所在的 regionserverX
  3. Client 读取 regionserverX 上的 region 数据 定位到真正的数据所在的 region 的时候,按照下述步骤进行操作: 先查找 memstore,如果 memstore 没有,查找 blockcache;如果 blockcache 没有,则查找 storefile 的数据,同时将数据缓存与 blockcache 中