头图

HBase的存储结构分为逻辑存储结构与物理存储结构,并且HBase通过逻辑存储结构来管理物理存储结构。而最终物理存储对应的文件又是存储在HDFS之上。而HBase的物理存储结构主要包括StoreFile、HFile和HLog日志。视频讲解如下:
https://www.bilibili.com/video/BV1T3BrYcE8a/?aid=113529894410...

一、 数据文件HFile

HBase会定时刷新MemStore中的数据从而生成StoreFile。Store File底层又是以HFile的格式保存在HDFS上。因此从根本上说,HBase的物理存储结构指的是HFile。视频讲解如下:
https://www.bilibili.com/video/BV1CKz8YZE6K/?aid=113558952089...

通过下面的方式可以查看员工表emp所对应的HFile。

(1)执行HDFS命令查看表emp对应的HDFS目录。

hdfs dfs -lsr /hbase/data/default/emp

# 输出的信息如下:
/hbase/data/default/emp/.tabledesc
/hbase/data/default/emp/.tabledesc/.tableinfo.0000000001
/hbase/data/default/emp/.tmp
/hbase/data/default/emp/459580d88e589ba8194336a7c578876f
/hbase/data/default/emp/459580d88e589ba8194336a7c578876f/.regioninfo
/hbase/data/default/emp/459580d88e589ba8194336a7c578876f/info
/hbase/data/default/emp/459580d88e589ba8194336a7c578876f/info/da157b802d4f41849363fda1956926bd
/hbase/data/default/emp/459580d88e589ba8194336a7c578876f/money
/hbase/data/default/emp/459580d88e589ba8194336a7c578876f/money/ba4e83b1887144d588f71cfec7a437c3

(2)可以emp表上info列族的数据信息。

hbase hfile -p -f \
/hbase/data/default/emp/459580d88e589ba8194336a7c578876f/info/da157b802d4f41849363fda1956926bd

# 输出的信息如下:
K: 7369/info:deptno/1649559894497/Put/vlen=2/seqid=4 V: 20
K: 7369/info:ename/1649559894497/Put/vlen=5/seqid=4 V: SMITH
K: 7369/info:hiredate/1649559894497/Put/vlen=10/seqid=4 V: 1980/12/17
K: 7369/info:job/1649559894497/Put/vlen=5/seqid=4 V: CLERK
K: 7369/info:mgr/1649559894497/Put/vlen=4/seqid=4 V: 7902
K: 7499/info:deptno/1649559894497/Put/vlen=2/seqid=4 V: 30
K: 7499/info:ename/1649559894497/Put/vlen=5/seqid=4 V: ALLEN
K: 7499/info:hiredate/1649559894497/Put/vlen=9/seqid=4 V: 1981/2/20
K: 7499/info:job/1649559894497/Put/vlen=8/seqid=4 V: SALESMAN
K: 7499/info:mgr/1649559894497/Put/vlen=4/seqid=4 V: 7698
K: 7521/info:deptno/1649559894497/Put/vlen=2/seqid=4 V: 30
K: 7521/info:ename/1649559894497/Put/vlen=4/seqid=4 V: WARD
K: 7521/info:hiredate/1649559894497/Put/vlen=9/seqid=4 V: 1981/2/22
K: 7521/info:job/1649559894497/Put/vlen=8/seqid=4 V: SALESMAN
K: 7521/info:mgr/1649559894497/Put/vlen=4/seqid=4 V: 7698
K: 7566/info:deptno/1649559894497/Put/vlen=2/seqid=4 V: 20
K: 7566/info:ename/1649559894497/Put/vlen=5/seqid=4 V: JONES
K: 7566/info:hiredate/1649559894497/Put/vlen=8/seqid=4 V: 1981/4/2
......

从上面输出的信息可以看出,HFile是一个Key-Value格式的数据存储文件,并最终以二进制的形式存储在了HDFS上。一个Store File对应着一个HFile。HFile的格式如下图所示。
image.png

从HFile的格式可以看出,HFile分为了以下六个部分:

  • Data块:该块保存了表中的数据,并且这部分可以被压缩以节约HFile所占用的存储空间。
  • Meta块:该块保存了用户自定义的Key-Value数据。与Data块一样也可以被压缩,但区别是Meta块不是必须存在。
  • File Info块:HBase使用File Info块来存储HFile的元信息,且这一部分的元信息是不能被压缩的。HBase也允许用户利用File Info块来存储自定义的元信息数据。
  • Data Index块:该块包含了Data块的索引信息。Data块中的每一条索引信息都会被记录到Data Index块的Key中。
  • Meta Index块:该块包含了Meta块的索引信息。
  • Trailer块:Trailer块保存了一个块的偏移量的地址,这里的块包括:Data块、Meta块 、File Info块、Data Index块和Meta Index块。读取一个HFile的数据时,HBase会首先读取Trailer中的信息以确定每一个块的位置。
提示:HFile文件是不定长的,其中长度固定的只有其中的两块:Trailer和File Info。其中Trailer中有指针指向其他数据块的起始点;而File Info记录了HFile文件的一些元信息。在Data Index和Meta 块中则记录了每个数据块和元数据块的起始位置。另外,HFile的Data块和Meta块通常采用压缩方式存储,压缩之后可以大大减少网络I/O和磁盘I/O,随之而来的开销则是需要花费CPU进行压缩和解压缩。

二、 预写日志文件HLog

HBase采用预写日志的方式写入数据。预写日志意为Write Ahead Log,简称WAL。它类似Oracle数据库中的Redo log或者MySQL中的Binlog。HBase会将WAL日志保存到HLog日志文件中,Hlog文件将记录数据的所有变更。一旦数据丢失或者损坏,HBase就可以从HLog中进行恢复。

视频讲解如下:

https://www.bilibili.com/video/BV1CmzEYcEWU/?aid=113570025052...

提示:HLog与Region Server相对应,即:每个Region Server只维护一个HLog。换句话说,同一个Region Server上的Region会使用同一个HLog。这样不同Region的WAL日志会混在一起。这样做的优点是可以减少磁盘寻址次数,从而可以提高对表的写性能;但是缺点是如果一台Region Server出现故障宕机并下线,为了在其他Region Server上执行恢复则需要要HLog进行拆分,然后分发到其它Region Server上进行恢复,这将增加HBase恢复时的复杂度。

在默认情况下,HLog都被保存到了HDFS的/hbase/WALs/下;而在HDFS的/hbase/oldWALs目录下保存的是已经过期的WAL日志。既然HLog保存了HDFS上,因此可以直接使用相关的命令来查看它。操作命令如下:

(1)使用HDFS命令查看目录/hbase/WALs/。

hdfs dfs -lsr /hbase/WALs/

# 输出的信息如下:
drwxr-xr-x ......
/hbase/WALs/localhost,16020,1649679358560
-rw-r--r-- ......
/hbase/WALs/localhost,16020,1649679358560/localhost%2C16020%2C1649679358560.1649682968518
-rw-r--r-- ......
/hbase/WALs/localhost,16020,1649679358560/localhost%2C16020%2C1649679358560.meta.1649682968557.meta

(2)使用HBase提供的命令查看HLog日志的内容。

hbase wal -j \
/hbase/WALs/localhost,16020,1649679358560/localhost%2C16020%2C1649679358560.1649682968518

# 输出的信息如下:
......
position: 600, {
    "sequence": "4",
    "region": "d6def4cd3110ca597ad6057936e2b898",
    "actions": [{
        "qualifier": "ename",
        "vlen": 4,
        "row": "7839",
        "family": "info",
        "value": "KING",
        "timestamp": "1649684058161",
        "total_size_sum": "88"
    }],
    "table": {
        "name": [101, 109, 112],
        "nameAsString": "emp",
        "namespace": [100, 101, 102, 97, 117, 108, 116],
        "namespaceAsString": "default",
        "qualifier": [101, 109, 112],
        "qualifierAsString": "emp",
        "systemTable": false,
        "hashCode": 100552
    }
}
edit heap size: 128
......
提示:从HLog日志中的action可以看出,客户端往列族info的ename列上插入了一个数据,即:KING。

三、 HBase写数据流程

在了解到了HBase的数据文件和预写日志文件后,便可以讨论HBase写数据的流程。与Oracle和MySQL类似,HBase在写入数据的时候也是先写入日志。只要预写日志WAL写入成功,客户端写入数据就成功,如下图所示。
image.png

当HBase的客户端发出一个写操作请求时,也就是执行put操作,HBase进行处理的第一步是将数据写入HBase的WAL中。WAL文件是顺序写入的,也就是所有新写入的日志会被写到WAL文件的末尾。当日志被成功写入WAL后,HBase将数据写入MemStore。如果此时MemStore出现了问题,写入的数据是会丢失的。这时候WAL就可以被用来恢复尚未写入HBase中的数据。当MemStore中的数据达到一定的量级后,HBase会执行Flush的操作将内存中的数据一次性地写入HFile中。

视频讲解如下:
https://www.bilibili.com/video/BV1H3UdY9EsZ/?aid=113524475042...

提示:当HBase执行Flush操作将内存中的数据写入HFile数据文件后,便可以清空WAL的预写日志。但是在生产环境中,一般建议保留所有的WAL日志。这样做的目的就是为了当HFile数据文件丢失或者损坏后,可以使用WAL日志来进行数据的恢复。

赵渝强老师
36 声望18 粉丝

20年以上的IT行业从业经历,清华大学计算机软件工程专业毕业,京东大学大数据学院院长,Oracle中国有限公司高级技术顾问;曾在BEA、甲骨文、摩托罗拉等世界500强公司担任高级软件架构师或咨询顾问等要职,精通大...