让你彻底学会HBase

让你彻底学会HBase

Apache HBase(Hadoop DataBase)是一个开源的、高可靠性、高性能、面向列(这里指列族,非列式存储)、可伸缩、实时读写的分布式数据库。利用 Hadoop HDFS 作为其文件存储系统,利用 ZooKeeper 作为其分布式协同服务。主要用来存储非结构化和半结构化的松散数据(列式存储 NoSQL 数据库)。

注意:HBase 是列族数据库(Column-Family Database),不是列式数据库(Column-Oriented Database)。
总结:HBase 是运行在 HDFS 之上的面向列(列族)的数据库管理系统。

特点

易扩展

容量大

面向列

多版本

稀疏性

高可靠

高性能

HBase 和 RDBMS 的区别

让你彻底学会HBase_第1张图片

数据类型

在 HBase 表中,一条数据拥有一个全局唯一的主键(RowKey)和任意数量的列(Column Qualifier),每个列的数据存储支持多个版本(Version),一列或多列组成一个列族(Column Family),同一个列族中列的数据在物理上都存储在同一个 HFile 中。这样基于列存储的数据结构有利于数据缓存和查询。

在 HBase 中定位一条数据需要通过:RowKeyColumn FamilyColumn QualifierVersion

让你彻底学会HBase_第2张图片

HBase 表中的数据是疏松地存储的,因此用户可以动态地为数据定义各种不同的列。

HBase 中的数据按主键排序(字典序),同时HBase 会将表按主键划分为多个 HRegion 存储在不同的 HRegionServer 上,以完成数据的分布式存储和读取。

NameSpace

命名空间类似于关系型数据库中的数据库的概念,他其实是表的逻辑分组。

default:没有明确指定命名空间的表将自动落入此命名空间
hbase:系统命名空间,用于包含 HBase 的内部表和元数据表

Table

Table 和关系型数据库中的表一个意思,由行和列组成。

RowKey

RowKey 的概念与关系型数据库中的主键相似,是一行数据的唯一标识。RowKey 可以是任意字符串(最大长度是64KB,实际应用中长度一般为 10-100 Bytes),RowKey 以字节数组保存。存储数据时,数据会按照 RowKey 的字典序排序存储,所以设计 RowKey 时,要充分利用排序存储这个特性,将经常一起读取的行存放到一起。
访问 HBase 数据的方式有三种:

  1. 基于 RowKey 的单行查询;
  2. 基于 RowKey 的范围查询;
  3. 全表扫描查询。
RowKey 如何设计,设计不好会产⽣什么后果

唯⼀原则
单主键
组合主键(注意顺序)
⻓度原则
不要超过 16 个字节
对⻬ RowKey ⻓度
Rowkey是⼀个⼆进制码流,Rowkey的⻓度被很多开发者建议说设计在10~100个字节,不过建议是越短越好,不要超过16个字节。
不要设计太⻓的原因如下:
1)数据的持久化⽂件HFile中是按照Key Value 存储的,如果Rowkey过⻓⽐如100个字节,1000万列数据,光Rowkey就要占⽤100*1000 万=10亿个字节,将近1G数据,这会极⼤影响 HFile的存储效率;
2)MemStore将缓存部分数据到内存,如果 Rowkey字段过⻓内存的有效利⽤率会降低,系统将⽆法缓存更多的数据,这会降低检索效率。因此Rowkey的字节⻓度越短越好;
3)⽬前操作系统是都是64位系统,内存8字节对⻬。控制在16个字节,8字节的整数倍利⽤操作系统的最佳特性。
散列原则:
反转
加盐
Hash

设计不好会出现热点问题:
HBase 中的⾏默认按⾏键的字典序进⾏排序,这种设计优化了扫描(Scan),允许将相关的⾏或彼此靠近的⾏⼀起读取。但是,设计不佳的⾏键是 Hot-Spotting 的常⻅来源。
热点发⽣在⼤量 Client 直接访问集群的⼀个或极少数个节点,⼤量访问会使热点 HRegion 所在的单个机器超出⾃身承受能⼒,性能下降甚⾄ HRegion 不可⽤。这也会对同⼀台区域服务器(HRegionServer)托管的其他区域(HRegion)产⽣不利影响(主机资源全部被这个热点HRegion 占⽤,已⽆法服务其他 HRegion 的请求)。

Column Family

Column Family 即列族,HBase 基于列划分数据的物理存储,同一个列族中列的数据在物理上都存储在同一个 HFile 中。一个列族可以包含任意多列,一般同一类的列会放在一个列族中,每个列族都有一组存储属性:
是否应该缓存在内存中;
数据如何被压缩或行键如何编码等。
HBase 在创建表的时候就必须指定列族。HBase 的列族不是越多越好,官方推荐一个表的列族数量最好小于或者等于三,过多的列族不利于 HBase 数据的管理和索引。

为什么不建议 HBase 设计过多列族
  1. 内存开销: 列族过多,内存开销会逐渐积累,导致RegionServer的内存占⽤增加,影响集群的稳定性
  2. 磁盘开销: 过多的列族会导致更多的磁盘寻址和IO操作,从⽽增加了磁盘开销
  3. 查询性能下降: 查询跨越多个列族,性能会受影响
  4. 写⼊性能下降:写⼊操作需要锁定列族,列族过多会导致性能下降

Column Qualifier

列族的限定词,理解为列的唯一标识。但是列标识是可以改变的,因此每一行可能有不同的列标识。使用的时候必须 列族:列 ,列可以根据需求动态添加或者删除,同一个表中不同行的数据列都可以不同。

Timestamp

Timestamp 是实现 HBase 多版本的关键。在 HBase 中,使用不同的 Timestamp 来标识相同 RowKey 对应的不同版本的数据。相同RowKey 的数据按照 Timestamp 倒序排列,默认查询的是最新的版本,当然用户也可以指定 Timestamp 的值来读取指定版本的数据。
HBase 通过 RowKey 和 Column Family,Column Qualifier 来确定一个存贮单元,然后再通过时间戳来进行索引。时间戳的类型是 64 位整型,时间戳默认是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值,如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。
为了避免数据存在过多版本而造成管理(包括存贮和索引)负担,HBase 提供了两种数据版本回收方案:

  1. 保存数据的最后 n 个版本
  2. 保存最近一段时间内的版本(比如最近七天)

Cell

Cell 由 Row,Column Family,Column Qualifier,Version 组成。Cell 中的数据是没有类型的,全部使用字节码形式存贮,因为 HDFS 上的数据都是字节数组。

架构模型

HBase 可以将数据存储在本地文件系统,也可以存储在 HDFS 文件系统。在生产环境中,HBase 一般运行在 HDFS 上,以 HDFS 作为基础的存储设施。用户通过 HBase Client 提供的 Shell 或 Java API 来访问 HBase 数据库,以完成数据的写入和读取。HBase 集群主要由 HMaster、HRegionServer 和 ZooKeeper 组成。

让你彻底学会HBase_第3张图片

ZooKeeper

HBase 通过 ZooKeeper 来完成选举 HMaster、监控 HRegionServer、维护元数据集群配置等工作。

选举 HMaster

监控 HRegionServer(节点探活)

维护元数据和集群配置

​ 存储所有 HRegion 的寻址入口(META 元数据表),存储所有的的元数据信息;
​ 存储 HBase 的 Schema,包括有哪些 Table,每个 Table 有哪些 Column Family。

Client

HBase Client 为用户提供了访问 HBase 的接口,可以通过元数据表(客户端负责发送请求到数据库)来定位到目标数据的HRegionServer。

  1. HBase Shell
  2. Java API

HMaster

HMaster 是 HBase 集群的主节点,负责整个集群的管理工作,HMaster 可以实现高可用(Active 和 Backup),通过 ZooKeeper 来维护主备节点的切换。

管理分配:管理和分配 HRegion,负责启动的时候分配 HRegion 到具体的 HRegionServer,又或者在分割 HRegion 时关于新 HRegion 的分配。管理用户对 Table 结构的 DDL(创建,删除,修改)操作。

  1. 表的元数据信息存储在 ZooKeeper
  2. 表的数据存储在 HRegionServer 上(实际存储在 HDFS 上)

负载均衡:一方面负责将用户的数据均衡地分布在各个 HRegionServer 上,防止 HRegionServer 数据倾斜过载。另一方面负责将用户的请求均衡地分布在各个 HRegionServer 上,防止 HRegionServer 请求过热;
维护数据:发现失效的 HRegion,并将失效的 HRegion 分配到正常的 HRegionServer 上。当某个 HRegionServer 下线时迁移其内部的HRegion 到其他 HRegionServer 上。
权限控制

HRegionServer

HRegionServer 直接对接用户的读写请求,是真正干活的节点,属于 HBase 具体数据的管理者。

  1. 实时和 HMaster 保持心跳,汇报当前节点的信息;
  2. 当接收到 HMaster 的命令创建表时,会分配一个 HRegion 对应一张表;
  3. 负责切分在运行过程中变得过大的 HRegion;
  4. 当 HRegionServer 意外关闭的时候,当前节点的 HRegion 会被其他 HRegionServer 管理;
  5. 维护 HMaster 分配给它的 HRegion,处理对这些 HRegion 的 IO 请求;

当某个 HRegionServer 宕机后,ZooKeeper 会通知 HMaster 进行失效备援。下线的 HRegionServer 所负责的 HRegion 暂时停止对外提供服务,HMaster 会将该 HRegionServer 所负责的 HRegion 转移到其他 HRegionServer 上,并且会对下线的 HRegionServer 进行日志重放,将MemStore 中还未持久化到磁盘中的数据进行恢复。

HRegion

让你彻底学会HBase_第4张图片

一个 HRegionServer 包含了多个 HRegion。HBase 将表中的数据基于 RowKey 的不同范围划分到不同 HRegion 上,每个 HRegion 都负责一定范围的数据存储和访问。

HRegion 是 HBase 中分布式存储和负载均衡的最小单元,不同的 HRegion 可以分布在不同的 HRegionServer 上。

HRegion 到阀值(10G)的时候,就会等分成两个 HRegion,切分后其中一个HRegion 会被转移到其他的 HRegionServer 上,实现负载均衡。可以根据自己的业务进行预分区。

让你彻底学会HBase_第5张图片

Split

当一个 Table 刚被创建的时候,HBase 默认的分配一个 HRegion 给 Table。可以用 pre-splitting 在创建 Table 时提前生成多个 HRegion。

HBase 在每次数据合并之后都会针对相应 HRegion 生成一个 requestSplit 请求,requestSplit 首先会执行 checkSplit,检测 FileSize 是否达到阈值,如果超过阈值,就进行切分。

在 0.94 版本之前 ConstantSizeRegionSplitPolicy 是默认和唯一的 Split 策略。当某个 Store(对应一个 Column Family)的大小大于配置值hbase.hregion.max.filesize 的时候(默认 10G)HRegion 就会自动分裂。

而 0.94 版本之后 IncreasingToUpperBoundRegionSplitPolicy 是默认的 Split 策略。这个策略中,最小的分裂大小和 Table 的某个HRegionServer 的 HRegion 个数有关,当 StoreFile 的大小大于以下公式得出的值的时候就会 Split。

# R 为同一个 Table 中在同一个 HRegionServer 中的 HRegion 的个数
Min(R^2 * "hbase.hregion.memstore.flush.size", "hbase.hregion.max.filesize")

Store

一个 HRegion 由多个 Store 组成,每个 Store 都对应一个 Column Family,Store 包含 1 个 MemStore 和 0 或多个 StoreFile 组成。

MemStore:作为 HBase 的内存数据存储,数据的写操作会先写到 MemStore 中,当 MemStore 中的数据增长到指定阈值(默认 128M)后,HRegionServer 会启动 FlushCache 进程将 MemStore 中的数据写入 StoreFile 持久化存储,每次写入后都形成一个单独的 StoreFile。当客户端检索数据时,先在 MemStore 中查找,如果 MemStore 中不存在,则会在 StoreFile 中继续查找。
StoreFile:MemStore 中的数据写到文件后就是 StoreFile,StoreFile 底层是以 HFile 格式保存的。HBase 以 StoreFile 的大小来判断是否需要切分 HRegion。当一个 HRegion 中所有 StoreFile 的大小和数量都增长到超过指定阈值时,HMaster 会把当前 HRegion 分割为两个,切分后其中一个 HRegion 会被转移到其他的HRegionServer 上,实现负载均衡。
HFile:HFile 和 StoreFile 是同一个文件,只不过站在 HDFS 的角度称这个文件为 HFile,站在 HBase 的角度就称这个文件为 StoreFile。是HBase 在 HDFS 中存储数据的格式,它包含多层的索引,这样在 HBase 检索数据的时候就不用完全的加载整个文件。

HFile

StoreFile(HFile) 是 HBase 最终存储数据的介质.

Block:每个 HFile 由 N 个 Block 组成。
KeyValue:每个 Block 又是由多个 KeyValue 数据组成,KeyValue 对象是数据存储的核心,KeyValue 包装了一个字节数组,同时将偏移量offsets 和 lengths 放入数组中,这个数组指定从哪里开始解析数据内容。

KeyValue 对象不跨 Block 存储,假如这里有一个 KeyValue 的大小为 8M,即使 Block-Size=64KB,当读取该 KeyValue 的时候也是以一个连贯的 Block 进行读取。

让你彻底学会HBase_第6张图片

无论是 Data Block Index 还是 Bloom Filter,都采用了分层索引的设计。

HLog

一个 HRegionServer 只有一个 HLog 文件。负责记录数据的操作日志,当 HBase 出现故障时可以进行日志重放、故障恢复。例如磁盘掉电导致 MemStore 中的数据没有持久化存储到 StoreFile,这时就可以通过 HLog 日志重放来恢复数据。

HLogKey 中记录了写入数据的归属信息,除了 Table 和 HRegion 名称外,同时还包括 Sequence Number 和 Timestamp:
Timestamp:写入时间。
Sequence Number:起始值为 0,或者是最近一次存入文件系统中的 Sequence Number。

读写流程

三层索引

HBase 0.96 以前

HBase 0.96 以前内部维护了两张特殊的表: -ROOT- 表和 .META. 表,用来查找各种表的 HRegion 位置。这两张特殊的表也像 HBase 中的其他表一样会切分成多个 HRegion。 -ROOT- 表比 .META. 更特殊一些,永远不会切分超过一个 HRegion,这样保证了只需要三次跳转,就能定位到任意 HRegion。
-ROOT- :记录 .META. 表的 HRegion 信息。
.META. :记录用户的表的 HRegion 信息。

而 -ROOT- 表的 HRegion 位置信息存放在 ZooKeeper 中,通过 ZooKeeper 可以找到 -ROOT- 的 HRegion 托管的 HRegionServer。再通过 -ROOT- 表找到 .META. 表的 HRegion 位置。 .META. 表中存放着用户的表的 HRegion 切分信息。
整个流程为: Client → ZooKeeper → -ROOT- → .META. → 用户的表的 HRegion

让你彻底学会HBase_第7张图片

HBase 0.96 以后

ROOT- 表被移除,直接将 .META. 表 HRegion 位置信息存放在 ZooKeeper 中,并将 .META. 表更名为 hbase:meta 。

此时整个流程为: Client → ZooKeeper → hbase:meta → 用户的表的 HRegion

让你彻底学会HBase_第8张图片

读取数据流程

让你彻底学会HBase_第9张图片

  1. Client 访问 ZooKeeper,获取 hbase:meta 所在 HRegionServer 的节点信息;
  2. Client 访问 hbase:meta 所在的 HRegionServer,获取 hbase:meta 记录的元数据后先加载到内存中,然后再从内存中查询出 RowKey 所在的 HRegion (HRegion 所在的 HRegionServer);
  3. Client 对 RowKey 所在的 HRegion 对应的 HRegionServer 发起读取数据请求;
  4. HRegionServer 构建 RegionScanner(需要查询的 RowKey 分布在多少个 HRegion 中就需要构建多少个 RegionScanner),用于对该HRegion 的数据检索;
  5. RegionScanner 构建 StoreScanner(HRegion 中有多少个 Store 就需要构建多少个 StoreScanner,Store 的数量取决于 Table 的ColumnFamily 的数量),用于对该列族的数据检索;
  6. 所有的 StoreScanner 合并构建最小堆(已排序的完全二叉树)StoreHeap:PriorityQueue;
  7. StoreScanner 构建一个 MemStoreScanner 和一个或多个 StoreFileScanner(数量取决于 StoreFile 数量);
  8. 过滤掉能够确定所要查询的 RowKey 一定不在的 StoreFileScanner 或 MemStoreScanner(布隆过滤器);
  9. 经过筛选后留下的 Scanner 开始做读取数据的准备,将对应的 StoreFile 定位到满足的 RowKey 的起始位置;
  10. 将所有的 StoreFileScanner 和 MemStoreScanner 合并构建最小堆 KeyValueHeap:PriorityQueue,排序的规则按照 KeyValue 从小到大排序;
  11. 从 KeyValueHeap:PriorityQueue 中经过一系列筛选后一行行的得到需要查询的 KeyValue。
写入数据流程
  1. Client 访问 ZooKeeper,获取 hbase:meta 所在 HRegionServer 的节点信息;
  2. Client 访问 hbase:meta 所在的 HRegionServer,获取 hbase:meta 记录的元数据后先加载到内存中,然后再从内存中查询出 RowKey 所在的 HRegion (HRegion 所在的 HRegionServer);
  3. Client 对 RowKey 所在的 HRegion 对应的 HRegionServer 发起写入数据请求;
  4. 建立连接后,首先将 DML 要做的操作写入到日志 HLog;
  5. 然后将数据的修改更新到 MemStore 中,本次操作结束。一个 HRegion 由多个 Store 组成,一个 Store 对应一个列族,Store 包括位于内存中的 Memstore 和位于磁盘的 StoreFile,写操作先写入 MemStore;
  6. 当 MemStore 数据达到阈值后(默认 128M),创建一个新的 MemStore;
  7. 旧的 MemStore 将刷写为一个独立的 StoreFile(HRegionServer 会启动 FlushCache 进程写入 StoreFile)并存放到 HDFS,最后删除 HLog 中的历史数据。

你可能感兴趣的:(hbase,数据库,大数据)