参考:
http://hi.baidu.com/harry_lime/item/f9ef8487eb022ae9ef083d44
http://www.alidata.org/archives/1509
HBASE初探
从事后台开发两年多,近期多有关注分布式KEY-VALUE存储系统,就从HBASE开始深入浅出。
简介
项目名称 | 语言 | 容错性 | 持久性存储介质 | API协议 | 数据模型 | 文档 | 赞助商/社区 |
Java | 复制 分区 | 自定义磁盘 | Custom API, Thrift, Rest | Bigtable | A | Apache, yes |
HBASE是一个分布式、面向列的开源数据库,起源于BIGTABLE。它是Apache和Hadoop的子项目,建立于HDFS(hadoop distribute file system)之上。Hbase提供了高可靠性、高性能、列存储、可伸缩、实时读写的服务。
Hbase介于NOSQL(key-value)和RDBMS(Relational Database Management System)之间,支持通过主键(row-key)和主键的range来访问(检索)数据。于hadoop、业界其他分布式存储系统类似,hbase依靠横向扩展,不断增加廉价的商用服务器,来增加计算和存储能力。
HBASE适用场景:
1. 数据量大,一个表可以有上亿行,上百列
2. 面向列存储、查询
3. 稀疏:只存储存在的列数据,不浪费空间
4. 仅支持单行事务操作,不支持联合查询
数据存储形式
Row-key | Time tamp | Column Family2 ="content" | Column Family2 ="title" | Column Family2 ="desc" | |
Column0 | Column1 | Column2 | |||
xx.com | T6 | "time:2014-04-01" | |||
T5 | "xxx.com" | ||||
T4 | "xx.com" | ||||
T3 | "<html>aaaaaaaa…" | "<tbody>…" | |||
T2 | "<htmp>…" | "<tbody>…" | |||
Yy.com | …… |
HBASE以表的形式存储数据,表中有行(row-key)和列(column)组成,所有的列可分为若干个列族(column family)。详细见上表
ROW-KEY
跟NOSQL(KEY-VALUE)系统一样,HBASE的通过row-key来进行数据访问,访问hbase中的数据可以通过下列方式:
1. 指定row-key,访问对应的行(可制定column family,用于返回结果过滤)
2. 指定row-key对应的range
3. 遍历全表
Row-key可以是任意字符串,最大长度64KB。Hbase存储时,row-key保存为字节数组;表中数据按照row-key的字典序进行排序存储,所以,设计key时,可以充分利用这一点,讲热点数据存放到一起。
列族
表中每个列,都只股数与某一个列族。相同列族的列存放一起,列名都以列族作为前缀,访问控制、硬盘数据和内存的访问统计都在列族的层面进行;必须在使用表前进行列族定义。
时间戳
时间戳为64B整型,由HBase在数据写入时自动补充,或者用户显示复制。如果用户想避免数据版本冲突,需要保证相同row-key时间戳的唯一性。相同row-key、column family下的多份数据,按照时间戳倒序排列,即最新的数据放在最上面。
Cell
有<row-key, column =(family+lable), version>三元组唯一确定的单元。Cell中数据是以字符串形式存储。
硬盘数据
table 在行的方向上分割为多个region。Region按照大小分割,每个表最开始的时候只有一个region,随着数据的不断增长,region不断增大,当region增大到一定的阀值的时候,region会分裂成两个。随着行的不断增长,表就会有越来越多的region。
每个region是hbase分布式存储和负载均衡的最小单元;但是在硬盘上并不是最小存储粒度,它由一个或者多个Store组成,每个store保存一个columns family。每个store 又由一个menstore+0或多个storefile组成。Storefile以hfile形式存储在HDFS上。
系统架构
Client
支持访问HBASE,缓冲着部分cache来做访问加速,如hbase中region的位置信息
Zookeeper
保证任何时候,集群中只有一个master
存储所有region的寻址入口
实时监控region service的状态,并将上下线信息通知master
存储table和table中的列族信息
Master
1 为Region server分配region
2 负责region server的负载均衡
3 发现失效的region server并重新分配其上的region
4 GFS上的垃圾文件回收
5 处理schema更新请求
Region Server
1 Region server维护Master分配给它的region,处理对这些region的IO请求
2 Region server负责切分在运行过程中变得过大的region
可以看到,client访问hbase上数据的过程并不需要master参与(寻址访问zookeeper和region server,数据读写访问regione server),master仅仅维护者table和region的元数据信息,负载很低。
关键模块流程说明
Region定位
用户访问通过zookeeper或者缓存得到row-key所在的region service,再向region server请求访问数据。
Zookeeper是怎么存储key到region的映射关系的呢?下面简单介绍:
将所有的表的region路由信息(表名、region起始rowkey、时间戳对应的region详细的信息、region server地址作为一个路由信息),保存在路由表。表的路由信息也作为独立的表,存储在hbase上,分成二级表:-ROOT-和.META.,它们的数据结构类似:
Rowkey (region name) | info | ||
Region-info | server | serverstartcode | |
TableName+ startkey(region)+timestamp | Startkey, endkey,family list, ……其他统计信息 | Address (管理此region的RegionServer地址) |
其中-ROOT-表数据常驻zookeeper内存中,保存了.META.表的路由信息,且不会进行分裂(只有一个region)。而.META.表保存了整个HBase集群中所有表的region路由信息,可能会比较大,有多个region,所以是作为普通表,存储在某些region service上。为了加快访问,.META.表的全部region都保存在内存中。
HBase的设计中-ROOT-表不会太大:假设,.META.表的一行在内存中大约占用1KB。并且每个region限制为128MB。那么上面的三层结构下,集群可以保存的region数目为:(128MB/1KB) * (128MB/1KB) = = 2(34)个region = 2(51)B=4PB。
Client会将已经得到的路由信息缓存起来,并不主动失效;只有在region发生了变化后,才可能需要重新从zookeeper拉去路由。
读写过程
读:处理读请求时,需要访问Store中全部的 StoreFile和MemStore,将数据按照row-key进行合并。memstore和storefile中数据都是有序的,且storefile带有内存索引,所以合并过程比较快。
写:数据更新时,先写入HLOG,后写入memstore(有序)中。
Memstore满:当memstore写到一定阀值时,会创建一个新的memstore,并将老的memstore添加到flush队列中,等待落地成为一个Hfile,完成后在HLOG中记录redo point,标志此时间点前的流水已经持久化。Hfile落地有不做更新。
storeFile文件数满:当storefile文件数达到阀值时,会进行数据合并操作,将多个storefile合并成一个storefile,合并过程中会进行版本合并和数据删除。由此可知,HBASE的数据更新、删除都是异步延后操作。
storeFile单个满:当storefile单个大小达到阀值后,会进行region分裂(split)操作,即将storefile分成两个,并且将region 分裂成2个region,老的region会下架,新分裂出来的2个region有master分配到相应到region server上。
HLOG
分布式存储系统中需要充分考虑的是容灾处理,上述写流程中,对于单机故障(死机)时,memstore的数据将会丢失,所以使用HLOG记录memstore中的数据。Region server异常死机后,master通过zookeeper感知到。Master首先会处理遗留的HLOG文件,将log文件根据region进行拆分,放到region目录下,新的server领导region后,会处理这些log(将此信息从hlog恢复到memstore,后flush到storefile,完成数据恢复)。通过hlog可以重建memstore中未及时落地的数据,
Region管理
任何时刻,一个region只能分配给一个region server。Master中记录了资源管理信息、和状态存活信息,即region的使用情况、和分配归属于那个region server,和有哪些可用region server。当master收到region申请请求,首先找到未使用的region和可用的region server,master给这个region server发送装载请求,将此region分配出去。Region server得到请求后,将开始对此region服务。
region server上线
master使用zookeeper来跟踪region server状态。当某个region server启动时,会首先在zookeeper上的server目录下建立代表自己的文件,并获得该文件的独占锁。由于master订阅了server 目录上的变更消息,当server目录下的文件出现新增或删除操作时,master可以得到来自zookeeper的实时通知。因此一旦region server上线,master能马上得到消息。
region server下线
当region server下线时,它和zookeeper的会话断开,zookeeper而自动释放代表这台server的文件上的独占锁。而master不断轮询 server目录下文件的锁状态。如果master发现某个region server丢失了它自己的独占锁,(或者master连续几次和region server通信都无法成功),master就是尝试去获取代表这个region server的读写锁,一旦获取成功,就可以确定:
1 region server和zookeeper之间的网络断开了。
2 region server挂了。
的其中一种情况发生了,无论哪种情况,region server都无法继续为它的region提供服务了,此时master会删除server目录下代表这台region server的文件,并将这台region server的region分配给其它还活着的同志。
如果网络短暂出现问题导致region server丢失了它的锁,那么region server重新连接到zookeeper之后,只要代表它的文件还在,它就会不断尝试获取这个文件上的锁,一旦获取到了,就可以继续提供服务。
其他问题
容错性
Master容错:Zookeeper重新选择一个新的Master
ü 无Master过程中,数据读取仍照常进行;
ü 无master过程中,region切分、负载均衡等无法进行;
RegionServer容错:
定时向Zookeeper汇报心跳,如果一旦时间内未出现心跳,Master 将该RegionServer上的Region重新分配到其他RegionServer上,失效服务器上“预写”日志由主服务器进行分割并派送给新的RegionServer
Zookeeper容错:Zookeeper是一个可靠地服务,一般配置3或5个Zookeeper实例
数据容灾:数据主要为region中的memstore和storefile,其中memstore通过HLOG达到故障容灾,storefile使用HDFS进行存储,依赖HDFS进行容灾。
访问接口
暂时未使用
使用场景
大数据量存储,大数据量高并发操作
需要对数据随机读写操作
读写访问均是非常简单的操作