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的格式如下图所示。
从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写入成功,客户端写入数据就成功,如下图所示。
当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日志来进行数据的恢复。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。