Hbase特点
- Hbase有4个维度来确定某个具体的值,行键、列族、列名、时间戳,
- 强一致性
- 每个值只出现在一个REGION
- 同一时间一个Region只分配给一个Region服务器
- 行内的mutation操作都是原子的(原子性操作是指:如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行)。
- put操作要么成功,要么完全失败。
- 稀疏多维列表
- 多维稀疏排序Map
BigTable本质上是一个Map结构数据库,HBase亦然,也是由一系列KV构成的。然而HBase这个Map系统却有很多限定词——稀疏的、分布式的、持久性的、多维的以及排序的。大家都知道Map由key和value组成,那组成HBase Map的key和value分别是什么?和普通Map的KV不同,HBase中Map的key是一个复合键,由rowkey、column family、qualif ier、type以及timestamp组成,value即为cell的值。
至此,我们对HBase中数据的存储形式有了初步的了解,在此基础上再来介绍多维、稀疏、排序等关键词:
-
- 多维:这个特性比较容易理解。HBase中的Map与普通Map最大的不同在于,key是一个复合数据结构,由多维元素构成,包括rowkey、columnfamily、qualif ier、type以及timestamp。
- 稀疏:稀疏性是HBase一个突出特点。从上图逻辑表中行"0001"可以看出,整整一行仅有一列(info:name)有值,其他列都为空值。在其他数据库中,对于空值的处理一般都会填充null,而对于HBase,空值不需要任何填充。这个特性为什么重要?因为HBase的列在理论上是允许无限扩展的,对于成百万列的表来说,通常都会存在大量的空值,如果使用填充null的策略,势必会造成大量空间的浪费。因此稀疏性是HBase的列可以无限扩展的一个重要条件。
- 排序:构成HBase的KV在同一个文件中都是有序的,但规则并不是仅仅按照rowkey排序,而是按照KV中的key进行排序——先比较rowkey,rowkey小的排在前面;如果rowkey相同,再比较column,即column family:qualifier,column小的排在前面;如果column还相同,再比较时间戳timestamp,即版本信息,timestamp大的排在前面。
- 分布式:很容易理解,构成HBase的所有Map并不集中在某台机器上,而是分布在整个集群中。
- HDFS 压缩存储
- 自动水平扩展
- 服务器自动调整平衡
1.HDFS为Hbase提供可靠的底层数据存储服务,
- MapReduce为Hbase提供高性能的计算能力,
- Zookeeper为Hbase提供稳定服务和Failover【失效转移
通俗地说,即当A无法为客户服务时,系统能够自动地切换,使B能够及时地顶上继续为客户提供服务,且客户感觉不到这个为他提供服务的对象已经更换。】机制,
因此我们说Hbase是一个通过大量廉价的机器解决海量数据的高速存储和读取的分布式数据库解决方案。
Hbase 架构各个角色的功能
- Client
Client包含了访问Hbase的接口,另外Client还维护了对应的cache来加速Hbase的访问,比如cache的.META.元数据的信息。
- Zookeeper
Hbase通过Zookeeper来做master的高可用【通过设计减少系统不能提供服务的时间】、RegionServer的监控、元数据的入口以及集群配置的维护等工作。具体工作如下:
- 通过Zoopkeeper来保证集群中只有1个master在运行,如果master异常,会通过竞争机制产生新的master提供服务
- 通过Zoopkeeper来监控RegionServer的状态,当RegionSevrer有异常的时候,通过回调的形式通知Master RegionServer上下限的信息
- 通过Zoopkeeper存储元数据的统一入口地址
- Hmaster
master节点的主要职责如下:
- 为RegionServer分配Region
- 维护整个集群的负载均衡
- 维护集群的元数据信息
- 发现失效的Region,并将失效的Region分配到正常的RegionServer
- 当RegionSever失效的时候,协调对应Hlog的拆分
- HregionServer
HregionServer直接对接用户的读写请求,是真正的“干活”的节点。它的功能概括如下:
- 管理master为其分配的Region
- 处理来自客户端的读写请求
- 负责和底层HDFS的交互,存储数据到HDFS
- 负责Region变大以后的拆分
- 负责Storefile的合并工作
- HDFS
HDFS为Hbase提供最终的底层数据存储服务,同时为Hbase提供高可用(Hlog存储在HDFS)的支持,具体功能概括如下:
- 提供元数据和表数据的底层分布式存储服务
- 数据多副本,保证的高可靠和高可用性
Hbase的使用场景
Hbase是一个通过廉价PC机器集群来存储海量数据的分布式数据库解决方案。它比较适合的场景概括如下:
- 是巨量大(百T、PB级别)
- 查询简单(基于rowkey或者rowkey范围查询)
- 不涉及到复杂的关联
- 有几个典型的场景特别适合使用Hbase来存储:
海量订单流水数据(长久保存)
交易记录
Hbase的写逻辑
Hbase的写逻辑涉及到写内存、写log、刷盘等操作,看起来简单,其实里面又有很多的逻辑,下面就来做详细的介绍。
第1步:Client从ZK获取数据写入的Region所在的RegionServer
第2步:请求写Hlog
第3步:请求写MemStore
只有当写Hlog和写MemStore都成功了才算请求写入完成。MemStore后续会逐渐刷到HDFS中。
PS:Hlog存储在HDFS,当RegionServer出现异常,需要使用Hlog来恢复数据。
MemStore刷盘几种时机
为了提高Hbase的写入性能,当写请求写入MemStore后,不会立即刷盘。而是会等到一定的时候进行刷盘的操作。具体是哪些场景会触发刷盘的操作呢?总结成如下的几个场景:
全局内存控制
这个全局的参数是控制内存整体的使用情况,当所有memstore占整个heap的最大比例的时候,会触发刷盘的操作。这个参数是hbase.regionserver.global.memstore.upperLimit,默认为整个heap内存的40%。但这并不意味着全局内存触发的刷盘操作会将所有的MemStore都进行刷盘,而是通过另外一个参数hbase.regionserver.global.memstore.lowerLimit来控制,默认是整个heap内存的35%。当flush到所有memstore占整个heap内存的比率为35%的时候,就停止刷盘。这么做主要是为了减少刷盘对业务带来的影响,实现平滑系统负载的目的。
MemStore达到上限
当MemStore的大小达到hbase.hregion.memstore.flush.size大小的时候会触发刷盘,默认128M大小
RegionServer的Hlog数量达到上限
前面说到Hlog为了保证Hbase数据的一致性,那么如果Hlog太多的话,会导致故障恢复的时间太长,因此Hbase会对Hlog的最大个数做限制。当达到Hlog的最大个数的时候,会强制刷盘。这个参数是hase.regionserver.max.logs,默认是32个。
手工触发
可以通过hbase shell或者java api手工触发flush的操作。
关闭RegionServer触发
在正常关闭RegionServer会触发刷盘的操作,全部数据刷盘后就不需要再使用Hlog恢复数据。
Region使用HLOG恢复完数据后触发
当RegionServer出现故障的时候,其上面的Region会迁移到其他正常的RegionServer上,在恢复完Region的数据后,会触发刷盘,当刷盘完成后才会提供给业务访问。
Hlog
Hlog简介
Hlog是Hbase实现WAL(Write ahead log)方式产生的日志信息,内部是一个简单的顺序日志。每个RegionServer对应1个Hlog(备注:1.x版本的可以开启MultiWAL功能,允许多个Hlog),所有对于该RegionServer的写入都被记录到Hlog中。Hlog实现的功能就是我们前面讲到的保证数据安全。当RegionServer出现问题的时候,能跟进Hlog来做数据恢复。此外为了保证恢复的效率,Hbase会限制最大保存的Hlog数量,如果达到Hlog的最大个数(hase.regionserver.max.logs参数控制)的时候,就会触发强制刷盘操作。对于已经刷盘的数据,其对应的Hlog会有一个过期的概念,Hlog过期后,会被监控线程移动到.oldlogs,然后会被自动删除掉。
Hlog结构
- 都个Region共享一个Hlog文件,
- 单个Region在Hlog中是按照时间顺序存储的,
- 但是多个Region可能并不是完全按照时间顺序
每个Hlog最小单元由Hlogkey和WALEdit两部分组成。Hlogky由sequenceid、timestamp、cluster ids、regionname以及tablename等组成,WALEdit是由一系列的KeyValue组成,对一行上所有列(即所有KeyValue)的更新操作,都包含在同一个WALEdit对象中,这主要是为了实现写入一行多个列时的原子性。
- Hlog
- Hlogkey
- sequenceid : 一个store级别的自增序列号,region的数据恢复和Hlog过期清除都要依赖这个信息
- timestamp
- cluster ids
- regionname
- tablename
- WALEdit
- n个 KeyValue
- Hlogkey
sequenceid的相关逻辑:Memstore在达到一定的条件会触发刷盘的操作,刷盘的时候会获取刷新到最新的一个sequenceid的下一个sequenceid,并将新的sequenceid赋给oldestUnflushedSequenceId,并刷到Ffile中。
Hlog文件对应所有Region的store中最大的sequenceid如果已经刷盘,就认为Hlog文件已经过期,就会移动到.oldlogs,等待被移除
当RegionServer出现故障的时候,需要对Hlog进行回放来恢复数据。回放的时候会读取Hfile的oldestUnflushedSequenceId中的sequenceid和Hlog中的sequenceid进行比较,小于sequenceid的就直接忽略,但与或者等于的就进行重做。回放完成后,就完成了数据的恢复工作
Hlog的生命周期
产生
所有涉及到数据的变更都会先写Hlog,除非是你关闭了Hlog
滚动
Hlog的大小通过参数hbase.regionserver.logroll.period控制,默认是1个小时,时间达到hbase.regionserver.logroll.period 设置的时间,Hbase会创建一个新的Hlog文件。这就实现了Hlog滚动的目的。Hbase通过hbase.regionserver.maxlogs参数控制Hlog的个数。滚动的目的,为了控制单个Hlog文件过大的情况,方便后续的过期和删除。
过期
Hlog的过期判断依赖于sequenceid。Hbase会将Hlog的sequenceid和Hfile最大的sequenceid(刷新到的最新位置)进行比较,如果该Hlog文件中的sequenceid比刷新的最新位置的sequenceid都要小,那么这个Hlog就过期了,过期了以后,对应Hlog会被移动到.oldlogs目录。
要将过期的Hlog移动到.oldlogs目录,而不是直接删除,原因如下:
因为Hbase还有一个主从同步的功能,这个依赖Hlog来同步Hbase的变更,有一种情况不能删除Hlog,那就是Hlog虽然过期,但是对应的Hlog并没有同步完成,因此比较好的做好是移动到别的目录。再增加对应的检查和保留时间。
删除
如果Hbase开启了replication,当replication执行完一个Hlog的时候,会删除Zoopkeeper上的对应Hlog节点。在Hlog被移动到.oldlogs目录后,Hbase每隔hbase.master.cleaner.interval(默认60秒)时间会去检查.oldlogs目录下的所有Hlog,确认对应的Zookeeper的Hlog节点是否被删除,如果Zookeeper 上不存在对应的Hlog节点,那么就直接删除对应的Hlog。
hbase.master.logcleaner.ttl(默认10分钟)这个参数设置Hlog在.oldlogs目录保留的最长时间。
RegionServer的故障恢复
我们知道,RegionServer的相关信息保存在ZK中,在RegionServer启动的时候,会在Zookeeper中创建对应的临时节点。RegionServer通过Socket和Zookeeper建立session会话,RegionServer会周期性地向Zookeeper发送ping消息包,以此说明自己还处于存活状态。而Zookeeper收到ping包后,则会更新对应session的超时时间。
当Zookeeper超过session超时时间还未收到RegionServer的ping包,则Zookeeper会认为该RegionServer出现故障,ZK会将该RegionServer对应的临时节点删除,并通知Master,Master收到RegionServer挂掉的信息后就会启动数据恢复的流程。