HBase是一个高可靠、高性能、面向列的,主要用于海量结构化和半结构化数据存储的分布式key-value存储系统。
HBase以表的形式将数据最终存储的hdfs上,建表时无需指定表中字段,只需指定若干个列簇即可。插入数据时,指定任意多个列到指定的列簇中。 通过行键、列簇、列和时间戳可以对数据进行快速定位。
hbase表结构
行键
行键(row key) HBase基于row key唯一标识一行数据,是用来检索数据的主键。HBase通过对row key进行字典排序从而对表中数据进行排序。基于这个特性,在设计row key时建议将经常一起读取的数据存储在一起。
列簇(column family)
HBase中的表可以有若干个列簇,一个列簇下面可以有多个列。
必须在建表时指定列簇,但不需要指定列。一个列簇的所有列存储在同一个底层文存储件中。
HBase对访问控制、磁盘和内存的使用统计都是在列簇层面进行的, 列簇越多,在取一行数据时所要参与IO、搜寻的文件就越多。所以如果没有必要,不要设置太多的列簇,也不要修改的太频繁。将经常一起查询的列放到一个列簇中,减少文件的IO、寻址时间,提升访问性能。
列(qualifier)
列属于唯一特定列簇,按照字典序排序,列名已列簇名为前缀 column family:qualifier,例 city:beijing
Cell
通过{row key, column family:qualifier, version}可以唯一确定的存贮单元。 cell中的数据全部以字节码形式存贮。 类似数据类型:SortedMap<RowKey, List<SortedMap<Column, List<Value,Timestamp>>>>
时间戳(timestamp)
每个cell都可以保存同一份数据的不同版本,不同版本的数据按照时间倒序排序,读取时优先读取最新值,并通过时间戳来索引。时间戳的类型是64位整型,可以由客户端显式赋值或者由HBase在写入数据时自动赋值(此时时间戳是精确到毫秒的当前系统时间)。
hbase系统架构
feature
- 强一致性读/写, 非最终一致性
- 自动分片:hbase表分布在不同的region上, 随着数据增长,region可以自动拆分和分配
- regionServer自动故障转移
- hbase使用 HDFS作为其分布式文件存储
- MapReduce: 支持将HBase做为 source 和 sink 进行 MapReduce 大规模并行处理
- hbase 支持易于使用的 Java api 进行编程访问, 同时还支持 Thrift 和 REST
- 块缓存和布隆过滤器:HBase 支持块缓存和布隆过滤器,用于大容量查询优化
- 数据规模:数亿、数十亿数据,使用hbase是个不错的选择
- 不支持 指定类型列、二级索引、事务、sql高级查询语句
- hbase建立在hdfs之上(使用hdfs存储索引化的 storeFiles), 提供了大型表的快速记录查找和更新
Master
- Master server 负责监控集群中所有的 RegionServer 实例,并且提供了所有元数据更改的接口
- 管理HRegion服务器的负载均衡,移动region调整分布来平衡集群负载(LoadBalancer进程周期运行)
- 在HRegion分裂后,负责新HRegion的分配
- 在HRegion服务器停机后,负责失效HRegion服务器上的HRegion迁移
- 因为hbase client直接和 regionServer连接,所以master挂了,集群仍然可以运行。但是Master 控制关键功能,例如 RegionServer 故障转移和region拆分,所以得尽快重启master。
HMaster Interface 暴露的方法主要是面向元数据的方法:
- Table(createTable、modifyTable、removeTable、enable, disable)
- ColumnFamily (addColumn, modifyColumn, removeColumn)
- Region (move, assign, unassign | 移动、分配、取消分配)
master 启动
- 从zookeeper上获取唯一一个代表active master的锁,用来阻止其它master成为master
- 扫描zookeeper上的server父节点,获得当前可用的region server列表
- 和每个region server通信,获得当前已分配的region和region server的对应关系
- 扫描.META.region的集合,计算得到当前还未分配的region,将他们放入待分配region列表
RegionServer
负责table数据的实际读写,Region的管理。
Interface 数据操作和region维护的接口
- Data (get, put, delete, next, etc.)
- Region (splitRegion, compactRegion, etc.)
regionServer Split
- memstore: write数据首先写入 memstore 。memstore flush: 一旦 memstore写满了,其中的数据就会以store file刷写到磁盘中。
- compact: 随着数据不断写入,会产生越来越多的store file小文件,HBase内部通过将多个文件合并成一个较大的文件解决这一小文件问题 。
- split: RegionServer 参考区域拆分策略来确定region是否已经变得太大, 提交region split请求。
细节:逻辑上,我们只需要找到合适的点将 region的数据拆分为两半就完成了split, 实际split过程却复杂的多。新创建的region并不会立即将数据重写到新的文件中,而是通过创建类似软链接文件(refrence files)的方式分别指向原来Region Storefile的前半部分和后半部分,当原Region数据文件不再被访问时,Region开始进行分裂。Reference files会随着分裂compact而逐渐被清除,最终Region不再引用原Region,分裂逐渐完成,原Region被清除。
regionServer Compaction
Compaction 是一种通过将 StoreFile 合并在一起来减少 StoreFile 数量的操作,以提高读取操作的性能。HBase根据合并规模将Compaction分为两类:Minor_compation 和 Major_compation
- minor合并 将多个小文件重写为数量较少的大文件,减少存储文件数量(多路归并),因为hfile的每个文件都是经过归类的,所以合并速度很快,主要受磁盘IO性能影响。不会丢弃或删除过期版本。
- major合并 将一个region中的一个列簇的若干个hfile重写为一个新的hfile, 而且major合并能扫描所有的键/值对,顺序重写全部数据,重写过程中会略过做了删除标记的数据。 IO消耗大,一般手工操作。
- Compaction and Deletions
当 HBase 中发生显式删除时,数据实际上并没有被删除, 而是进行标记删除; major compaction 期间,数据会被真实删除,标记也会从 storeFile中删除。TTL过期被删除数据,不会创建删除标记,过期数据直接被过滤,不会被重写到compacted StoreFile。- Compaction and Versions
- 创建列簇时,可以指定要保留的最大版本数,默认值为 1。如果存在超过指定最大值的版本,则过滤掉多余的版本, 并且不会被重写到compacted StoreFile。
Write Ahead Log (WAL) 预写日志
WAL(Write-Ahead Log)预写日志是一个保险机制。当向Hbase写入一条数据时,Hbase首先会将数据写入WAL,然后再把数据放入内存中(Memstore)。如果在刷新 MemStore 之前 RegionServer 崩溃或变得不可用,WAL 可以重放对数据的更改。如果写入 WAL 失败,则整个修改数据的操作都会失败。
Regions 是表可用性和分布的基本元素,由每个列簇的一个store组成
- 一个HregionServer可以有多个Hregion
- 一个列族column family的数据是存储在一起的,所以一个列族的数据存储在一个Store里面
- Store 包括 Mem Store、Store File、HFile
- HBase在写数据的时候,会先写到Mem Store,当MemStore超过一定阈值,就会将内存中的数据刷写到硬盘上,形成StoreFile,而StoreFile底层是以HFile的格式保存,HFile是HBase中KeyValue数据的存储格式
Region 是Hbase中分布式存储和负载均衡的最小单元,不同Region分布到不同RegionServer, 但region不是物理存储的最小单元。