上图是HBase的存储架构图。
由上图可以知道,客户端是通过Zookeeper找到HMaster,然后再与具体的Hregionserver进行沟通读写数据的。
具体到物理实现,细节包括以下这些:
1、客户端在zookeeper中找到存储了-ROOT-表的RegionServer
2、在-ROOT-中找到.META.表的位置
3、在.META.表中找到存储了指定rowkey的HRegionServer位置
4、客户端连接该机器进行数据读写
首先要清楚HBase在hdfs中的存储路径,以及各个目录的作用。在hbase-site.xml 文件中,配置项 <name> hbase.rootdir</name> 默认 “/hbase”,就是hbase在hdfs中的存储根路径。以下是hbase0.96版本的个路径作用。1.0以后的版本请参考这里: https://blog.bcmeng.com/post/hbase-hdfs.html
hbase在hdfs中的存储路径1、/hbase/.archive
HBase 在做 Split或者 compact 操作完成之后,会将 HFile 移到.archive 目录中,然后将之前的 hfile 删除掉,该目录由 HMaster 上的一个定时任务定期去清理。
2、/hbase/.corrupt
存储HBase损坏的日志文件,一般都是为空的。
3、/hbase/.hbck
HBase 运维过程中偶尔会遇到元数据不一致的情况,这时候会用到提供的 hbck 工具去修复,修复过程中会使用该目录作为临时过度缓冲。
4、/hbase/logs
HBase 是支持 WAL(Write Ahead Log) 的,HBase 会在第一次启动之初会给每一台 RegionServer 在.log 下创建一个目录,若客户端如果开启WAL 模式,会先将数据写入一份到.log 下,当 RegionServer crash 或者目录达到一定大小,会开启 replay 模式,类似 MySQL 的 binlog。
5、/hbase/oldlogs
当.logs 文件夹中的 HLog 没用之后会 move 到.oldlogs 中,HMaster 会定期去清理。
6、/hbase/.snapshot
hbase若开启了 snapshot 功能之后,对某一个用户表建立一个 snapshot 之后,snapshot 都存储在该目录下,如对表test 做了一个 名为sp_test 的snapshot,就会在/hbase/.snapshot/目录下创建一个sp_test 文件夹,snapshot 之后的所有写入都是记录在这个 snapshot 之上。
7、/hbase/.tmp
当对表做创建或者删除操作的时候,会将表move 到该 tmp 目录下,然后再去做处理操作。
8、/hbase/hbase.id
它是一个文件,存储集群唯一的 cluster id 号,是一个 uuid。
9、/hbase/hbase.version
同样也是一个文件,存储集群的版本号,貌似是加密的,看不到,只能通过web-ui 才能正确显示出来
10、-ROOT-
该表是一张的HBase表,只是它存储的是.META.表的信息。通过HFile文件的解析脚本 hbase org.apache.hadoop.hbase.io.hfile.HFile -e -p -f 可以查看其存储的内容,如下所示:
hbase org.apache.hadoop.hbase.io.hfile.HFile -e -p -f /hbase/-ROOT-/70236052/info/604443e666684d8ca2b3f81d662df6c3
解析内容如下:
K: .META.,,1/info:server/1504514627434/Put/vlen=14/ts=0 V: dchbase2:60020
K: .META.,,1/info:serverstartcode/1504514627434/Put/vlen=8/ts=0 V: \x00\x00\x01]\xA0\xAA\x04A
以上可以看出,-ROOT-表记录的.META.表的所在机器是dchbase2,与web界面看到的一致:
META表信息
11、.META.
通过以上表能找到.META.表的信息,该表也是一张hbase表,通过以上命令,解析其中一个region:
hbase org.apache.hadoop.hbase.io.hfile.HFile -e -p -f /hbase/.META./1028785192/info/2de4d44c7a2e4d86928f3a075ad8471b
解析内容如下:
K: adt_app_channel,,1439437512159.cd311ca186e08ee5aeaa4cc188121ba3./info:server/1498474805942/Put/vlen=14/ts=0 V: dchbase3:60020
K: dc_debug_log,EAA47BA32FD980D20E2DB2D19050A51D|2|638069812,1509447378983.3642c1134e2dcd810f48a0b0409f60b3./info:server/1509531353681/Put/vlen=14/ts=0 V: dckafka1:60020
K: dc_debug_log,EAA47BA32FD980D20E2DB2D19050A51D|2|638069812,1509447378983.3642c1134e2dcd810f48a0b0409f60b3./info:server/1509447380418/Put/vlen=14/ts=0 V: dckafka2:60020
以上可以看出,adt_app_channel表的数据记录在dchbase3这台reginserver上,也与界面一致,如果有多个region,则会在表名后面加上rowkey的范围:
普通表信息
通过以上描述,只要找到-ROOT-表的信息,就能根据rowkey找到对应的数据,那-ROOT-在哪里找呢?从本文一开始的图中可以知道,就是在zookeeper中找的。进入zookeeper命令行界面:
./hbase zkcli -server dcnamenode1:2181(hbase自带zk)
[zk: dcnamenode1:2181(CONNECTED) 3] get /hbase/root-region-server
12439@dchbase3dchbase3,60020,1498474547671 ###注意该行信息
cZxid = 0x2f0001c2c0
ctime = Mon Jun 26 19:00:04 CST 2017
mZxid = 0x2f0001c2c0
mtime = Mon Jun 26 19:00:04 CST 2017
pZxid = 0x2f0001c2c0
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 47
numChildren = 0
[zk: dcnamenode1:2181(CONNECTED) 4]
可以看出-ROOT-表存储在 dchbase3 机器中,对应界面如下:
ROOT表信息
以上就是HBase客户端根据指定的rowkey从zookeeper开始找到对应的数据的过程。
那在Region下HBase是如何存储数据的呢?
以下就具体操作一张表,查询对应的HFile文件,看HBase的数据存储过程。
在HBase创建一张表 test7,并插入一些数据,如下命令:
create 'test7','info' #创建表
put 'test7','100',info:name','yann'
put 'test7','100',info:age','12'
put 'test7','200',info:name','yann'
put 'test7','200',info:age','15'
查看wal日志,通过 hbase org.apache.hadoop.hbase.regionserver.wal.HLog --dump -p 命令可以解析HLog文件,内容如下:
hbase org.apache.hadoop.hbase.regionserver.wal.HLog --dump -p /hbase/.logs/server1,60020,1511338186832/server1%2C60020%2C1511338186832.1511593793118
Sequence 68663206 from region 1028785192 in table .META.
Action:
row: test7,,1511593978551.33ba34be458d2b18f97d7b7ccc89468e.
column: info:regioninfo
at time: Sat Nov 25 15:12:58 CST 2017
value: \x01\x00\x00\x00\x00\x01_\xF2\x05\xAA\xB76test7,,1511593978551.33ba34be458d2b18f97d7b7ccc89468e.\x00\x00\x05test7$\xB2\xBEV
Sequence 68663207 from region 1028785192 in table .META.
Action:
row: test7,,1511593978551.33ba34be458d2b18f97d7b7ccc89468e.
column: info:server
at time: Sat Nov 25 15:12:58 CST 2017
value: server1:60020
Action:
row: test7,,1511593978551.33ba34be458d2b18f97d7b7ccc89468e.
column: info:serverstartcode
at time: Sat Nov 25 15:12:58 CST 2017
value: \x00\x00\x01_\xE2\xC6\x98P
Sequence 68663208 from region 33ba34be458d2b18f97d7b7ccc89468e in table test7
Action:
row: 100
column: info:name
at time: Sat Nov 25 15:13:33 CST 2017
value: yann
Sequence 68663209 from region 33ba34be458d2b18f97d7b7ccc89468e in table test7
Action:
row: 100
column: info:age
at time: Sat Nov 25 15:13:41 CST 2017
value: 12
Sequence 68663210 from region 33ba34be458d2b18f97d7b7ccc89468e in table test7
Action:
row: 200
column: info:name
at time: Sat Nov 25 15:13:47 CST 2017
value: yann
Sequence 68663211 from region 33ba34be458d2b18f97d7b7ccc89468e in table test7
Action:
row: 200
column: info:age
at time: Sat Nov 25 15:13:51 CST 2017
value: 12
Sequence 68663212 from region 33ba34be458d2b18f97d7b7ccc89468e in table test7
Action:
row: METAROW
column: METAFAMILY:
at time: Sat Nov 25 15:14:19 CST 2017
value: HBASE::CACHEFLUSH
Sequence 68663213 from region 33ba34be458d2b18f97d7b7ccc89468e in table test7
Action:
row: 200
column: info:age
at time: Sat Nov 25 15:15:19 CST 2017
value: 15
查看HFile文件,内容如下:
hbase org.apache.hadoop.hbase.io.hfile.HFile -e -p -f /hbase_1/test7/33ba34be458d2b18f97d7b7ccc89468e/info/caeaaf25659242c19e5f4f983c5206ee
K: 100/info:age/1511594021359/Put/vlen=2/ts=0 V: 12
K: 100/info:name/1511594013569/Put/vlen=4/ts=0 V: yann
K: 200/info:age/1511594031440/Put/vlen=2/ts=0 V: 12
K: 200/info:name/1511594027562/Put/vlen=4/ts=0 V: yann
由此可见,HFile文件就是存储HBase的KV对,其中Key的各个字段包含了的信息如下:
100/info:age/1511594021359/Put/vlen=2/ts=0
rowkey / columnFamily:column / timestamp / Option / len / ts
由于hbase把cf和column都存储在HFile中,所以在设计的时候,这两个字段应该尽量短,以减少存储空间。
但删除一条记录的时候,HBase会怎么操作呢?执行以下命令:
deleteall 'test7','200'
删除了rowkey为200的记录,查看hdfs,原来的HFile并没有改变,而是生成了一个新的HFile,内容如下:
K: 100/info:/1511594203116/DeleteFamily/vlen=0/ts=0 V:
所以在HBase中,删除一条记录并不是修改HFile里面的内容,而是写新的文件,待HBase做合并的时候,把这些文件合并成一个HFile,用时间比较新的文件覆盖旧的文件。HBase这样做的根本原因是,HDFS不支持修改文件。
网友评论