十分钟了解Hbase基础概念和存储架构

HBase 基础概念和架构
HBase 介绍
HBase 是 BigTable 的开源 Java 版本。是建立在 HDFS 之上,提供高可靠性、高性能、列存储、可伸缩、实时读写 NoSql 的数据库系统。
它介于 NoSql 和 RDBMS 之间,仅能通过主键(row key)和主键的 range 来检索数据,仅支持单行事务(可通过 hive 支持来实现多表 join 等复杂操作)。主要用来存储结构化和半结构化的松散数据。
Hbase 查询数据功能很简单,不支持 join 等复杂操作,不支持复杂的事务(行级的事务) Hbase 中支持的数据类型:byte[] 与 hadoop 一样,Hbase 目标主要依靠横向扩展,通过不断增加廉价的商用服务器,来增加计算和存储能力。
HBase 中的表一般有这样的特点:
- 大:一个表可以有上十亿行,上百万列
- 面向列:面向列(族)的存储和权限控制,列(族)独立检索。
- 稀疏:对于为空(null)的列,并不占用存储空间,因此,表可以设计的非常稀疏。
HBase 数据模型
HBase是一个面向列的数据库,在表中它由行排序。表模式定义只能列族,也就是键值对。一个表有多个列族以及每一个列族可以有任意数量的列。后续列的值连续存储在磁盘上。表中的每个单元格都具有时间戳。总之,在一个HBase:
- 表示行的集合;
- 行是列族的集合;
- 列族是列的集合;
- 列是键值对的集合;
这里的列式存储或者面向列,说的是列族存储,HBase根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候必须指定。
HBase 和 RMBMS的比较
| 差异类别 | HBase | RDBMS |
|---|---|---|
| 数据类型 | Bytes | 丰富的数据类型 |
| 数据操作 | 简单CRUD | 丰富的SQL支持 |
| 数据模式 | 列存储 | 行存储 |
| 数据保护 | 保留 | 替换可 |
| 可伸缩性 | 好 | 差 |
| 吞吐量 | 百万查询/每秒 | 数钱查询/每秒 |
| 索引 | 仅支持Row-key | 支持 |
RDBMS
| Primary key | name | age |
|---|---|---|
| 1 | 张三 | 20 |
| 2 | 李四 | 25 |
| 3 | 王五 | 30 |
HBase表
| info(列族) | info(列族) | Job(列族) | Job(列族) | |
|---|---|---|---|---|
| Rowkey(行键) | info:name(列) | info:age(列) | job:position(列) | job:exp(列) |
| Rk001 | 张三 | 20 | CEO | 5 |
| Rk002 | 李四 | 25 | CTO | 7 |
| Rk003 | 王五 | 30 | CFO | 10 |
Row Key 行键
与NoSQL数据库一样,rowkey是用来表示唯一一行记录的主键,HBase的数据是按照RowKey的字典顺序进行全局排序的,所有查询都只依赖这一个排序维度。
Row key行键可以是任意字符串,在HBase内部row key保存为字节数组。存储时数据按照Row key的字典排序(btye order)。设计key时,要充分利用排序存储这个特性,将经常一起读取的行存储放到一起。
访问HBase table中的行,只有三种方式:
- 通过单个row key访问;
- 通过row key的range(正则);
- 全表扫描;
Columns Family 列族
列族:HBase表中的每个列都归属于某个列族。列族是表的schema的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如 info:name、info:age,都输入Info这个列族。
Cell
由{row key、column family、version} 唯一确定的单元,cell中的数据是没有类型的,全是字节码形式存储。
Time Stamp 时间戳
HBase通过rowkey和columns确定为一个存储单元称为cell,每个cell保持着同一份数据的多个版本。版本通过时间戳来索引,时间戳类型是64位整形,时间戳由HBase数据写入时自动赋值。时间戳也可以由客户端显示赋值。
为避免数据存在过多的版本造成管理负担,HBase提供了两种数据版本回收方式,一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近7天),可以针对每个列族设置。
HBase 物理存储方式
整体结构

- Table中的所有行都按照Row Key的字典序排列;
- Table在行的方向上分割为多个HRegion;
- HRegion按大小分割的(默认10G),每个表一开始只有一个HRegion,随着数据不断插入表,HRegion不断增大,当增大到一个阈值时,HRegion就会等分成两个新的HRegion,当Table中的行不断增多,就会有越来越多的HRegion;
- HRegion是HBase中分布式存储和负载均衡的最小单元。就表示不同的HRegion可以分布在不同的HRegion Server上,但是一个HRegion是不会拆分到多个Server上的。
- HRegion是负载均衡的最小单位但不是物理存储的最小单位,HRegion由一个或者多个Store组成,每个Store保存一个Column Family,每个Store又由一个MemStore和 0至多个StoreFIle组成。
StoreFile 和 HFile结构

HBase中所有数据都存储在Hadoop HDFS文件系统上,格式主要有两种:
- HFile,HBase中Key-Value数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFIle就是对HFile轻量级包装,即StoreFile底层就是HFile。
- HLog FIle,HBase中WAL(Write Ahead Log)的存储格式,物理上市Hadoop的Sequence File。
HLog File

HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。 HLog Sequece File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue。
HBase 读写数据流程
写数据流程

- Client通过Zookeeper的调度,想RegionServer发出写请求,在Region中写入数据;
- 数据被写入Region的MemStore,指导MemStore达到阈值(即MemStroe满);
- MemStore中的数据被Flush成一个StoreFIle;
- 随着StoreFIle文件不断增多,当其数量增长到一定阈值后,触发Compact合并操作,将多个StoreFIle合并成一个StoreFIle,同时进行版本合并和数据删除;
- StroeFIles随着不断Compact合并操作,逐步形成越来越大的StoreFIle;
- 单个StoreFIle大小超过一定阈值后,触发Split操作,把当前Region Split成功2个新的Region,父Region会下线,新split出2个子Region会被HMaster分配到相应的RegionServer上,使原来1个Region的压力分流到2个Region上。
可以看出HBase只有增添数据,所有更新和删除操作都是在后续Compact历程中进行的,使得用户的写操作是要进入内存就可以立刻返回,实现了HBase I/O的高性能。
读数据流程
- Client访问Zookeeper,查找ROOT表,获取META表信息;
- 从META表查询获取存放目标数据的Region信息,从而找到对应的RegionServer;
- 通过RegionServer获取需要找到的数据;
- RegionServer内存分为MemStore和BlockCache两部分,MemStore主要用于写数据,BlockCache主要用于读数据,读请求先到MemStore中查数据,查不到就到BlockCache中查,再查不到就会到StoreFIle上读,并把读的结果放入BlockCache。
- 寻址过程:client -> zookeeper -> root表 -> meta表 -> RegionServer -> Region ->client
