Hbase(四):Hbase原理
Hbase的工作方式
region的分裂和结构
hbase表中的数据按照行键的字典顺序排序
hbase表中的数据按照行的的方向切分为多个region
最开始只有一个region 随着数据量的增加 产生分裂 这个过程不停的进行 一个表可能对应一个或多个region
region是hbase表分布式存储和负载均衡的基本单元 一个表的多个region可能分布在多台HRegionServer上
region是分布式存储的基本单元 但不是存储的基本单元 内部还具有结构
一个region由多个Store来组成
有几个store取决于表的列族的数量 一个列族对应一个store 之所以这么设计 是因为 一个列族中的数据往往数据很类似 方便与进行压缩 节省存储空间
表的一个列族对应一个store store的数量由表中列族的数量来决定
一个store由一个memstore 和零个或多个storefile组成
storefile其实就是hdfs中的hfile 只能写入不能修改 所以hbase写入数据到hdfs的过程其实是不断追加hfile的过程
Hbase写入数据
数据写入hbase时 先在hlog中记录日志 再修改memstore 直接返回成功 这样 不需要真正等待写入hdfs的过程 所以很快
memstore 内存有限 当写入数量达到一定的阈值的时候 就会创建一个新的memstore继续工作 而旧的memstore 会用一个单独的线程 写出到storefile中 最终清空旧的memstore 并在zookeeper中记录最后写出数据时间的redo point信息
由于storefile 不能修改 所以数据的更新其实是不停创建新的storefile的过程
这样多个storefile中可能存在对同一个数据的多个版本 其中旧的版本其实是垃圾数据 时间一长 垃圾数据就可能很多 浪费磁盘空间
所以当达到一定的阈值的时候 会自动合并storefile 在合并的过程中将垃圾数据清理
而当合并出来的文件达到一定程度时 再从新进行切分 防止文件过大
虽然看起来是小变大再变小 但是经过这个过程垃圾数据就被清理掉了
所以store中的数据 其实是memstore和storefile来组成的
而memstore由于是内存中的数据 一旦断电就会丢失
为了解决可能的意外造成数据丢失的问题 hbase在整个hregionserver中 通过记录hlog 来保存了所有数据操作的记录
当hbase启动时 会检查zookeeper中的redo point信息 从hlog中恢复 这个时间点之后的数据 解决内存数据可能丢失的问题
hlog整个hregionServer中只有一个 所有这台机器中的所有HRegion都共用这个文件 这样整个机器的磁盘性能都可以为这一个文件提供支持 提升文件的读写效率
hlog文件最终对应的是hdfs中的文件 也是分布式存储的 保证了日志文件的可靠性
Hbase读取数据
hfile的内部由以下部分组成:
Data Blocks 段–保存表中的数据,这部分可以被压缩
Meta Blocks 段 (可选的)–保存用户自定义的kv对,可以被压缩。
File Info 段–Hfile的元信息,不被压缩,用户也可以在这一部分添加自己的元信息。
Data Block Index 段–Data Block的索引。每条索引的key是被索引的block的第一条记录的key。
Meta Block Index段 (可选的)–Meta Block的索引。
Trailer–这一段是定长的。保存了每一段的偏移量,读取一个HFile时,会首先 读取Trailer,Trailer保存了每个段的起始位置(段的Magic Number用来做安全check),然后,DataBlock Index会被读取到内存中,这样,当检索某个key时,不需要扫描整个HFile,而只需从内存中找到key所在的block,通过一次磁盘io将整个 block读取到内存中,再找到需要的key。DataBlock Index采用LRU机制淘汰。
HFile的Data Block,Meta Block通常采用压缩方式存储,压缩之后可以大大减少网络IO和磁盘IO,随之而来的开销当然是需要花费cpu进行压缩和解压缩。
在查询数据时,先查找内存,如果内存中有当前键对应的数据,获取数据直接返回。如果没有在内存中找到数据,就去查找region对应的hfile,注意不是将所有hfile中的数据恢复到内存,而是查找每个hfile的Trailer,通过trailer找到Data Block Index,如果在这里发现了要找的数据,通过索引找到Data Blocks中对应的Data Block,将Data Block数据送回内存组装,最终多个hfile中获取到的数据 合并后 返回最新的。
由于hbase中的数据天然排序 再加上索引 整个查询也可以非常的快
Hbase中的region的寻址
在hbase中有一个hbase:meta表,其中存放了 表和region和regionSever 之间的对应关系信息,这个表很特别,只有一个region
并且这个meta表的这个region的位置信息被存放在了zookeeper的meta-region-server节点下
在客户端从hbase中查找数据时,需要先联系zookeeper找到meta表对应的region的位置,连接这个位置读取到meta表中的信息,才能知道要查询的表 和 表的region和region对应的regionServer的信息
再根据这些信息连接真正要查询的表 对应的region的regionServer进行读取
这个过程就称之为region的寻址过程。
这样的寻址过程是相当耗费时间的,为了提高性能,客户端通常会缓存之前已经知道的region寻址信息,当客户端再次读取同一个表中的数据时,可以通过本地缓存的region地址信息 直接定位读取,提高效率。
存储系统的三种结构
hash存储
例如HashMap
优点 写效率高 读效率高 支持增删改随机读
缺点 顺序信息会丢失
B树 B+树 B-树 B*树
例如MySql
优点 写效率高 读效率高 顺序信息不会丢失
缺点 当数据量很大 性能大幅下降
LSM树 - Log-Structured Merge Tree
例如HBase
支持增、删、读、改、顺序扫描操作
牺牲了一部分读的性能换取了高效写入能力
Hbase系统架构
hbase中的老大叫hmaster 小弟叫hregionServer
客户端叫Client
Zookeepr为hbase提供集群协调
client
访问hbase 保留一些缓存信息提升效率
zookeeper
保证任何时候集群只有一个HMaster
监控regionServer的状态 将其上线下线信息通知mater
存储所有Region的寻址地址
存储hbase的元数据信息 包括 有哪些表 有哪些列族等等
Mater
为RegionServer分配Region
为RegionServer进行负载的均衡
GFS上的垃圾回收
处理对Schema数据的更新请求
RegionServer
维护Master分配给它的region,处理对这些region的IO请求
负责切分在运行过程中变得过大的region
为什么Hbase可以很快
从逻辑结构上来说:
表按照行键进行了排序,所以查询时可以很快定位
数据按照行键切分为多个HRegion,分布在多个RegionServer中,查询大量数据时,多个RegionServer可以一起工作,从而提高速度
从物理结构上来说:
HRegion是存活在RegionServer的内存中的,读写会非常的高效
还有HFile的支持保证大量的数据可以持久化的保存
数据最终落地到HDFS中,分布式的存储,保证数据段可靠性和可扩展性
为什么Hbase可以存储很多数据
基于hdfs,所以支持可扩展性,可以通过增加大量的廉价的硬件提高存储容量
按列存储,空的数据不占用空间,当存储稀疏数据时,不会浪费空间
按例存储,同一列的数据存放在一起,而同一列的数据一般都是同样的类型的内容相似的数据,可以实现非常高效的压缩,节省空间
为什么Hbase的数据是可靠的
基于hdfs,由hdfs的可靠性保证了hbase的可靠性–即数据可以有多个备份
利用zookeeper实现了HA,即使某一台机器挂掉另外的机器也可以很快的替换它
Hbase与Hive,以及传统关系型数据库的比较
比起传统的关系型数据库,可以存储半结构化非结构化的数据,可以存储和处理更大级别的数据,提供高效的查询,对于稀疏数据的处理更好,具有更好的横向扩展性,免费开源性价比很高。但是不能支持非常好的事务特性,只支持行级的事务。只能通过行键来查询,表设计时难度更高。而mysql用来存储结构化的数据提供更好的事务控制。
比起hive,hive只是在mapreduce上包了一层壳,本质上还是离线数据的处理的工具,实时查询性能有限,本质上是一个基于hadoop的数据仓库工具,不能支持行级别的新增修改和删除。hbase可以提供实时的数据的处理能力,适用于在线数据查询处理,本质上是一种数据库工具。