HBase表数据倾斜治理_HFile结构与Snapshot结构

HBase表数据倾斜治理_HFile结构与Snapshot结构

1.HFile结构

1.1 HFile逻辑结构

hfile v2在逻辑上的结构主要分为四个部分:

  • 扫描时会被读取的部分;
  • 扫描时不会被读取的部分;
  • regionserver启动时会被加载到内存中的部分;
  • 尾部:主要记录hfile的版本信息、各部分的offset。

1.2 HFile物理结构

hfile在物理存储上被切分成一个个大小相等的block块,block块的大小可以在建表时通过参数blocksize设置,默认是64kb。

组成hfile的block块的种类主要有8种,每种block块中保存不同种类的信息,但是每种block的物理结构都相同,如下图。

这8种block的简介如下,不同种类的block主要是blockdata内部结构不同,有的存储用户数据,有的存储索引数据等。

1.3 Trailer Block

读取某个hfile的步骤:

  • 首先读取version版本信息到内存,根据version版本信息确定trailer的长度;
  • 读取trailer block到内存,获取LoadOnOpen区域的起点和终点偏移量;
  • 读取LoadOnOpen区域数据到内存,接下来就可以根据布隆过滤器和索引直接定位目标数据block块。

1.4 BloomFilter Meta Block & Bloom Block

布隆过滤器用于帮助get操作和scan操作剔除不会用到的hfile文件,减少实际IO次数,提高随机读性能。

根据rowkey进行查询时,首先将布隆过滤器函数及为位数组block加载进内存,然后进行hash映射,如果对应数组位上存在0,则说明该hfile中不存在该rowkey,不用进行后续数据加载。

1.5 hbase命令查看hfile

在hbase配置环境下可以直接使用hbase语法解析查看hfile文件。语法如下:

1
hbase org.apache.hadoop.hbase.io.hfile.HFile -f hfile的hdfs存储路径 -e -p -m -s

应用实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
E:\HBase\hbase\bin>hbase org.apache.hadoop.hbase.io.hfile.HFile -f hdfs://localhost:9005/hbase/data/default/fellowjava/674dcf9d985c1c583ab5a4a0b23f7a37/d/7790adf6cac8430e8b12b8017ef9b67b -e -p -m -s

2022-05-20 00:51:16,731 INFO [main] hfile.CacheConfig: Created cacheConfig: CacheConfig:disabled
K: ,\x1D\xA0\x002022/4/4/d:Work/1652515746619/Put/vlen=6/seqid=4 V: \xE5\xAE\x9E\xE4\xB9\xA0
K: ,\x1D\xA0\x002022/4/4/d:name/1652515746619/Put/vlen=11/seqid=4 V: zengqingfan
K: ,\x1D\xA0\x002022/4/4/d:sex/1652515746619/Put/vlen=3/seqid=4 V: \xE7\x94\xB7
K: ?\x03H@2022/3/18/d:Work/1652515746619/Put/vlen=6/seqid=4 V: \xE6\xAD\xA3\xE5\xBC\x8F
K: ?\x03H@2022/3/18/d:name/1652515746619/Put/vlen=5/seqid=4 V: lijun
K: ?\x03H@2022/3/18/d:sex/1652515746619/Put/vlen=3/seqid=4 V: \xE7\x94\xB7
K: |I\x00\x002022/4/11/d:Work/1652515746619/Put/vlen=6/seqid=4 V: \xE5\xAE\x9E\xE4\xB9\xA0
K: |I\x00\x002022/4/11/d:name/1652515746619/Put/vlen=10/seqid=4 V: lijiazheng
K: |I\x00\x002022/4/11/d:sex/1652515746619/Put/vlen=3/seqid=4 V: \xE7\x94\xB7
K: \xE3\xA9\x00\x002022/4/24/d:Work/1652515746619/Put/vlen=6/seqid=4 V: \xE6\xAD\xA3\xE5\xBC\x8F
K: \xE3\xA9\x00\x002022/4/24/d:name/1652515746619/Put/vlen=12/seqid=4 V: jiazhengyang
K: \xE3\xA9\x00\x002022/4/24/d:sex/1652515746619/Put/vlen=3/seqid=4 V: \xE7\x94\xB7
K: \xF1\xC6$\x002022/3/16/d:Work/1652515746619/Put/vlen=6/seqid=4 V: \xE6\xAD\xA3\xE5\xBC\x8F
K: \xF1\xC6$\x002022/3/16/d:name/1652515746619/Put/vlen=9/seqid=4 V: qiuyuchen
K: \xF1\xC6$\x002022/3/16/d:sex/1652515746619/Put/vlen=3/seqid=4 V: \xE7\x94\xB7
Block index size as per heapsize: 400
reader=hdfs://localhost:9005/hbase/data/default/fellowjava/674dcf9d985c1c583ab5a4a0b23f7a37/d/7790adf6cac8430e8b12b8017ef9b67b,
compression=none,
cacheConf=CacheConfig:disabled,
firstKey=,\x1D\xA0\x002022/4/4/d:Work/1652515746619/Put,
lastKey=\xF1\xC6$\x002022/3/16/d:sex/1652515746619/Put,
avgKeyLen=29,
avgValueLen=6,
entries=15,
length=5581
Trailer:
fileinfoOffset=867,
loadOnOpenDataOffset=751,
dataIndexCount=1,
metaIndexCount=0,
totalUncomressedBytes=5482,
entryCount=15,
compressionCodec=NONE,
uncompressedDataIndexSize=42,
numDataIndexLevels=1,
firstDataBlockOffset=0,
lastDataBlockOffset=0,
comparatorClassName=org.apache.hadoop.hbase.KeyValue$KeyComparator,
encryptionKey=NONE,
majorVersion=3,
minorVersion=0
Fileinfo:
BLOOM_FILTER_TYPE = ROW
DELETE_FAMILY_COUNT = \x00\x00\x00\x00\x00\x00\x00\x00
EARLIEST_PUT_TS = \x00\x00\x01\x80\xC1\x9D3;
KEY_VALUE_VERSION = \x00\x00\x00\x01
LAST_BLOOM_KEY = \xF1\xC6$\x002022/3/16
MAJOR_COMPACTION_KEY = \xFF
MAX_MEMSTORE_TS_KEY = \x00\x00\x00\x00\x00\x00\x00\x04
MAX_SEQ_ID_KEY = 4
TIMERANGE = 1652515746619....1652515746619
hfile.AVG_KEY_LEN = 29
hfile.AVG_VALUE_LEN = 6
hfile.CREATE_TIME_TS = \x00\x00\x01\x80\xDD5\x0ET
hfile.LASTKEY = \x00\x0D\xF1\xC6$\x002022/3/16\x01dsex\x00\x00\x01\x80\xC1\x9D3;\x04
Mid-key: \x00\x0C,\x1D\xA0\x002022/4/4\x01dWork\x00\x00\x01\x80\xC1\x9D3;\x04
Bloom filter:
BloomSize: 8
No of Keys in bloom: 5
Max Keys for bloom: 6
Percentage filled: 83%
Number of chunks: 1
Comparator: RawBytesComparator
Delete Family Bloom filter:
Not present
Stats:
Key length:
min = 28.00
max = 29.00
mean = 28.80
stddev = 0.45
median = 29.00
75% <= 29.00
95% <= 29.00
98% <= 29.00
99% <= 29.00
99.9% <= 29.00
count = 5
Row size (bytes):
min = 127.00
max = 134.00
mean = 130.80
stddev = 2.59
median = 131.00
75% <= 133.00
95% <= 134.00
98% <= 134.00
99% <= 134.00
99.9% <= 134.00
count = 5
Row size (columns):
min = 3.00
max = 3.00
mean = 3.00
stddev = 0.00
median = 3.00
75% <= 3.00
95% <= 3.00
98% <= 3.00
99% <= 3.00
99.9% <= 3.00
count = 5
Val length:
min = 3.00
max = 12.00
mean = 6.13
stddev = 3.07
median = 6.00
75% <= 9.00
95% <= 12.00
98% <= 12.00
99% <= 12.00
99.9% <= 12.00
count = 15
Key of biggest row: \xE3\xA9\x00\x002022/4/24
Scanned kv count -> 15

2.Snapshot结构

2.1 hbase表数据在hdfs当中的目录结构

1
2
3
4
5
6
7
8
9
10
11
12
/ {hbase.rootdir}
/ data
/ {namespace}
/ {tablename}
/ .tabledesc
* .tableinfo.0000000001
/ {region1 name}
* .regioninfo
/ {columns family}
* {hfile1 name}
* {hfile2 name}
/ {region2 name}

  • 说明:{}当中表示文件名可变,/表示文件夹,*表示文件。其中各级目录当中还有很多.tmp临时文件夹,用于进行数据操作时临时存放,变更完成后都会变成空文件夹。
  • {hbase.rootdir}在hbase-site.xml文件中定义,一般是{fs.default.name}+”/hbase”。
  • {namespace}为表的命令空间,如果创建表时没有指定命令空间,则自动设置命名空间为default。
  • {tablename}为表名。
  • .tableinfo.0000000001文件中以字节码的形式保存着表名、列族等表基本信息。
  • {region1 name}为表的region名。表按照rowkey不同按行分割存储成不同的region存储到不同的regionserver中。
  • .regioninfo文件中以字节码的形式保存着region的基本信息和其中所有hfile的地址链接。
  • {columns family}为列族名,同一个region中的数据按列族分隔存储在不同的store当中。
  • {hfile1 name}当中存储真实数据。

2.2 snapshot在hdfs当中的目录结构

1
2
3
4
5
6
/ {hbase.rootdir}
/ .hbase-snapshot
/ {snapshot name}
* .inprogress
* .snapshotinfo
* data.manifest

  • .snapshotinfo当中保存了表名等基本信息。
  • data.manifest是源hbase表当中所有.regioninfo的集合,保存了每个region下所有hfile文件的地址链接(link)。

2.3 archive文件夹的目录结构

1
2
3
4
5
6
7
8
/ {hbase.rootdir}
/ archive
/ data
/ {namespace}
/ {table name}
/ {region name}
/ {columns family}
* {hfile}

snapshot其实就是源表数据文件的指针,对snapshot的take、clone、restore、delete等操作并不会涉及到数据文件本身。

但是当源表数据发生flush、compact的变化或者被删除时,首先会检测是否存在snapshot文件指向该数据文件,如果存在则会先将该源表数据文件复制到archive文件夹中。后续对于snapshot的数据操作都是使用archive文件夹中的数据。

snapshot的export操作同样是先将源表数据文件全部复制到archive文件夹中再导出到目标地址。所以完成export操作之后,导出目标地址上会有两个文件夹,分别是.hbase-snapshot和archive,依靠这两个文件夹就可以完全还原出源表。