1.LSMTree
LSM 树(log-structured merge-tree)。输入数据首先被存储在日志文件(HLog), 这些文件内的数据完全有序。当有日志文件被修改时,对应的更新会被先保存在内存中来加 速查询。当系统经历过许多次数据修改,且内存(存放数据)空间被逐渐被占满后,LSM 树会把有序的“键-记录”对写到磁盘中,同时创建一个新的数据存储文件(storefile)。 此时,因为最近的修改都被持久化了,内存中保存的最近更新就可以被丢弃了。
存储文件的组织与 B 树相似,不过其为磁盘顺序读取做了优化,所有节点都是满的并 按页存储。修改数据文件的操作通过滚动合并完成,也就是说,系统将现有的页与内存刷写 数据混合在一起进行管理,直到数据块达到它的容量(region 的阈值,达到阈值进行 region 的切割,重新分配 hregionserver)。 多次数据刷写之后会创建许多数据存储文件,后台线程就会自动将小文件聚合成大文 件,这样磁盘查找就会被限制在少数几个数据存储文件中。磁盘上的树结构也可以拆分成独 立的小单元,这样更新就可以被分散到多个数据存储文件中。所有的数据存储文件都按键排 序,所以没有必要在存储文件中为新的键预留位置。 查询时先查找内存中的存储,然后再查找磁盘上的文件。这样在客户端看来数据存储文 件的位置是透明的。
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 实例来处理。
第一步是要决定数据是否需要写到由 HLog 类实现的预写日志中。WAL 是标准的 Hadoop SequenceFile,并且存储了 HLogKey 实例。这些键包括序列号和实际数据, 所以在服务器崩溃时可以回滚还没有持久化的数据。
一旦数据被写入到 WAL 中,数据就会被放到 MemStore 中。同时还会检查 MemStore 是 否 已 经 满 了 , 如 果 满 了 , 就 会 被 请 求 刷 写 到 磁 盘 中 去 。 刷 写 请 求 由 另 外 一 个 HRegionServer 的线程处理,它会把数据写成 HDFS 中的一个新 HFile。同时也会保存 最后写入的序号,系统就知道哪些数据现在被持久化了。
4.读流程
- Client 访问 Zookeeper,查找 hbase:meta 表位置,看他在哪个 regionserverR 上。
- Client 访问 regionserverR 上 hbase:meta 表中的数据,查找要操作 rowkey 的所在 表对应 region 所在的 regionserverX
- Client 读取 regionserverX 上的 region 数据 定位到真正的数据所在的 region 的时候,按照下述步骤进行操作: 先查找 memstore,如果 memstore 没有,查找 blockcache;如果 blockcache 没有,则查找 storefile 的数据,同时将数据缓存与 blockcache 中