大数据基础-分布式数据库HBase
- 概述
- HBase简介
- HBase与传统关系数据库的对比分析
- HBase数据模型
- 数据模型概述
- 数据模型相关概念
- 数据坐标
- HBase的实现原理
- HBase功能组件
- 表和Region
- Region的定位
- HBase框架结构
- HMaster
- RegionServer
- HBase协作组件
- Region
- ColumnFamily
- KeyValue
- 小结
- HBase运行机制
- HBase系统架构
- Region服务器工作原理
- 用户读写数据
- 缓存的刷新
- StoreFile的合并
- Store工作原理
- HLog工作原理
- HBase写流程
- Flush刷新写操作
- 多HFile的影响
- Compaction压缩
- Split分裂操作
- HBase读流程
- 精确查询
- Scanner
- BloomFilter
- HBase应用方案
- 在HBase上构建SQL引擎
- 构建HBase二级索引
- Hindex二级索引
- HBase+Redis
- Solr+HBase
概述
HBase简介
- HBase是一个高可靠、高性能、面向列 、可伸缩的分布式数据库,是谷歌BigTable的开源实现,主要用来存储非结构化和把结构化的松散数据。
- HBase的目标是处理非常庞大的表,可以通过水平扩展的方式,利用廉价计算机集群处理由超过10亿行数据和数百万列元素组成的数据表。
HBase和BigTable的底层技术对应关系
BigTable | HBase | |
---|---|---|
文件存储系统 | GFS | HDFS |
海量数据处理 | MapReduce | Hadoop MapReduce |
协同服务管理 | Chubby | Zookeeper |
问题:关系数据库已经流行多年,并且Hadoop已经有了HDFS和MapReduce,为什么需要HBase?
- 受限于Hadoop MapReduce编程框架高延迟数据处理机制,Hadoop无法满足大规模数据实时处理应用的需求。
- HDFS面向批量访问模式,不是随机访问模式。
- 传统的通用关系数据库无法应对在数据规模剧增时导致的系统扩展性和性能问题。
- 传统关系数据库在数据结构变化时一般需要停机维护,并且空列浪费存储空间。
因此,业界出现了一类面向半结构化数据存储和处理的高扩展性、低写入/查询延迟的系统。
HBase已经成功应用于互联网服务领域和传统行业的众多在线式数据分析处理系统中。
注:半结构化数据是指具有一定的结构,但又有一定的灵活可变性,典型如XML、HTML等数据。
HBase与传统关系数据库的对比分析
HBase与传统的关系数据库的区别主要体现在:
关系数据库 | HBase | |
---|---|---|
数据类型 | 采用关系模型,具有丰富的数据类型和存储方式 | 简单的数据模型,把数据存储为未经解释的字符串 |
数据操作 | 包含了丰富的操作,设计复杂的多表连接 | 不存在复杂的表与表之间的关系,只有简单地增删改查 |
存储模式 | 基于行模式存储 | 基于列模式存储,每个列族都由几个文件保存,不同列族的文件是分离的 |
数据索引 | 针对不同列构建复杂的多个索引 | 或者通过行键访问,或者通过行键扫描 |
数据维护 | 执行更新操作时,最新的当前值会替换记录中原来的旧值,旧值被覆盖后就不会存在 | 执行更新操作时,并不会删除数据旧的版本,而是生成一个新的版本,旧的版本仍然保留 |
可伸缩性 | 很难实现横向口占,纵向扩展的空间也比较有限 | 能够轻易在集群中增加或者减少硬件数量来实现性能的伸缩 |
HBase数据模型
数据模型概述
- HBase是一个稀疏、多维度、排序的映射表,这张表的索引是行键、列族、列限定符和时间戳
- 每一个值是一个未经解释的字符串,没有数据类型
- 每一行都有一个可排序的行键和任意多的列
- 表在水平方向由一个或者多个列族组成,一个列族可以包含任意多个列,同一个列族里面的数据存储在一起
- 列族支持动态扩展,无需预先定义列的数量以及类型,所有列均以字符串形式存储,用户需要自行进行数据类型转换
- HBase执行更新操作时,并不会删除数据旧的版本,而是生成一个新的版本,旧的版本仍然保留
数据模型相关概念
- 表:HBase采用表来组织数据,表由行和列组成,列划分为若干个列族
- 行:每个HBase表都由若干行组成,每个行由**行键(row key)**来标识
- 列族:一个HBase表被分组成许多**列族(Column Family)**的集合,它是基本的访问控制单元
- 列限定符:列族里的数据通过列限定符(或列)来定位
- 单元格:在HBase表中,通过行、列族和列限定符确定一个单元格(cell),单元格中存储的数据没有数据类型,总被视为字节数据byte[]
- 时间戳:每个单元格都保存着同一份数据的多个版本,这些版本采用时间戳进行索引
数据坐标
HBase中需要根据行键、列族、列限定符和时间戳来确定一个单元格,因此,可以视为一个 “四维坐标”,即 [行键,列族,列限定符,时间戳]
如:
HBase的实现原理
HBase功能组件
HBase的实现包括三个主要的功能组件:
- 库函数:链接到每个客户端
- 一个Master主服务器
- 许多个Region服务器
- 主服务器Master负责管理和维护HBase表的分区信息,维护Region服务器列表,分配Region,负载均衡
- Region服务器负责存储和维护分配给自己的Region,处理来自客户端的读写请求
- 客户端并不是直接从Master主服务器上读取数据,而是在获得Region的存储位置信息后,直接从Region服务器上读取数据
- 客户端并不依赖Master,而是通过Zookeeper来获得Region位置信息,大多数客户端甚至从来不和Master通信,这种设计方式使得Master负载很小。
表和Region
一个HBase表被划分为多个Region:
一个Region会分裂为多个新的Region(拆分操作非常快,接近瞬间):
不同的Region可以分布在不同的Region服务器上:
Region的定位
- 元数据表,又名.META.表,存储了Region和Region服务器的映射关系
- 当HBase表很大时,.META.表也会被分裂为多个Region
- 根数据表,又名-ROOT-表,记录所有元数据的具体位置
- -ROOT-表只有唯一一个Region,名字是在程序中被写死的
- Zookeeper文件记录了-ROOT表的位置
如下为HBase的三层结构:
- 为了加快访问速度,.META.表的全部Region都会被保存在内存中
- 假设.META.表的每行(一个映射条目)在内存中大约占用1KB,并且每个Region限制为128MB,那么,上面的三层结构可以保存的用户数据表的Region数目的计算方法是:
- (-ROOT-表能够寻址的.META.表的Region个数)×(每个.META.表的Region可以寻址的用户数据表的Region个数)
- 一个-ROOT-表最多只能有一个Region,也就是只能有128MB,按照每行占用1KB内存计算,128MB空间可以容纳128MB/1KB= 2 17 2^{17} 217行,也就是说,一个-ROOT-表可以寻址 2 17 2^{17} 217个.META.表的Region
- 同理,每个.META.表的Region可以寻址的用户数据表的Region个数是128MB/1KB= 2 17 2^{17} 217
- 最终,三层结构可以保存的Region数目是(128MB/1KB)×(128MB/1KB)= 2 34 2^{34} 234个Region
HBase框架结构
HMaster
在HA模式下,包含主用Master和备用Master
- 主用Master
- 备用Master(当主用Master故障时,备用Master将取代主用Master对外提供服务。故障恢复后,原主用Master降为备用)
HMaster的主要功能如下:
1)负责管理所有的RegionServer
- 新RegionServer的注册
- RegionServer Failover的处理
- 负责建表/修改表/删除表以及一些集群操作
2)负责所有Region的转移操作
- 新表创建时的Region分配
- 运行期间的负载均衡保障
- RegionServer Failover后的Region接管
RegionServer
RegionServer是HBase的数据服务进程,负责处理用户数据的读写请求:
- Region被交由RegionServer管理
- RegionServer负责提供表数据读写等服务,是HBase的数据处理和计算单元,所有用户数据的读写请求,都是和RegionServer上的Region进行交互
- Region可以在RegionServer之间进行转移
- RegionServer一般与HDFS集群的DataNode部署在一起,实现数据的存储功能
HBase协作组件
- Zookeeper:为HBase集群中各进程提供分布式协作服务,各RegionServer将自己的信息注册到Zookeeper中,主用Master据此感知各个RegionServer的健康状态
- HDFS:为HBase提供高可靠的文件存储服务,HBase的数据全部存储在HDFS中
Region
- Region是HBase分布式存储的最基本单元
- Region:将一个数据表按key值范围横向划分为一个个的子表,实现分布式存储
- 每一个Region都关联一个Key值范围,即一个使用StartKey和EndKey描述的区间。事实上,每一个Region仅仅记录StartKey即可,因为它的EndKey就是下一个Region的StartKey
Region分为元数据Region以及用户Region两类。
- Meta Region记录了每一个User Region的路由信息
- 读写Region数据的路由主要包括如下几步:
1)找寻Meta Region地址
2)再由Meta Region找寻User Region地址
Region结构
- Store:一个Region由一个或多个Store组成,每个Store对应图中的一个ColumnFamily
- MemStore:一个Store包含一个MemStore,MemStore缓存客户端向Region插入的数据。当RegionServer中的MemStore大小达到配置的容量上限时,RegionServer会将MemStore中的数据“flush”到HDFS中
- StoreFile:MemStore的数据flush到HDFS后成为StoreFile。随着数据的插入,一个Store会产生多个StoreFile
- Hfile:HFile定义了StoreFile在文件系统中的存储格式,它是当前HBase系统中StoreFile的具体实现
- Hlog:Hlog日志保证了当RegionServer故障的情况下用户写入的数据不丢失,RegionServer的多个Region共享一个相同的Hlog
ColumnFamily
- ColumnFamily是Region的一个物理存储单元。同一个Region下面的多个ColumnFamily,位于不同的路径下面。
- ColumnFamily信息是表级别的配置。也就是说,同一个表的多个Region,都拥有相同的ColumnFamily信息。
KeyValue
- KeyValue具有特定的结构。Key部分被用来快速的检索一条数据记录,Value部分用来存储实际的用户数据信息。
- KeyValue作为承载用户数据的基本单元,需要保存一些对自身的描述信息,例如,时间戳,类型等等。那么,势必会有一定的结构化空间开销。
和传统数据库或者是文件系统不同的是,HBase中的key-value是一起存储的,通过字段的形式一起以数据的类型存储到实际的存储空间中,key-value分为了三部分,第一部分记录的是key值的长度和value值的长度,第二部分是key值的具体字段(行键值长度,行键,列族长度,列族值,时间戳,key类型),第三部分是实际的value数据。
key值中的行键值、列族值,以及时间戳就是我们事先数据查询的三个重要字段,我们称之为三维有序存储。
小结
- 从框架进程上来讲,HBase分为Hmaster、Region和RegionServer
- 对于HBase来说,一个表按照横向进行划分,都由物理上的column进行存储,任意个column之间构成了columnfamily,由于columnfamily的基本单位是表,所以基于表横向创建的多个region他们就会拥有相同的columnfamily信息
HBase运行机制
HBase系统架构
注:Zookeeper可以帮助选举一个Master作为集群的总管,并保证在任何时刻总有唯一一个Master在运行,避免了Master的“单点失效”问题
Region服务器工作原理
用户读写数据
- 用户写入数据时,被分配到相应的Region服务器去执行
- 用户数据首先被写入到MemStore和Hlog中
- 只有当操作写入Hlog之后,commit()调用才会将其返回给客户端
- 当用户读取数据时,Region服务器会首先访问MemStore缓存,如果找不到,再去磁盘上面的StoreFile中寻找
缓存的刷新
- 系统会周期性地把MemStore缓存里的内容刷写到磁盘的StoreFile文件中,清空缓存,并在Hlog里面写入一个标记
- 每次刷写都生成一个新的StoreFile文件,因此,每个Store包含多个StoreFile文件
- 每个Region服务器都有一个自己的HLog 文件,每次启动都检查该文件,确认最近一次执行缓存刷新操作之后是否发生新的写入操作;如果发现更新,则先写入MemStore,再刷写到StoreFile,最后删除旧的Hlog文件,开始为用户提供服务
StoreFile的合并
- 每次刷写都生成了一个新的StoreFile,数量太多,影响查找速度
- 调用Store.compact()把多个合并成一个
- 合并操作比较耗费资源,只有数量达到一个阈值才启动合并
Store工作原理
StoreFile的合并和分裂过程
- Store是Region服务器的核心
- 多个StoreFile合并成一个
- 单个StoreFile过大时,又触发分裂操作,1个父Region被分裂成两个子Region
HLog工作原理
- HLog保证系统恢复
- 用户更新数据必须首先写入日志后,才能写入MemStore缓存,并且,直到MemStore缓存内容对应的日志已经写入磁盘,该缓存内容才能被刷写到磁盘(预写式日志)
- 当某个Region服务器发生故障时,Zookeeper会通知Master,Master首先会处理该故障Region服务器上面遗留的HLog文件,这个遗留的HLog文件中包含了来自多个Region对象的日志记录
- 系统会根据每条日志记录所属的Region对象对HLog数据进行拆分,分别放到相应Region对象的目录下,然后,再将失效的Region重新分配到可用的Region服务器中,并把与该Region对象相关的HLog日志记录也发送给相应的Region服务器
- Region服务器领取到分配给自己的Region对象以及与之相关的HLog日志记录以后,会重新做一遍日志记录中的各种操作,把日志记录中的数据写入到MemStore缓存中,然后,刷新到磁盘的StoreFile文件中,完成数据恢复
HBase写流程
Region写流程
- RegionServer请求需要写入数据的Region的读写锁
- 继续请求所需要修改的行的行锁
- RegionServer将数据写入到内存中,并且在写完成之后释放掉对应的行锁
- 行锁释放后,数据操作将会写入日志中
- 全部修改完成之后,RegionServer就会释放掉对应的Region的读写锁
- 数据在写入到MemStore之后,也会顺序写入到HLog中,以保证数据的安全
Flush刷新写操作
刷新操作会触发数据从内存中写入到对应的 HFile 中,如下三种场景,会触发一个 Region 的 Flush 操作
1)该Region的MemStore的总大小,达到了预设的FlushSize阈值
2)RegionServer的总内存大小超出了预设的阈值大小
3)当WALs中文件数量达到阈值时
多HFile的影响
随着时间的不断迁移,HFile文件数目越来越多,读取时延也越来越大
Compaction压缩
Compaction的主要目的是为了减少同一个Region同一个ColumnFamily下面的小文件数目,从而提升读取的性能
Compaction分为Minor、Major两类:
- Minor:小范围的Compaction。有最少和最大文件数目限制,通常会选择一些连续时间范围的小文件进行合并
- Major:涉及该Region该ColumnFamily下面的所有HFile文件
Split分裂操作
- 普通的RegionSplit操作,是指集群运行期间,某一个Region的数据大小超出了预设的阈值,则需要将该Region 自动分裂成为两个子Region。
- 分裂过程中,被分裂的Region会暂停读写服务。由于分裂过程中,父Region的数据文件并不会真正的分裂并重写到两个子Region中,而是仅仅通过在新Region中创建引用文件的方式,来实现快速的分裂。因此,Region暂停服务的时间会比较短暂。
- 客户端侧所缓存的父Region的路由信息需要被更新。
HBase读流程
精确查询
- 客户端发起请求
- 通过Zookeeper寻找到meta表所在RegionServer
- 请求发送到该RegionServer,由其具体处理数据读取
- 数据读取返回到客户端
Scanner
- Scanner可以理解为一个栈,一个store里面有memstore和hfile,当我们执行查询的时候,就会打开memstore的栈和各个hfile的栈,先从各个栈中poll出一条数据,然后做排序,next返回排序后的第一个数据,然后该栈继续poll出一条数据,继续排序
- 在寻找到rowkey所对应的RegionServer和Region之后,需要打开一个查找器
- Scanner,由其具体执行查找数据,Region中会包含内存数据MemStore,文件数据Hfiles,那么在openscanner的时候就需要分别读取这两块数据,打开对应不同的scanner做查询操作
BloomFilter
- BloomFilter被用来优化一些随机读取的场景,即Get场景。它可以被用来快速的判断一条用户数据在一个大的数据集合(该数据集合的大部分数据都没法被加载到内存中)中是否存在。
- BloomFilter在判断一个数据是否存在时,拥有一定的误判率。但对于“用户数据XXXX不存在”的判断结果是可信的。
- HBase的BloomFilter的相关数据,被保存在HFile中。
HBase应用方案
在HBase上构建SQL引擎
NoSQL区别于关系型数据库的一点就是NoSQL不使用SQL作为查询语言,至于为何在NoSQL数据存储HBase上提供SQL接口,有如下原因:
- 易使用
- 减少编码
方案
1.Hive整合HBase
2.Phoenix(是构建在Apache HBase之上的一个SQL中间层)
构建HBase二级索引
HBase只有一个针对行健的索引,访问HBase表中的行,只有三种方式:
- 通过单个行健访问
- 通过一个行健的区间来访问
- 全表扫描
使用其他产品为HBase行健提供索引功能:
- Hindex二级索引
- HBase+Redis
- HBase+solr
Hindex二级索引
Hindex 是华为公司开发的纯 Java 编写的HBase二级索引。当前的特性如下:
- 多个表索引
- 多个列索引
- 基于部分列值的索引
HBase+Redis
Coprocessor构建二级索引
Redis做客户端缓存
将索引实时更新到Redis等KV系统中,定时从KV更新索引到HBase的索引表中