一、HBASE概述
HBase来源于google的论文BigTable,由apache做了开源项目即HBase.
HBase是一种NoSql非关系型数据库,适合存储半结构化、非结构化数据以及稀疏数据。面向列进行存储,可提供海量数据,实现上亿条记录的毫秒级别查询。缺点:不提供严格 的事务控制,只能在行级别保证事务。
总体来说,HBase是一个高可靠、高性能、面向列、可伸缩的分布式存储系统,可在廉价的pc上搭建起大规模结构化存储集群。
二、逻辑结构
HBase通过表存储数据,但是表结构和关系型数据库非常不一样。
HBase核心概念:
行键-RowKey:
HBase主键
访问HBase中的数据有三种方式
通过单一行键访问
通过一组行键访问
全表扫描
列族-column Family:
是表的元数据的一部分,需要在建表时声明,不能后期增加,如果需要增加,只能alter表,一个列族可以包含一个或多个列
列-column:
不需要提前声明,不是表的元数据一部分。
单元格与时间戳-cell timestamp:
通过row和columns确定一个存储单元,每个存储单元保存一个或多个版本,版本通过时间戳来区别。而由row column和timestamp确定出来的唯一的数据存储单元称之为一个cell单元格。
存储数据:
数据都以二进制形式存储,没有数据类型的区别。
所有空数据都不占用空间(与关系型数据库对比)
三、HBase原理
1、HBase工作方式
1.1、region的分裂和结构
HBase表中的数据按照行键的字典顺序排序。
HBase表中数据按照行的方向切为多个region。
最开始只有一个region,随着数据量增加,一个region分裂成两个region,不停进行。一个表可能对应一个或多个region。
region是HBase表分布式存储和负载均衡的基本单元,一个表的多个region可能分布在多台HRegionSerevr上。
region是分布式存储的基本单元,但不是存储的基本单元,内部有其具体结构。
一个region由多个store组成,一个store对应一个列族,方便压缩,节省空间。
一个store由一个memstore和0或多个storefile组成。storefile就是hdfs中的hfile,只能写入,不能修改。所以HBase写入数据到hdfs的过程是不断追加hfile的过程。
1.2、hbase写入数据
数据写入HBase,先在hlog中记录日志,再修改memstore,成功后直接返回结果,并不真正等待写入hdfs中。
memstore内存有限,当写入数量达到一定阈值,就会创建一个新的memstore,而旧的memstore会用一个单独的线程写出到storefile中,最终清空就得memstore并在zookeeper中记录最后写出数据时间的redo point信息。
由于storefile不能修改,所以数据的更新其实是在不停的创建新的storefile。多个storefile中可能存在对同一个数据的多个版本,其中旧的版本其实是垃圾数据。当垃圾数据达到一定阈值,就会自动合并storefile,在合并过程中,将垃圾数据清理。当合并的文件达到一定大小,在从新进行切分,防止文件过大
storefile中的数据,其实是由memstore和storefile来组成。而memstore是内存数据,一旦断电会丢失。为了解决可能的意外造成的数据丢失问题,hbase在整个hregionserver中,通过记录hlog来保存所有的数据操作记录。
当hbase启动,会检查zookeeper中redopoint信息,从hlog中回复这个时间点之后的数据,解决数据丢失问题。
hlog在整个hregionserver中只有一个,这台机器中所有的HRegion都公用这个文件,这样整个机器的磁盘性能都可以为这个文件提供支持,提升了文件的读写效率。hlog最终对应的是hdfs中的文件,也是分布式存储,保证了日志文件的可靠性。
1.3、HBase读取数据
hfile组成:
Data Blocks段:保存表中数据,这部分可压缩
Meta Blocks段:保存用户自定义的kv对,可以被压缩
File Info段:hfile的元信息,不被压缩,用户也可以在这一部分添加自己的元信息。
Data Block Index段:Data Blocks的索引。每条索引的key是被索引的block的第一条记录的key。
Meta Block Index段:Meta Block的索引。
Trailer:这一段数据定长,保存了每一段的偏移量。
hbase读取过程:
读取一个HFile时,会首先读取Trailer,Trailer保存了每个段的起始位置。DataBlock Index会被读取到内存之中,当检索到某个key,不需要扫描整个HFile,而只需从内存中找到key所在的block,通过一次磁盘io,将整个block读取到内存中,再找到需要的key。DataBlock Index采用LRU(内存管理的一种页面置换算法)机制淘汰。
在查询数据时,先查找内存,如果内存中有当前键的对应数据,获取数据直接返回。如果没有,就去查找region中对应的hfile。注意不是将所有的hfile数据恢复到内存,而是查找每个hfile的Trailer,通过Trailer找到Data Block Index,如果这里发现了要找的数据,通过索引找到Data Blocks,将Data Block数据送回内存组装,最终讴歌hfile中获取到的数据,合并后返回最新数据。
由于hbase中的数据天然排序,再加上索引,整个查询也可以非常快。
1.4、HBase中region寻址
在HBase的HBase库中,有一张meta表,其中存放了表和region和regionServer之间的对应关系,这个表规定只能有一个region。meta表的region位置信息存放在zookeeper的meta-region-server节点下。在客户端从hbase中查找数据,需首先联系zookeeper,找到meta表对应的region的位置,链接这个位置读取到meta表中的信息,才能知道要查询的表和表的region对应的regionServer的信息。再根据这些信息链接真正要查询的表,这个过程称之为region的寻址过程。
从介绍也可知,此寻址相当耗费时间,为了提高性能,客户端通常会缓存之前已知道的region寻址信息。当客户端再次读取同一个表的数据时,可以通过本地缓存,直接定位读取,提高效率。
1.5hbase系统架构
hbase为分布式数据库
hbase中的老大为master,小弟叫regionServer
客户端称Client
Zookeeper为HBase提供集群协调
client
访问HBase保留一些缓存信息提升效率
zookeeper
保证任何时候集群只有一个HMaster
监控regionServer的状态,将其上线下线的信息通知master
存储所有Region的寻址地址
存储HBase元数据信息,包括哪些表,哪些列族
Master
为RegionServer分配region
为RegionServer进行负载均衡
GFS上的垃圾回收,多个小hfile文件合成大的hfile再分裂成小的hfile
处理对Schema数据的更新请求
RegionServer
维护master分配的region,处理这些region的IO请求
负责切分在运行过程中变得过大的region
1.6、HBase读取快速的原因
从逻辑结构:
表按照键进行排序,查询时可以很快定位
数据按照行键切分成多个HRegion,分布多个RegionServer,查询大量数据时,多个RegionServer可以一起工作,可以提高速度。
从物理结构:
HRegion存活在RegionServer的内存中,读写会非常高效
1.7、HBase的可靠性与海量数据存储
海量数据:
基于hdfs,支持扩展性,可以通过增加大量廉价的硬件提高存储容量
按列存储,空的数据不占用空间,但存储稀疏数据,不会浪费空间。同一列的数据放在一起,一般为内容相似的数据,可以实现非常高效的压缩,节省空间。
可靠性:
基于hdfs,实现了数据的备份
四、HBase设计原则
HBase表的设计主要是列族的设计和行键的设计
列族设计
HBase表列族不宜过多,越少越好,官方推荐不超过3个
经常在一起查询的数据放在一个列族中,尽量减少跨列族查询
如果有多个列族,列族的数据应该设计均匀
行键设计
行键是表中一行数据的唯一标识,所以行键的设计将直接影响对habse的查询性能和便利性
基本原则
行键必须唯一
行键必须有意义
行键最好是字符串
行键最好有固定长度,否则排序结果可能与预期不一致
行键不宜过长,最长可达64kb,但最好在10-100字节之间,为8字节的整倍数
行键最佳实践
散列原则:
行键影响数据排序,继而影响region切分后的结果,注意让经常查询的数据分散在不同的region中,防止某一个或者某几个regionServer成为热点。
有序原则:
将连续查询的条件作为行键最前面的数据,可以方便批量查询