HBase简介
- HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统。
- 适合于存储大表数据(表的规模可以达到数十亿行以及数百万列),并且对大表数据的读、写访问可以达到实时级别。
- 利用HadoopHDFS(HadoopDistributed File System)作为其文件存储系统,提供实时读写的分布式数据库系统。
- 利用ZooKeeper作为协同服务。
HBase与关系型数据库的对比
HBase与传统的关系数据库的区别主要体现在以下几个方面:
- 数据索引:关系数据库通常可以针对不同列构建复杂的多个索引,以提高数据访问性能。HBase只有一个索引一一行键,通过巧妙的设计,HBase中的所有访问方法,或者通过行键访问,或者通过行键扫描,从而使得整个系统不会慢下来。
- 数据维护:在关系数据库中,更新操作会用最新的当前值去替换记录中原来的日值,旧值被覆盖后就不会存在。而在HBase中执行更新操作时,并不会删除数据旧的版本,而是生成一个新的版本,旧有的版本仍然保留。
- 可伸缩性:关系数据库很难实现横向扩展,纵向扩展的空间也比较有限。相反,HBase和BigTable这些分布式数据库就是为了实现灵活的水平扩展而开发的,能够轻易地通过在集群中增加或者减少硬件数量来实现性能的伸缩。
数据模型
- 应用程序是以表的方式在HBase存储数据的。表是由行和列构成的,所有的列是从属于某一个列族的。
- 表结构稀疏,行和列的交叉点称之为单元格(cell),cell是版本化的。cell的内容是不可分割的字节数
- 组。
- 表的行键也是一段字节数组,所以任何东西都可以保存进去,不论是字符串或者数字。所有的表都必须要有主键-key。HBase的表是按key排序的,排序方式是针对字节的。
HBase表结构
- 表:HBase采用表来组织数据,表由行和列组成,列划分为若干个列族。
- 行:每个HBase表都由若干行组成,每个行由行键(RowKey)来标识。
- 列族:一个HBase表被分组成许多“列族”(ColumnFamily)的集合,它是基本的访问控制单元。
- 列限定符:列族里的数据通过列限定符(或列)来定位。
- 单元格:在HBase表中,通过行、列族和列限定符确定一个“单元格”(cell),单元格中存储的数据没有数据类型,总被视为字节数组byte[]。
- 时间戳:每个单元格都保存着同一份数据的多个版本,这些版本采用时间戳进行索引。
数据存储概念视图
有一个名为webtable的表,包含两个列族:contents和anchor.在这个例子里面,anchor有两个列(anchor:aa.com, anchor:bb.com),contents仅有一列(contents:html)。
数据存储物理视图
尽管在概念视图里,表可以被看成是一个稀疏的行的集合。但在物理上,它是区分列族存储的。新的columns可以不经过声明直接加入一个列族。
行存储和列存储的比较
行存储,数据按行存储在底层文件系统中。通常,每一行会被分配固定的空间。
- 优点:有利于增加/修改整行记录等操作;有利于整行数据的读取操作。
- 缺点:单列查询时,会读取一些不必要的数据。
列存储,数据以列为单位,存储在底层文件系统中。
- 优点:有利于面向单列数据的读取/统计等操作。
- 缺点:整行读取时,可能需要多次|/O操作。
HBase体系架构图
客户端
- 客户端包含访问HBase的接口,但并不直接从HMaster主服务器上读取数据,而是通过Zookeeper获得Region位置信息后,直接从HRegionServer上读取数据。大多数客户端甚至从来不和HMaster通信,这种设计方式使得HMaster负载很小。
- 客户端会在缓存中维护着已经访问过的Region位置信息,用来加快后续数据访问过程。
HMaster
主服务器HMaster主要负责表和Region的管理工作:
- 管理用户对表的增加、删除、修改、查询等操作。
- 实现不同HRegionServer之间的负载均衡。
- 在Region分裂或合并后,负责重新调整Region的分布。
- 对发生故障失效的HRegionServer上的Region进行迁移。
HMaster高可用
- Zookeeper可以帮助选举出一个HMaster作为集群的总管,并保证在任何时刻总有唯一个HMaster在运行,这就避免了HMaster的“单点失效”问题。
HRegionServer
HRegionServer是HBase中最核心的模块。
- 负责存储和维护分配给自己的Region。
- 处理来自客户端的读写请求。
HBase表(Table)
Region
- HBase表开始只有一个Region,当Region的大小超出了预设的阈值时,HBase会拆分Region。
- Region拆分操作非常快,接近瞬间,因为拆分之后的Region读取的仍然是原存储文件,直到分裂过程结束,把存储文件异步地写到独立的文件之后,才会读取新文件。
Region的定位
用户读写数据的过程
- 用户写入数据时,被分配到相应HRegionServer去执行。
- 用户数据首先被写入到Hlog中,再写入MemStore中,最终写到磁盘上形成StoreFile。
- 只有当操作写入Hlog之后,commit(调用才会将其返回给客户端。
- 当用户读取数据时,HRegionServer会首先访问MemStore缓存,如果找不到,再去磁盘上面的StoreFile中寻找。
缓存的刷新
- 系统会周期性地把MemStore缓存里的内容刷写到磁盘的StoreFile文件中,清空缓存,并在Hlog里面写入一个标记。
- 每次刷写都生成一个新的StoreFile文件,因此,每个Store包含多个StoreFile文件。
- 每个HRegionServer都有一个自己的HLog文件,每次启动都检查该文件,确认最近一次执行缓存刷新操作之后是否发生新的写入操作;如果发现更新,则先写入MemStore,再刷写到StoreFile,开始为用户提供服务。
Store工作原理
- Store是HRegionServer的核心。
- StoreFile的合并:每次刷写都生成一个新的StoreFile,数量太多,影响查找速度。调用Store.compact()把多个StoreFile合并成一个。
- 单个StoreFile过大时,又触发分裂操作,1个父Region被分裂成两个子Region。
HLog工作原理
- 分布式环境必须要考虑系统出错,HBase采用HLog保证系统恢复。
- HBase系统为每个HRegionServer配置了一个HLog文件,它是一种预写式日志(Write Ahead Log)。
- 用户更新数据必须首先写入日志后,才能写入MemStore缓存,并且,直到MemStore缓存内容对应的日志已经写入磁盘,该缓存内容才能被刷写(Flush)到磁盘。
- Zookeeper会实时监测每个HRegionServer的状态,当某个HRegionServer发生故障时,Zookeeper会通知HMaster。
- HMaster首先会处理该故障HRegionServer上面遗留的HLog文件,这个遗留的HLog文件中包含了来自多个Region对象的日志记录。
- 系统会根据每条日志记录所属的Region对象对HLog数据进行拆分,分别放到相应Region对象的目录下,然后,再将失效的Region重新分配到可用的HRegionServer中,并把与该Region对象相关的HLog日志记录也发送给相应的HRegionServer。
- HRegionServer领取到分配给自己的Region对象以及与之相关的HLog日志记录以后,会重新做一遍日志记录中的各种操作,把日志记录中的数据写入到MemStore缓存中,然后,刷新到磁盘的StoreFile文件中,完成数据恢复。
- 共用日志优点:提高对表的写操作性能;缺点:恢复时需要分拆日志。
Compaction机制
- HFile文件数目越来越多,读取时延也越来越大。
- Compaction的目的,是为了减少同一个Region中同一个ColumnFamily下面的小文件(HFile)数目,从而提升读取的性能。
- ·Compaction分为Minor、Major两类:
- MinorCompaction:小范围的Compaction。有最少和最大文件数目限制。通常会选择一些连
- 续时间范围的小文件进行合并。
- Major Compaction:涉及该Region该ColumnFamily下面的所有的HFile文件。
- Minor Compaction选取文件时,遵循一定的算法。
OpenScanner
OpenScanner的过程中,会创建两种不同的Scanner来读取Hfile、MemStore的数据:
- HFile对应的Scanner为StoreFileScanner。
- MemStore对应的Scanner为MemStoreScanner。
BloomFilter
- BloomFilter用来优化一些随机读取的场景,即Get场景。它可以被用来快速的判断一条用户数据在一个大的数据集合(该数据集合的大部分数据都没法被加载到内存中)中是否存在。
- BloomFilter在判断一个数据是否存在时,拥有一定的误判率。但对于“用户数据XXXX不存在”的判断结果是可信的。
- HBase的BloomFilter的相关数据,被保存在HFile中。
行键(RowKey)
- 行键是按照字典序存储,因此,设计行键时,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。
- 举个例子:如果最近写入HBase表中的数据是最可能被访问的,可以考虑将时间戳作为行键的一部分,由于是字典序排序,所以可以使用Long.MAX_VALUE-timestamp作为行键,这样能保证新写入的数据在读取时可以被快速命中。
- HBase只有一个针对行健的索引。
- 访问HBase表中的行,只有三种方式:
- 通过单个行健访问
- 通过一个行健的区间来访问
- 全表扫描
构建HBase二级索引
Hindex是华为公司开发的纯Java编写的HBase二级索引,兼容ApacheHBase0.94.8。当前的特性如下:
- 多个表索引
- 多个列索引
- 基于部分列值的索引
HBase常用Shell命令
- create:创建表
- list:列出HBase中所有的表信息
- put:向表、行、列指定的单元格添加数据
- scan:浏览表的相关信息
- get:通过表名、行、列、时间戳、时间范围和版本号来获得相应单元格的值
- enable/disable:使表有效或无效
- drop:删除表
总结
- HBase是BigTable的开源实现,和BigTable一样,支持大规模海量数据,分布式并发数据处理效率极高,易于扩展且支持动态伸缩,适用于廉价设备。HBase实际上是一个稀疏、多维、持久化存储的映射表,它采用行键、列键和时间戳进行索引,每个值都是未经解释的字符串。