HBase:分布式列式NoSQL数据库
传统的ACID数据库,可扩展性上受到了巨大的挑战。而HBase这类系统,兼具可扩展性的同时,也提出了类SQL的接口。
HBase架构组成
HBase采用Master/Slave架构搭建集群,它隶属于Hadoop生态系统,由一下类型节点组成:HMaster节点、HRegionServer节点、ZooKeeper集群,而在底层,它将数据存储于HDFS中,因而涉及到HDFS的NameNode、DataNode等,总体结构如下:
HBase Client通过RPC方式和HMaster、HRegionServer通信
HMaster节点
- 协调HRegionServer
- 启动时HRegion的分配,以及负载均衡和修复时HRegion的重新分配。
- 监控集群中所有HRegionServer的状态(通过与zookeeper的Heartbeat和监听ZooKeeper中的状态,并不直接和slave相连)
- Admin职能:创建、删除、修改Table的定义。
HRegionServer节点
- 存放和管理本地HRegion。
- 读写HDFS,管理Table中的数据。
- Client直接通过HRegionServer读写数据
一个HRegionServer可以存放1000个HRegion(出自BigTable);HBase使用RowKey将表水平切割成多个HRegion,从HMaster的角度,每个HRegion都纪录了它的StartKey和EndKey(第一个HRegion的StartKey为空,最后一个HRegion的EndKey为空),由于RowKey是排序的,因而Client可以通过HMaster快速的定位每个RowKey在哪个HRegion中。
底层Table数据存储于HDFS中,而HRegion所处理的数据尽量和数据所在的DataNode在一起,实现数据的本地化;数据本地化并不是总能实现,比如在HRegion移动(如因Split)时,需要等下一次Compact才能继续回到本地化。
ZooKeeper集群是协调系统
- 存放整个HBase集群的元数据以及集群的状态信息(avalible/alive)。
- 实现HMaster主从节点的failover,并在HRegionServer宕机的时候通知HMaster。
HBase的第一次读写
0.96以前的版本(参考BigTable)
HBase有两个特殊的表,ROOT表(唯一)和META表。其中,ROOT表的位置保存在ZooKeeper中,它存储了META表的RegionInfo信息。而META表 则存储了用户Table的RegionInfo信息,它可以被切分成多个HRegion。
- 从ZooKeeper读取ROOT表位置
- HRegionServer中根据请求的Root表和RowKey读取META表位置
- 最后从该HRegionServer中读取META表的内容而获取此次请求需要访问的HRegion所在的位置
- 读取内容。
- 所以需要3次读取才能获取目标HRegion的位置,然后第4次请求才能获取真正的数据。所以,一般客户端有ROOT表位置喝内容的缓存。
我们来看看为什么BigTable要选择三级索引结构,BigTable论文里面提到,一般每个HRegion大小为128M,每行META数据1KB。所以,三级索引可以索引2^34个HRegion,可以索引很大很大的数据了。但是如果只有二级索引,我们就只能索引16TB,在大数据情况下这是完全不够。
0.96后的版本
显然只构建两级索引可以大大加快查询速度,为了两级索引的情况下也能支持大数据量。我们可以加大每个HRegion的大小,如果每个HRegion大小为2GB,两级索引就可以支持4PB。同样,客户端会缓存查询后的HRegion位置信息。
hbase:meta表
meta表存储了所有用户HRegion的位置信息,它的RowKey是:tableName,regionStartKey,regionId,replicaId等,它只有info列族,这个列族包含三个列,他们分别是:
- regioninfo列是RegionInfo的proto格式:regionId,tableName,startKey,endKey,offline,split,replicaId;
- server格式:HRegionServer对应的server:port;
- serverstartcode格式是HRegionServer的启动时间戳。
meta表(root表)结构
HRegionServer详解
HRegionServer一般和DataNode在同一台机器上运行,实现数据的本地性。HRegionServer包含多个HRegion,由WAL(HLog)、BlockCache、MemStore、HFile组成。
WAL(Write Ahead Log, HLog)
所有写操作都会先保证将数据写入这个Log文件(每个HRegionServer只有一个)后,才会真正更新MemStore,最后写入HFile中。这样即使HRegionServer宕机,我们依然可以从HLog中恢复数据。
由于HDFS只允许同一时刻对一个文件只能一个客户端写入,所以对HLog只能单线程写入。这样很明显会影响性能,所以再HBase1.0以后的版本,多个WAL并行写(MultiWAL),该实现采用HDFS的多个管道写,以单个HRegion为单位。
BlockCache
读缓存,Hbase中有两种(BlockCache为HRegionServer内存大小的20%)
- on-heap LruBlockCache:LruBlockCache受到java gc的影响,不稳定
- BucketCache(通常是off-heap):一般采用这种方式,自己管理内存,更加稳定
HRegion
HRegion是一个表的一部分,表的横切的一部分
HStore
HRegion由多个Store(HStore)构成,每个HStore对应了一个Table在这个HRegion中的一个Column Family,即每个Column Family就是一个集中的存储单元,因而最好将具有相近IO特性的Column存储在一个Column Family,以实现高效读取(数据局部性原理,可以提高缓存的命中率)。
HStore是HBase中存储的核心,它实现了读写HDFS功能,一个HStore由一个MemStore 和0个或多个HFile组成。
- MemStore:所有数据的写在完成WAL日志写后,会 写入MemStore中,由MemStore根据一定的算法将数据Flush到地层HDFS文件中(HFile),通常每个HRegion中的每个 Column Family有一个自己的MemStore。
- HFile:在HFile中的数据是按RowKey、Column Family、Column排序,对相同的Cell(即这三个值都一样),则按timestamp倒序排列
MemStore
MemStore是一个In Memory Sorted Buffer,在每个HStore中都有一个MemStore,即它是一个HRegion的一个Column Family对应一个实例。它的排列顺序以RowKey、Column Family、Column的顺序以及Timestamp的倒序,如下所示:
每一次Put/Delete请求都是先写入到MemStore中,当MemStore满后会Flush成一个新的StoreFile(底层实现是HFile),即一个HStore(Column Family)可以有0个或多个StoreFile(HFile)。有以下三种情况可以触发MemStore的Flush动作,需要注意的是MemStore的最小Flush单元是HRegion而不是单个MemStore。据说这是Column Family有个数限制的其中一个原因,估计是因为太多的Column Family一起Flush会引起性能问题
- MemStore超过128M,此时当前的HRegion中所有的MemStore会Flush到HDFS中。
- HRegionServer上所有MemStore的大小超过了机器上默认40%的内存使用量。此时当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,Flush顺序是MemStore大小的倒序,直到低于某个阈值,默认38%
- WAL过大,当前HRegionServer中所有HRegion中的MemStore都会Flush到HDFS中,Flush使用时间顺序,最早的MemStore先Flush直到WAL的数量少于某个阈值。
在MemStore Flush过程中,还会在尾部追加一些meta数据,其中就包括Flush时最大的WAL sequence值,以告诉HBase这个StoreFile写入的最新数据的序列,那么在Recover时就直到从哪里开始。
HFile格式
HFile是MemStore在HDFS上的实体,所以写一个HFile是顺序写,速度很快。HFile一共经历了三个版本
v1
数据存放再Data块中,Data块的大小可以用户指定,大的Data块适合scan,小的Data块适合随机查找。
HFile里面的每个KeyValue对就是一个简单的byte数组。但是这个byte数组里面包含了很多项,并且有固定的结构。
Block Index:使用记录每个Data Block最大值的方案,需要将索引一次性读入内存
v2
解决了V1版本内存占用,特别是Bloom File和Block Index过大。它的解决方案是把Bloom File和Block Index打散放入Data,每次查询不用加载全部信息。对HFileV2格式具体分析,它是一个多层的类B+树索引,采用这种设计,可以实现查找不需要读取整个文件
Data Block中的Cell都是升序排列,每个block都有它自己的Leaf-Index,每个Block的最后一个Key被放入Intermediate-Index中,Root-Index指向Intermediate-Index。Bloom过滤器用于快速定位没有在DataBlock中的数据
v3
v3和v2没有太大变化,只是加了一个tag字段
理一理HRegionServer中的结构
- HRegionServer
- WAL(Hlog,一个,HDFS中)
- BlockCache
- HRegion(最多1000个,表的横切,rowkey不会重叠)
- HStore(列族,HRegion的列切, 多个)
- MemStore(写完Hlog后,刚生成的数据)
- HFile(多个,具体的数据,排序,HDFS中)
- HStore(列族,HRegion的列切, 多个)
HRegionServer写流程
- 客户端发起一个Put请求时,首先它从hbase:meta表中查出该Put数据最终需要去的HRegionServer。然后客户端将Put请求发送给相应的HRegionServer,在HRegionServer中它首先会将该Put操作写入WAL日志文件中
- 完WAL日志文件后,HRegionServer根据Put中的TableName和RowKey找到对应的HRegion,并根据Column Family找到对应的HStore,并将Put写入到该HStore的MemStore中。写入成功,返回给客户端。
- 当MemStore积累一定量的数据后,flush成HFile到HDFS上
HBase读流程
HBase写时,相同Cell(RowKey/ColumnFamily/Column相同)并不保证在一起,甚至删除一个Cell也只是写入一个新的Cell,它含有Delete标记,而不一定将一个Cell真正删除了,因而这就引起了一个问题,如何实现读的问题?
相同的cell可能存在3个不同的位置,Block Cache,MemStore,HFile中。
- 从Block Cache中读取
- 从MemStore中读取
- 从多个HFile中读取,用Bloom Filter筛掉明显不存在所需数据的HFile,Index用于快速定位HFile中的数据块
Compaction
HFile过多,在数据读取的时候,会产生性能问题。所以一段时间后,HFile会进行合并。HBase中Compaction分为两种:Minor Compaction和Major Compaction。
- Minor Compaction:是指选取一些小的、相邻的HFile将他们合并成一个更大的StoreFile,在这个过程中不会处理已经Deleted或Expired的Cell。(BigTable中将memtable的数据flush的一个HFile/SSTable称为一次Minor Compaction)
- Major Compaction:是指将所有的HFile合并成一个HFile,可以手动触发或者自动触发,但是会引起性能问题,一般安排在周末。
HRegion Split
最初,一个Table只有一个HRegion,随着数据写入增加,如果一个HRegion到达一定的大小,就需要Split成两个HRegion,这个大小由hbase.hregion.max.filesize指定,默认为10GB。
当split时(split时停止服务),两个新的HRegion会在同一个HRegionServer中创建,它们各自包含父HRegion一半的数据,当Split完成后,父HRegion会下线,而新的两个子HRegion会向HMaster注册上线,处于负载均衡的考虑,这两个新的HRegion可能会被HMaster分配到其他的HRegionServer中。
分裂流程
- RegionServer在本地决定分割HRegion,并准备分割。第一步,汇报给zookeeper。
- master获取zookeeper中的状态。
- RegionServer在HDFS的父目录区域目录下创建一个名为“.splits”的子目录。
- RegionServer关闭父HRegion,强制刷新缓存,并将该区域标记为本地数据结构中的脱机状态。此时,来到父区域的客户端请求将抛出NotServingRegionException异常。客户端将重试一些备用值。
- RegionServer在.splits目录下创建Region目录,为子区域A和B创建必要的数据结构。然后,它分割存储文件,因为它在父区域中为每个存储文件创建两个引用文件。那些引用文件将指向父Region文件。
- RegionServer在HDFS中创建实际的区域目录,并移动每个子Region的引用文件。
- RegionServer向META表发送请求。将父HRegion设置为.META中的脱机状态,并添加关于子HRegion的信息。在这时,在META中不会为女儿分配单独的条目。客户端会看到父区域是分割的,如果他们扫描.META,但不知道子HRegion,直到他们出现在.META。
- RegionServer并行open子HRegion接受写入。
- RegionServer将女儿A和B添加到.META。以及它所在地区的信息。此后,客户可以发现新的地区,并向新的地区发出请求,之前的缓存失效。
- HRegion Server向zookeeper汇报split结束的消息,master进行负载均衡。
- 拆分后,meta表和HDFS仍将包含对父HRegion的引用。当子HRegion进行Compaction时,这些引用信息会被删除。Master也会定期检查子HRegion,如果没有父HRegion中的信息,父HRegion将被删除。
HRegion分裂后负载均衡
出于负载均衡的考虑,HMaster可能会将其中的一个甚至两个重新分配的其他的HRegionServer中。可能会产生HFile在其他节点上,直到下一次Major Compaction将数据从远端的节点移动到本地节点。
既然有拆分,但是HRegion也可以合并。HRegion调用closeAndMerge把两个HRegion合并(需要两个HRegion停止服务)
HBase中的负载均衡
负载均衡器会平衡系统中每个HRegionServer中HRegion个数。
负载均衡对系统性能影响很大,实际一般关闭,每周开启一次。
容错
HRegionServer Recovery
- zookeeper感知,通知HMaster
- 重新分配HRegion到其他节点
- 为每个HRegion拆分WAL,将拆分出的WAL文件写入对应的目的HRegionServer的WAL目录中,并并写入对应的DataNode中
- 回放WAL,重建MemStore
HMaster Recovery
依靠zookeeper进行主备切换
HBase一致性
HBase是强一致性,它表现在:
- HRegion split时相关HRegion不可用
- HRegion合并时相关HRegion不可用
- HRegionServer Recovery时相关HRegion不可用
HBase:分布式列式NoSQL数据库的更多相关文章
- HBase 是列式存储数据库吗
在介绍 HBase 是不是列式存储数据库之前,我们先来了解一下什么是行式数据库和列式数据库. 行式数据库和列式数据库 在维基百科里面,对行式数据库和列式数据库的定义为:列式数据库是以列相关存储架构进行 ...
- HBase与MongDB等NoSQL数据库对照
HBase概念学习(十)HBase与MongDB等NoSQL数据库对照 转载请注明出处: jiq•钦's technical Blog - 季义钦 一.开篇 淘宝之前使用的存储层架构一直是MySQL数 ...
- HBase概念学习(十)HBase与MongDB等NoSQL数据库对照
转载请注明出处: jiq•钦's technical Blog - 季义钦 一.开篇 淘宝之前使用的存储层架构一直是MySQL数据库,配合以MongDB,Tair等存储. MySQL因为开源,而且生态 ...
- Linux系统:Centos7下搭建ClickHouse列式存储数据库
本文源码:GitHub·点这里 || GitEE·点这里 一.ClickHouse简介 1.基础简介 Yandex开源的数据分析的数据库,名字叫做ClickHouse,适合流式或批次入库的时序数据.C ...
- 阿里云HBase全新发布X-Pack NoSQL数据库再上新台阶
一.八年双十一,造就国内最大最专业HBase技术团队 阿里巴巴集团早在2010开始研究并把HBase投入生产环境使用,从最初的淘宝历史交易记录,到蚂蚁安全风控数据存储.持续8年的投入,历经8年双十一锻 ...
- [转载] 【每周推荐阅读】C-Store:列式存储数据库
Record-based与column-based是数据库和存储系统里面两种不同的data layout.我们的思维逻辑是基于行记录的,即Record-based data layout,数据记录都是 ...
- mongodb,redis,hbase 三者都是nosql数据库,他们的最大区别和不同定位是什么?
不严谨地讲,Redis定位在"快",HBase定位于"大",mongodb定位在"灵活". NoSQL的优点正好就是SQL的软肋,而其弱 ...
- 各NoSQL数据库管理系统与模型比较
提供:ZStack云计算 内容简介 NoSQL数据库的存在意义在于提供传统关系数据库管理系统所不具备的特定功能.无论是负责承载简单的键-值对存储以实现短期缓存,抑或是处理传统数据库及结构化查询语言(简 ...
- Hadoop HBase概念学习系列之HBase里的列式数据库(十七)
列式数据库,从数据存储方式上有别于行式数据库,所有数据按列存取. 行式数据库在做一些列分析时,必须将所有列的信息全部读取出来 而列式数据库由于其是按列存取,因此只需在特定列做I/O即可完成查询与分析, ...
随机推荐
- kepware http接口 javascript开发
读取某变量的值(jquery var settings = { "async": true, "crossDomain": true, "url&qu ...
- hdu1176--免费馅饼(简单动态规划)
都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼.说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的10米范围内.馅饼如果掉在了地上当然就 ...
- noip第28课作业
分段数列 [问题描述] 对于给定的一个长度为N的正整数数列A[i],现要将其分成连续的若干段,并且每段和不超过M(可以等于M),问最少能将其分成多少段使得满足要求. 输入格式: 输入第1行包含两个正整 ...
- js-判断当前日期的天数
<!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...
- SRM475
250pt: 题意:有最长N=17的一条格子,每个格子是W.B和R三种颜色之一,当某个格子上有兔子时,下一个回合该兔子按照以下的规则移动: 如果兔子在第一个格子,则向右移动一格: 否则如果兔子在倒数两 ...
- Android-Java-封装
先看一个未封装的Demo案例一: package android.java.oop03; class Person { int age; } public class PottingDemo { pu ...
- WPF Command CanExecute 触发一次的问题
昨天在项目中遇到一个问题,按钮bind了Command后,利用CanExecute控制它的是否可点击.结果却在初始化viewmodel的时候执行了一次CanExecute,之后一直不触发,按钮的可用性 ...
- InfluxDB概念和基本操作
InfluxDB基本概念 数据格式 在 InfluxDB 中,我们可以粗略的将要存入的一条数据看作一个虚拟的 key 和其对应的 value(field value).格式如下: cpu_usage, ...
- 【Spark基础】:RDD
我的代码实践:https://github.com/wwcom614/Spark 1.RDD是Spark提供的核心抽象,全称为Resillient Distributed Dataset,即弹性分布式 ...
- html-文件上传设置accept类型延时问题
今天在做文件上传时,采用了jQuery的upload插件,使用过程中发现了一个很有意思也很头疼的问题. 上传按钮,第一次点击时瞬间就可以打开文件选择框,之后再点击则需要等待恐怖的8s以上. 百度 ...