hbase架构解析

HBase是Apache Hadoop中的一个子项目,Hbase依托于Hadoop的HDFS做为最基本存储基础单元,经过使用hadoop的DFS工具就能够看到这些这些数据存储文件夹的结构,还能够经过Map/Reduce的框架(算法)对HBase进行操做css

1、   hbase架构html

 1.概述。前端

HBase是Apache Hadoop的数据库,可以对大型数据提供随机、实时的读写访问。HBase的目标是存储并处理大型的数据。HBase是一个开源的,分布式的,多版本的,面向列的存储模型。它存储的是松散型数据。linux

上图是hadoop的生态系统描述,hadoop全部应用都是构建于hdfs(它提供高可靠的底层存储支持,几乎已经成为分布式文件存储系统事实上的工业标准)之上的分布式列存储系统,主要用于海量结构化数据存储。web

HBase是一种NoSQL数据库. NoSQL是一个通用词表示数据库不是RDBMS ,后者支持 SQL 做为主要访问手段。有许多种 NoSQL 数据库: BerkeleyDB 是本地 NoSQL 数据库例子, 而 HBase 是大型分布式数据库。 技术上来讲, HBase 更像是"数据存储(Data Store)" 多于 "数据库(Data Base)"。由于缺乏不少RDBMS特性, 如列类型,第二索引,触发器,高级查询语言等算法

然而, HBase 有许多特征同时支持线性化和模块化扩充。 HBase 集群经过增长RegionServers进行扩充。 它能够放在普通的服务器中。例如,若是集群从10个扩充到20个RegionServer,存储空间和处理容量都同时翻倍。 RDBMS 也能很好扩充, 但仅对一个点 - 特别是对一个单独数据库服务器的大小 - 同时,为了更好的性能,须要特殊的硬件和存储设备。Hbase特性:shell

强一致性读写: HBase 不是 "最终一致性(eventually consistent)" 数据存储. 这让它很适合高速计数聚合类任务。数据库

自动分片(Automatic sharding):HBase 表经过region分布在集群中。数据增加时,region会自动分割并从新分布。apache

RegionServer 自动故障转移编程

Hadoop/HDFS 集成: HBase 支持本机外HDFS 做为它的分布式文件系统。

MapReduce: HBase 经过MapReduce支持大并发处理, HBase 能够同时作源和目标.

Java 客户端 API: HBase 支持易于使用的 Java API 进行编程访问.

Thrift/REST API:HBase 也支持Thrift和 REST 做为非Java 前端.

Block Cache 和 Bloom Filters: 对于大容量查询优化, HBase支持 Block Cache 和 Bloom Filters。

运维管理: HBase提供内置网页用于运维视角和JMX 度量.

前文提到Hbase是一个列式存储的数据库,那么什么是列式存储,它与传统的RDBMS采用的行式存储又有什么区别?列存储不一样于传统的关系型数据库,其数据在表中是按行存储的,列方式所带来的重要好处之一就是,因为查询中的选择规则是经过列来定义的,所以整个数据库是自动索引化的。按列存储每一个字段的数据汇集存储,在查询只须要少数几个字段的时候,能大大减小读取的数据量,一个字段的数据汇集存储,那就更容易为这种汇集存储设计更好的压缩/解压算法。这张图讲述了传统的行存储和列存储的区别:

 2.hbase架构

注:准确的说位于上图下半部分的组建应该是hdfs而非hadoop,hbase并不依赖于hadoop,可是它构建于hdfs之上。

Zookeeper
Zookeeper Quorum存储-ROOT-表地址、HMaster地址
HRegionServer把本身以Ephedral方式注册到Zookeeper中,HMaster随时感知各个HRegionServer的健康情况
Zookeeper避免HMaster单点问题
HMaster
HMaster没有单点问题,HBase中能够启动多个HMaster,经过Zookeeper的MasterElection机制保证总有一个Master在运行
主要负责Table和Region的管理工做:
1 管理用户对表的增删改查操做
2 管理HRegionServer的负载均衡,调整Region分布
3 Region Split后,负责新Region的分布
4 在HRegionServer停机后,负责失效HRegionServer上Region迁移

HRegionServer
HBase中最核心的模块,主要负责响应用户I/O请求,向HDFS文件系统中读写数据

HRegionServer管理一些列HRegion对象;
每一个HRegion对应Table中一个Region,HRegion由多个HStore组成;
每一个HStore对应Table中一个Column Family的存储;
Column Family就是一个集中的存储单元,故将具备相同IO特性的Column放在一个Column Family会更高效

HStore
HBase存储的核心。由MemStore和StoreFile组成。
MemStore是Sorted Memory Buffer。用户写入数据的流程:

Client写入 -> 存入MemStore,一直到MemStore满 -> Flush成一个StoreFile,直至增加到必定阈值 -> 出发Compact合并操做 -> 多个StoreFile合并成一个StoreFile,同时进行版本合并和数据删除 -> 当StoreFiles Compact后,逐步造成愈来愈大的StoreFile ->单个StoreFile大小超过必定阈值后,触发Split操做,把当前Region Split成2个Region,Region会下线,新Split出的2个孩子Region会被HMaster分配到相应的HRegionServer 上,使得原先1个Region的压力得以分流到2个Region上
由此过程可知,HBase只是增长数据,全部的更新和删除操做,都是在Compact阶段作的,因此,用户写操做只须要进入到内存便可当即返回,从而保证I/O高性能。

HLog
引入HLog缘由:
在分布式系统环境中,没法避免系统出错或者宕机,一旦HRegionServer意外退出,MemStore中的内存数据就会丢失,引入HLog就是防止这种状况
工做机制:
每 个HRegionServer中都会有一个HLog对象,HLog是一个实现Write Ahead Log的类,每次用户操做写入Memstore的同时,也会写一份数据到HLog文件,HLog文件按期会滚动出新,并删除旧的文件(已持久化到 StoreFile中的数据)。当HRegionServer意外终止后,HMaster会经过Zookeeper感知,HMaster首先处理遗留的 HLog文件,将不一样region的log数据拆分,分别放到相应region目录下,而后再将失效的region从新分配,领取到这些region的 HRegionServer在Load Region的过程当中,会发现有历史HLog须要处理,所以会Replay HLog中的数据到MemStore中,而后flush到StoreFiles,完成数据恢复。

HBase存储格式
HBase中的全部数据文件都存储在Hadoop HDFS文件系统上,格式主要有两种:
1 HFile HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile作了轻量级包装,即StoreFile底层就是HFile
2 HLog File,HBase中WAL(Write Ahead Log) 的存储格式,物理上是Hadoop的Sequence File

HFile

HFile文件不定长,长度固定的块只有两个:Trailer和FileInfo
Trailer中指针指向其余数据块的起始点
File Info中记录了文件的一些Meta信息,例如:AVG_KEY_LEN,AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等
Data Index和Meta Index块记录了每一个Data块和Meta块的起始点
Data Block是HBase I/O的基本单元,为了提升效率,HRegionServer中有基于LRU的Block Cache机制
每一个Data块的大小能够在建立一个Table的时候经过参数指定,大号的Block有利于顺序Scan,小号Block利于随机查询
每一个Data块除了开头的Magic之外就是一个个KeyValue对拼接而成, Magic内容就是一些随机数字,目的是防止数据损坏

HFile里面的每一个KeyValue对就是一个简单的byte数组。这个byte数组里面包含了不少项,而且有固定的结构。

KeyLength和ValueLength:两个固定的长度,分别表明Key和Value的长度
Key部分:Row Length是固定长度的数值,表示RowKey的长度,Row 就是RowKey
Column Family Length是固定长度的数值,表示Family的长度
接着就是Column Family,再接着是Qualifier,而后是两个固定长度的数值,表示Time Stamp和Key Type(Put/Delete)
Value部分没有这么复杂的结构,就是纯粹的二进制数据

HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。
HLog Sequece File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue

 3.何时应该使用hbase

在学习一门新技术的时候首先须要明白,咱们到底应该在何时使用它,而后才是怎么去使用它,Hbase并不适合全部问题。

首先,确信有足够多数据,若是有上亿或上千亿行数据,HBase是很好的备选。若是只有上千或上百万行,则用传统的RDBMS多是更好的选择。由于全部数据能够在一两个节点保存,集群其余节点可能闲置。

其次,确信能够不依赖全部RDBMS的额外特性 (e.g., 列数据类型, 第二索引,事物,高级查询语言等.) 一个创建在RDBMS上应用,如不能仅经过改变一个JDBC驱动移植到HBase。相对于移植, 需考虑从RDBMS 到 HBase是一次彻底的从新设计。

第三, 确信你有足够硬件。甚至 HDFS 在小于5个数据节点时,干很差什么事情 (根据如HDFS 块复制具备缺省值 3), 还要加上一个NameNode.

HBase 能在单独的笔记本上运行良好。但这应仅当成开发配置。

4.目录表(.meta.和-root-)

-ROOT- 保存 .META. 表存在哪里的踪影. -ROOT- 表结构以下:

Key:

.META. region key (.META.,,1)

Values:

info:regioninfo (序列化.META.的 HRegionInfo 实例 )

info:server ( 保存 .META.的RegionServer的server:port)

info:serverstartcode ( 保存 .META.的RegionServer进程的启动时间)

.META. 保存系统中全部region列表。 .META.表结构以下:

Key:

Region key 格式 ([table],[region start key],[region id])

Values:

info:regioninfo (序列化.META.的 HRegionInfo 实例 )

info:server ( 保存 .META.的RegionServer的server:port)

info:serverstartcode ( 保存 .META.的RegionServer进程的启动时间)

以上是官网文档对于.meta.和-root-的描述,简而言之,-root-中存储了.meta.的位置,而在.meta.中保存了具体数据(region)的存储位置。如图:

Zookeeper中记录了-ROOT-表的location
客户端访问数据的流程:
Client -> Zookeeper -> -ROOT- -> .META.-> 用户数据表
屡次网络操做,不过client端有cache缓存

a.    启动时序

1.启动时主服务器调用AssignmentManager.

2.AssignmentManager 在META中查找已经存在的区域分配。

3.若是区域分配还有效(如 RegionServer 还在线),那么分配继续保持。

4.若是区域分配失效,LoadBalancerFactory 被调用来分配区域。 DefaultLoadBalancer 将随机分配区域到RegionServer.

5.META 随RegionServer 分配更新(若是须要) , RegionServer 启动区域开启代码(RegionServer 启动时进程)

b.故障转移

当regionServer故障退出时:

1.区域当即不可获取,由于区域服务器退出。

2.主服务器会检测到区域服务器退出。

3.区域分配会失效并被从新分配,如同启动时序。

5.预写日志(wal)

每一个RegionServer会将更新(Puts, Deletes)先记录到预写日志中(WAL),而后将其更新在StoreMemStore里面。这样就保证了HBase的写的可靠性。若是没有WAL,当RegionServer宕掉的时候,MemStore尚未flush,StoreFile尚未保存,数据就会丢失。HLog 是HBase的一个WAL实现,一个RegionServer有一个HLog实例。

WAL 保存在HDFS 的 /hbase/.logs/ 里面,每一个region一个文件。

2、   数据模型

1.概念视图

以bigTable论文中的例子来讲明,有一个名为webtable的表,包含两个列族:contents和anchor.在这个例子里面,anchor有两个列 (anchor:cssnsi.com,anchor:my.look.ca),contents仅有一列(contents:html)

Row Key

Time Stamp

ColumnFamily contents

ColumnFamily anchor

"com.cnn.www"

t9

 

anchor:cnnsi.com = "CNN"

"com.cnn.www"

t8

 

anchor:my.look.ca = "CNN.com"

"com.cnn.www"

t6

contents:html = "<html>..."

 

"com.cnn.www"

t5

contents:html = "<html>..."

 

"com.cnn.www"

t3

contents:html = "<html>..."

 

RowKey:行键,是表中每条记录的“主键”,方便快速查找,Rowkey的设计很是重要。
Column Family:列族,拥有一个名称(string),包含一个或者多个相关列
Column:属于某一个columnfamily,每条记录可动态添加
Version Number:类型为Long,默认值是系统时间戳,可由用户自定义
Value(Cell):一个cell由familyName:columnName惟必定义

2.物理视图

尽管在概念视图里,表能够被当作是一个稀疏的行的集合。但在物理上,它的是区分列族 存储的。新的columns能够不通过声明直接加入一个列族.

Row Key

Time Stamp

Column Family anchor

"com.cnn.www"

t9

anchor:cnnsi.com = "CNN"

"com.cnn.www"

t8

anchor:my.look.ca = "CNN.com"

 

Row Key

Time Stamp

ColumnFamily "contents:"

"com.cnn.www"

t6

contents:html = "<html>..."

"com.cnn.www"

t5

contents:html = "<html>..."

"com.cnn.www"

t3

contents:html = "<html>..."

值得注意的是在上面的概念视图中空白cell在物理上是不存储的,由于根本没有必要存储。所以若一个请求为要获取t8时间的contents:html,他的结果就是空。类似的,若请求为获取t9时间的anchor:my.look.ca,结果也是空。可是,若是不指明时间,将会返回最新时间的行,每一个最新的都会返回。例如,若是请求为获取行键为"com.cnn.www",没有指明时间戳的话,活动的结果是t6下的contents:html,t9下的anchor:cnnsi.com和t8下anchor:my.look.ca。

对于hbase我一直有一个疑问,在hbase提供了修改和删除的接口,可是hdfs自己很难实现修改和删除(能够将文件块从hdfs中下载,进行修改再上传),那么hbase是如何实现快速的删除与修改呢?实际上在HBase中,修改和删除数据都是增长1个新版本的数据(时间戳为最新),旧版本的数据并无发生变化,而实际上的修改和删除是在Hfile的合并阶段实现的。

3、   Hbase优化

1.    预先分区

默认状况下,在建立 HBase 表的时候会自动建立一个 Region 分区,当导入数据的时候,全部的 HBase 客户端都向这一个 Region 写数据,直到这个 Region 足够大了才进行切分。一种能够加快批量写入速度的方法是经过预先建立一些空的 Regions,这样当数据写入 HBase 时,会按照 Region 分区状况,在集群内作数据的负载均衡。

2.    Rowkey优化

HBase 中 Rowkey 是按照字典序存储,所以,设计 Rowkey 时,要充分利用排序特色,将常常一块儿读取的数据存储到一块,将最近可能会被访问的数据放在一块。

此外,Rowkey 如果递增的生成,建议不要使用正序直接写入 Rowkey,而是采用 reverse 的方式反转Rowkey,使得 Rowkey 大体均衡分布,这样设计有个好处是能将 RegionServer 的负载均衡,不然容易产生全部新数据都在一个 RegionServer 上堆积的现象,这一点还能够结合 table 的预切分一块儿设计。

3.    减小列族数量

不要在一张表里定义太多的 ColumnFamily。目前 Hbase 并不能很好的处理超过 2~3 个 ColumnFamily 的表。由于某个 ColumnFamily 在 flush 的时候,它邻近的 ColumnFamily 也会因关联效应被触发 flush,最终致使系统产生更多的 I/O。

4.    缓存策略

建立表的时候,能够经过 HColumnDescriptor.setInMemory(true) 将表放到 RegionServer 的缓存中,保证在读取的时候被 cache 命中。

5.    设置存储生命期

建立表的时候,能够经过 HColumnDescriptor.setTimeToLive(int timeToLive) 设置表中数据的存储生命期,过时数据将自动被删除。

6.    硬盘配置

每台 RegionServer 管理 10~1000 个 Regions,每一个 Region 在 1~2G,则每台 Server 最少要 10G,最大要1000*2G=2TB,考虑 3 备份,则要 6TB。方案一是用 3 块 2TB 硬盘,二是用 12 块 500G 硬盘,带宽足够时,后者能提供更大的吞吐率,更细粒度的冗余备份,更快速的单盘故障恢复。

7.    分配合适的内存给RegionServer服务

在不影响其余服务的状况下,越大越好。例如在 HBase 的 conf 目录下的 hbase-env.sh 的最后添加 export HBASE_REGIONSERVER_OPTS="-Xmx16000m$HBASE_REGIONSERVER_OPTS”

其中 16000m 为分配给 RegionServer 的内存大小。

8.    写数据的备份数

备份数与读性能成正比,与写性能成反比,且备份数影响高可用性。有两种配置方式,一种是将 hdfs-site.xml拷贝到 hbase 的 conf 目录下,而后在其中添加或修改配置项 dfs.replication 的值为要设置的备份数,这种修改对全部的 HBase 用户表都生效,另一种方式,是改写 HBase 代码,让 HBase 支持针对列族设置备份数,在建立表时,设置列族备份数,默认为 3,此种备份数只对设置的列族生效。

9.    WAL(预写日志)

可设置开关,表示 HBase 在写数据前用不用先写日志,默认是打开,关掉会提升性能,可是若是系统出现故障(负责插入的 RegionServer 挂掉),数据可能会丢失。配置 WAL 在调用 JavaAPI 写入时,设置 Put 实例的WAL,调用 Put.setWriteToWAL(boolean)。

10. 批量写

HBase 的 Put 支持单条插入,也支持批量插入,通常来讲批量写更快,节省来回的网络开销。在客户端调用JavaAPI 时,先将批量的 Put 放入一个 Put 列表,而后调用 HTable 的 Put(Put 列表) 函数来批量写。

11. 客户端一次从服务器拉取的数量

经过配置一次拉去的较大的数据量能够减小客户端获取数据的时间,可是它会占用客户端内存。有三个地方可进行配置:

1)在 HBase 的 conf 配置文件中进行配置 hbase.client.scanner.caching;

2)经过调用 HTable.setScannerCaching(intscannerCaching) 进行配置;

3)经过调用 Scan.setCaching(intcaching) 进行配置。三者的优先级愈来愈高。

12. RegionServer的请求处理I/O线程数

较少的 IO 线程适用于处理单次请求内存消耗较高的 Big Put 场景 (大容量单次 Put 或设置了较大 cache 的Scan,均属于 Big Put) 或 ReigonServer 的内存比较紧张的场景。

较多的 IO 线程,适用于单次请求内存消耗低,TPS 要求 (每秒事务处理量 (TransactionPerSecond)) 很是高的场景。设置该值的时候,以监控内存为主要参考。

在 hbase-site.xml 配置文件中配置项为 hbase.regionserver.handler.count。

13. Region的大小设置

配置项为 hbase.hregion.max.filesize,所属配置文件为 hbase-site.xml.,默认大小 256M。

在当前 ReigonServer 上单个 Reigon 的最大存储空间,单个 Region 超过该值时,这个 Region 会被自动 split成更小的 Region。小 Region 对 split 和 compaction 友好,由于拆分 Region 或 compact 小 Region 里的StoreFile 速度很快,内存占用低。缺点是 split 和 compaction 会很频繁,特别是数量较多的小 Region 不停地split, compaction,会致使集群响应时间波动很大,Region 数量太多不只给管理上带来麻烦,甚至会引起一些Hbase 的 bug。通常 512M 如下的都算小 Region。大 Region 则不太适合常常 split 和 compaction,由于作一次 compact 和 split 会产生较长时间的停顿,对应用的读写性能冲击很是大。

此外,大 Region 意味着较大的 StoreFile,compaction 时对内存也是一个挑战。若是你的应用场景中,某个时间点的访问量较低,那么在此时作 compact 和 split,既能顺利完成 split 和 compaction,又能保证绝大多数时间平稳的读写性能。compaction 是没法避免的,split 能够从自动调整为手动。只要经过将这个参数值调大到某个很难达到的值,好比 100G,就能够间接禁用自动 split(RegionServer 不会对未到达 100G 的 Region 作split)。再配合 RegionSplitter 这个工具,在须要 split 时,手动 split。手动 split 在灵活性和稳定性上比起自动split 要高不少,并且管理成本增长很少,比较推荐 online 实时系统使用。内存方面,小 Region 在设置memstore 的大小值上比较灵活,大 Region 则过大太小都不行,过大会致使 flush 时 app 的 IO wait 增高,太小则因 StoreFile 过多影响读性能。

14. 操做系统参数

Linux系统最大可打开文件数通常默认的参数值是1024,若是你不进行修改并发量上来的时候会出现“Too Many Open Files”的错误,致使整个HBase不可运行,你能够用ulimit -n 命令进行修改,或者修改/etc/security/limits.conf和/proc/sys/fs/file-max 的参数,具体如何修改能够去Google 关键字 “linux limits.conf ”

15. Jvm配置

修改 hbase-env.sh 文件中的配置参数,根据你的机器硬件和当前操做系统的JVM(32/64位)配置适当的参数

HBASE_HEAPSIZE 4000 HBase使用的 JVM 堆的大小

HBASE_OPTS "‐server ‐XX:+UseConcMarkSweepGC"JVM GC 选项

HBASE_MANAGES_ZKfalse 是否使用Zookeeper进行分布式管理

16. 持久化

重启操做系统后HBase中数据全无,你能够不作任何修改的状况下,建立一张表,写一条数据进行,而后将机器重启,重启后你再进入HBase的shell中使用 list 命令查看当前所存在的表,一个都没有了。是否是很杯具?没有关系你能够在hbase/conf/hbase-default.xml中设置hbase.rootdir的值,来设置文件的保存位置指定一个文件夹,例如:<value>file:///you/hbase-data/path</value>,你创建的HBase中的表和数据就直接写到了你的磁盘上,一样你也能够指定你的分布式文件系统HDFS的路径例如:hdfs://NAMENODE_SERVER:PORT/HBASE_ROOTDIR,这样就写到了你的分布式文件系统上了。

17. 缓冲区大小

hbase.client.write.buffer

这个参数能够设置写入数据缓冲区的大小,当客户端和服务器端传输数据,服务器为了提升系统运行性能开辟一个写的缓冲区来处理它,这个参数设置若是设置的大了,将会对系统的内存有必定的要求,直接影响系统的性能。

18. 扫描目录表

hbase.master.meta.thread.rescanfrequency

定义多长时间HMaster对系统表 root 和 meta 扫描一次,这个参数能够设置的长一些,下降系统的能耗。

19. split/compaction时间间隔

hbase.regionserver.thread.splitcompactcheckfrequency

这个参数是表示多久去RegionServer服务器运行一次split/compaction的时间间隔,固然split以前会先进行一个compact操做.这个compact操做多是minorcompact也多是major compact.compact后,会从全部的Store下的全部StoreFile文件最大的那个取midkey.这个midkey可能并不处于所有数据的mid中.一个row-key的下面的数据可能会跨不一样的HRegion。

20. 缓存在JVM堆中分配的百分比

hfile.block.cache.size

指定HFile/StoreFile 缓存在JVM堆中分配的百分比,默认值是0.2,意思就是20%,而若是你设置成0,就表示对该选项屏蔽。

21. ZooKeeper客户端同时访问的并发链接数

hbase.zookeeper.property.maxClientCnxns

这项配置的选项就是从zookeeper中来的,表示ZooKeeper客户端同时访问的并发链接数,ZooKeeper对于HBase来讲就是一个入口这个参数的值能够适当放大些。

22. memstores占用堆的大小参数配置

hbase.regionserver.global.memstore.upperLimit

在RegionServer中全部memstores占用堆的大小参数配置,默认值是0.4,表示40%,若是设置为0,就是对选项进行屏蔽。

23. Memstore中缓存写入大小

hbase.hregion.memstore.flush.size

Memstore中缓存的内容超过配置的范围后将会写到磁盘上,例如:删除操做是先写入MemStore里作个标记,指示那个value, column 或 family等下是要删除的,HBase会按期对存储文件作一个major compaction,在那时HBase会把MemStore刷入一个新的HFile存储文件中。若是在必定时间范围内没有作major compaction,而Memstore中超出的范围就写入磁盘上了。

相关文章
相关标签/搜索