HBase 架构 | 存储
目前主流的RDBMS和其他非关系型数据库底层数据库结构大都会使用B树或B+树,有时还会使用LSM树(Log-Structured Tree)。HBase与BitTable一样,是基于LSM树的系统。
基本结构 为了了解HBase存储层,下图给出了一个顶层结构图。
文章图片
从上图中可以看到HBase主要处理两种文件,预写日志(WAL)
,实际文件
。这两种文件主要由HRegionServer管理。在某些情况下,HMaster也可以进行一些低层的文件操作。当存储数据到HDFS中时,数据文件会被切分成更小的块。
一个基本的流程分为三步:
- 通过
ZooKeeper
查询到含有-ROOT-
的region server A - 通过region server A查询到含有
.META.
表中对应的region server B - 通过region server B查询到行健信息
.META.
表。-ROOT-
存在于zookeeper上,类似于RDBMS里的database这个概念,可以更好的做权限管理和安全控制; .META.
的信息作为一种Region存放在Region Server上。 在新版本的HBase里面,
-ROOT-
表已经改名为hbase:namespace
,.META.
表改名为hbase:meta
。查看-ROOT- 启动zookeeper client,可以使用
ls /hbase/namespace
查询得到 启动hbase shell,可以使用
scan 'hbase:namespace'
查询得到查看.META. 启动hbase shell,可以使用
scan 'hbase:meta'
查询得到文件 目录结构
.
├── habse.version
├── hbase.id
├── .logs
├── .corrupt
├── splitlog
└── data
└── default
├── t1
│├── f1f21fee947157f277b042f11d127e82
││├── .regioninfo
││├── c1
│││└── 5201b34c76d646c2870c58949f54e776
││└── splits
│├── .tabledesc
││└── .tableinfo.0000000001
│└── .tmp
└── testtable
├── 2e1f76c4bf66f2e2c16cff1b1a676bbd
│├── .regioninfo
│├── colfam1
│├── recovered.edits
││└── 2.seqid
│├── splits
│└── .tmp
├── .tabledesc
│└── .tableinfo.0000000001
└── .tmp
HBase使用一个HDFS中可配置的根目录,用户可以使用
hdfs
命令来查看,也可以使用hue这款工具来查询,这里使用hue进行示范。文件可以被分为两类,一类位于HBase根目录下,另一类位于根目录中的表目录下。
根级文件
文章图片
目录/文件名 | 用途 |
---|---|
wals | 由HLog实例管理,存放在“目录结构”中的.log目录中 |
hbase.id | 文件包含集群唯一的ID和文件格式版本信息 |
hbase.version | 文件格式版本信息 |
splitlog | 存储日志拆分过程中产生的中间拆分文件 |
corrupt | 存储日志拆分过程中产生的中间损坏日志 |
文章图片
在HBase中,每张表都有自己的目录,其位于文件系统的HBase根目录下。
目录/文件名 | 用途 |
---|---|
.tabledesc | 存储相应的表序列化后的HTableDescriptor |
.tmp | 临时数据,比如更新.tableinfo文件时生成的临时数据 |
md5.. | region级文件 |
.tableinfo文件在.tabledesc目录里面region级文件
文章图片
region级文件位于表目录里面。region级文件的目录时一部分region名字的MD5散列值。
目录/文件名 | 用途 |
---|---|
.regioninfo | 对应region的HRegionInfo实例反序列化的信息 |
recovered.edits | 存放临时的拆分文件 |
- 将上述文件移动到临时的recovered.edits文件中
- 若region被打开,region服务器将会看到需要恢复的文件,并放回其中对应的条目
一旦region超过了配置中region大小的最大值,region就需要拆分,其会创建一个对应的splits目录,它被用来临时存放两个region相关的数据。如果拆分成功(通常这个过程持续几秒或更短),之后它们会被移动到表目录中,并形成两个新的region,每个region代表原始值的一半。
当用户看到region的目录中:region拆分
- 没有.tmp目录,意味着还没有进行过压缩操作
- 没有recovered.edits目录,意味着WAL没有进行过回放操作
在拆分过程中,所有的步骤在ZooKeeper中都进行跟踪,这使得一个服务器失效时,其他进程可以直到这个region的状态。
文章图片
region合并
存储文件会被后台的管理进程仔细的监控起来以确保它们处于控制值夏,随着memstore的写入会生成很多的磁盘文件,如果文件的数目达到阈值,合并过程将会把它们合并成数量更少,体积更大的文件。这个过程持续到这些文件超过配置的最大存储文件大小,会触发一个region拆分
压缩合并有两种,即minor和major。
- minor合并负责重写最后生成的几个文件到一个更大的文件中。
- major合并会将所有文件压缩成一个单独的文件,在执行压缩检查时,系统自动决定运行哪种合并。
如果海没有达到major合并的执行周期,系统会选择minor合并执行。当minor合并包括所有的存储文件,且所有文件均未达到设置的每次压缩的最大文件数时,minor合并可能被提升成major合并。
HFile 格式 实际的存储文件功能是由HFile类实现的,它被专门创建达到一个目的:有效的存储HBase的数据。它们基于Hadoop的TFile类。HFile参考BigTable的SSTable和Hadoop的TFile实现,从HBase开始到现在,HFile经历了三个版本,其中V2在0.92引入,V3在0.98引入。这里我们看下V1的格式。
文章图片
这些文件是可变长度的,唯一固定的块是File Info块和Trailer块。如上图所示:
Trailer有指向其他块的指针,它是在持久化数据到文件结束时写入的,写入后即确定其成为不可变的数据存储文件。
Index块记录Data和Meta块的偏移量。
Data和Meta块实际上都是可选的,但是考虑到HBase如何使用数据文件,在存储文件中用户几乎总能找到Data块。
在HDFS中,文件的默认块大小是64MB(现默认是128MB),这个是HFile默认块大小的1024倍,因此HBase存储文件的块与Hadoop的块之间并没有匹配关系。事实上,这两种块类型之间根本没有相关性。HBase把它的文件透明的存储到文件系统中,而HDFS也使用块来切分文件仅仅是一个巧合,并且HDFS并不知道HBase中存储的是什么。
下图描述了逻辑上把一个单元格的数据存储到一张表中,到实际存储到HDFS的映射过程。
文章图片
KeyValue格式
文章图片
KeyValue类是HBase中数据存储的核心,由
keylength
、valuelength
、key
、value
四个部分组成。其中Key又由
Row Length
、Row、Column Family Length
、Column Family
、Column Qualifier
、Time Stamp
、Key Type
七部分组成。KeyValue不会在块之间拆分。例如,如果有一个8 MB的KeyValue,即使块大小是64kb,这个KeyValue将作为一个连续块读取。
- KeyLength存储Key的长度,占4B;
- ValueLength存储Value的长度,占4B;
Key | 作用 |
---|---|
Row Length | 存储rowkey的长度,占2B (Bytes.SIZEOF_INT) |
Row | 存储Rowkey实际内容,其大小为Row Length |
Column Family Length | 存储列簇Column Family的长度,占1B (Bytes.SIZEOF_BYTE) |
Column Family | 存储Column Family实际内容,大小为Column Family Length |
Column Qualifier | 存储Column Qualifier对应的数据 |
Time Stamp | 存储时间戳Time Stamp,占8B (Bytes.SIZEOF_LONG) |
Key Type | 存储Key类型Key Type,占1B ( Bytes.SIZEOF_BYTE),Type分为Put、Delete、DeleteColumn、DeleteFamilyVersion、DeleteFamily、Maximum、Minimum等类型,标记这个KeyValue的类型 |
Value存储单元格Cell对应的实际的值Value 示例 【HBase 架构 | 存储】对于
Put: rowkey=row1, cf:attr1=value1
操作,Key对应关系如下:key | value |
---|---|
rowlength | 4 |
row | row1 |
columnfamilylength | 2 |
columnfamily | cf |
columnqualifier | attr1 |
timestamp | server time of Put |
keytype | Put |
推荐阅读
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- MySQL|MySQL 存储过程语法及实例
- 数据技术|一文了解Gauss数据库(开发历程、OLTP&OLAP特点、行式&列式存储,及与Oracle和AWS对比)
- 2018-03-11|2018-03-11 存储过程
- mvcc原理和hbase实现
- 年薪30万的Java架构师必会的springboot面试题
- EdgeDB 架构简析
- 笔记|C语言数据结构——二叉树的顺序存储和二叉树的遍历
- C语言学习(bit)|16.C语言进阶——深度剖析数据在内存中的存储
- 03_ARMv8指令集介绍加载与存储指令