HBase的架构原理、读写过程、表结构、行存储和(HBase)列存储、应用场景、扩容(增加节点

一、Hbase架构

Hbase能做什么?

1、海量数据的存储(P级别)

2、海量数据的查询(毫秒级)

一个表:30字段,60亿条数据

根据rowkey查询:1k条,几十毫秒,2w条数据,几百毫秒。RPC通信机制

三、传统的行存储和(HBase)列存储的区别

从上图可以很清楚地看到,行式存储下一张表的数据都是放在一起的,但列式存储下都被分开保存了。所以它们就有了如下这些优缺点:

                             

行式存储

列式存储

优点

Ø  数据被保存在一起

Ø  INSERT/UPDATE容易

Ø  查询时只有涉及到的列会被读取

Ø  投影(projection)很高效

Ø  任何列都能作为索引

缺点

Ø  选择(Selection)时即使只涉及某几列,所有数据也都会被读取

Ø  选择完成时,被选择的列要重新组装

Ø  INSERT/UPDATE比较麻烦

注:关系型数据库理论回顾 - 选择(Selection)和投影(Projection)

2、数据压缩

 通过字典表压缩数据。

下面才是那张表本来的样子。经过字典表进行数据压缩后,表中的字符串才都变成数字了。正因为每个字符串在字典表里只出现一次了,所以达到了压缩的目的(有点像规范化和非规范化Normalize和Denomalize)

3、查询执行性能

下面就是最牛的图了,根据列值进行条件查询(过滤)

通过一条查询的执行过程说明列式存储(以及数据压缩)的优点:

关键步骤如下:

1.     去字典表里找到字符串对应数字(只进行一次字符串比较)。

2.     用数字去列表里匹配,匹配上的位置设为1。

3.     把不同列的匹配结果进行位运算得到符合所有条件的记录下标。

4.     使用这个下标组装出最终的结果集。

Hbase名词解释

Zookeeper

  • 保证任何时候,集群中只有一个master(负责多HMaster的选举)
  • 存贮所有Region的寻址入口,meta表
  • 实时监控RegionServer的状态、将RegionServer的上线和下线信息实时通知给Master(服务器之间状态同步)
  • 存储Hbase的schema(元数据信息)。包括有哪些table、每个table有哪些column family等

HMaster
(主要负责table和region的管理工作)

  • 监听zk,负责RegionServer的负载均衡,调整region的分配
  • 基于zookeeper感应RegionServer的上下线,发现失效的regionserver并重新分配其上的region,在一个RegionServer死机后,负责失效节点的Region的迁移,
  • Region分裂后,为RegionServer分配新的Region
  • 基于zookeeper来保证HA
  • 管理用户对表table的增、删、改、查操作
  • 处理schema更新请求 (管理用户对表的增删修改)
  • 不参与对表的读写访问

RegionServer
(主要负责响应用户对其上region的I/O请求,向HDFS读写数据,HbasHBase核心模块)

  • 一个HRegionServer会有多个HRegion和一个HLog。
  • HRegionSserver维护Master分配给它的region,维护Region,处理region的flush、compact、split分裂,StoreFileCompaction合并,写入到HDFS中。
  • 处理Client端的读写请求(根据从HMaster返回的元数据找到对应的Region来读写数据)。数据的添加、删除、修改、查询等操作。

Region
(图中为Hregion,也就是指一个Table的分区)

  • HRegion是分布式存储和负载的最小单元。表中的数据存储在Region中,每个Region都由RegionServer进行管理。对hbase数据表的表数据维护。
  • 每一个HRegion又由很多的Store组成,每一个Store存储的实际上是一个列簇(ColumnFamily)下所有的数据。此外,在每一个Store(又名HStore)中有包含一块MemStore。MemStore驻留在内存中,数据到来时首先更新到MemStore中,当到达阈值之后再flush(默认64M)到对应的StoreFile(又名HFile)中,所以每一个Store包含多个StoreFile,StoreFile负责的是实际数据存储,为HBase中最小的存储单元。
  • 达到某个阈值时,分裂(默认256M)。所以一个HRegionServer管理多个表,一个表下有多个Region,一个HRegion有多少个列族就有多少个Store,Store下有多个StoreFile文件,是HBase中最小的存储单元
  • 以Region为单位管理, region(startKey,endKey);【默认情况下,刚创建一个表时,并不知道startkey和endkey】
  • 每个Column Family单独存储:storeFile;( storefile的数量一多(到达阀值),就合并(同时合并版本以及删除之前要删除的数据);合并后大小到达阀值就split)
  • 当某个Column Family累积的大小(具体的数据量) > 某阈值时,自动分裂成两个Region;合并之后,旧数据也不是立即删除,而是复制一份并同内存中的数据一起写到磁盘,在之后,LSM-Tree会提供一些机制来回收这些空间。[4]
  • 如何找到某行属于哪个region呢?两张特殊的表:-NAMESPACE- 和.META.

StoreFile
(底层存储格式是HFile,HBase中最小的存储单元)

memStore内存中的数据写到文件后就是StoreFile,StoreFile底层是以HFile的格式保存。 

HFile
(HFile基于Hadoop的TFile类实现,模仿Google的BIgTable论文中的SSTable格式。)

  • HBase中KeyValue数据的存储格式,是hadoop的二进制格式文件。
  • HFile文件是不定长的,长度固定的只有其中的两块:Trailer和FileInfo。
  • Trailer中有指针指向其他数据块的起始点,FileInfo记录了文件的一些meta信息。 - Data Block是hbase io的基本单元,为了提高效率,HRegionServer中有基于LRU的block cache机制。
  • 每个Data块的大小可以在创建一个Table的时候通过参数指定(默认块大小64KB),大号的Block有利于顺序Scan,小号的Block利于随机查询。
  • 每个Data块除了开头的Magic以外就是一个个KeyValue对拼接而成
  • Magic内容就是一些随机数字,目的是防止数据损坏
    这里写图片描述

HLog(WAL log)
(HLog是WAL的核心实现类)

  • WAL意为write ahead log,HBase中的预写日志,用来做灾难恢复使用,底层实现是HLog,HLog记录数据的所有变更。使用WAL的原因:因为MemStore存储的数据是驻留在内存中的,是不稳定的(比如宕机时),所以采用了WAL预写日志来解决这个问题。(运行MApReduce作业时,可以通过关闭WAL功能来获得性能的提升——setWriteToWAL(boolean))
  • 其实HLog文件就是一个普通的Hadoop Sequence File, Sequence File的value是key时HLogKey对象,其中记录了写入数据的归属信息,除了table和region名字外,还同时包括sequence number和timestamp,timestamp是写入时间,sequence number的起始值为0,或者是最近一次存入文件系统中的sequence number。 Sequence File的value是HBase的KeyValue对象,即对应HFile中的KeyValue。[1]

4、-ROOT-,.META.的作用

我们先来看.META.表,假设HBase中只有两张用户表:Table1和Table2,Table1非常大,被划分成了很多Region,因此在.META.表中有很多条Row用来记录这些Region。而Table2很小,只是被划分成了两个Region,因此在.META.中只有两条Row用来记录。这个表的内容看上去是这个样子的: 

.META.行记录结构

现在假设我们要从Table2里面插寻一条RowKey是RK10000的数据。那么我们应该遵循以下步骤:

1. 从.META.表里面查询哪个Region包含这条数据。

2. 获取管理这个Region的RegionServer地址。

3. 连接这个RegionServer, 查到这条数据。

问题是.META.也是一张普通的表,我们需要先知道哪个RegionServer管理了.META.表,怎么办?有一个方法,我们把管理.META.表的RegionServer的地址放到ZooKeeper上面,这样大家都知道了谁在管理.META.。

貌似问题解决了,但对于这个例子我们遇到了一个新问题。因为Table1实在太大了,它的Region实在太多了,.META.为了存储这些Region信息,花费了大量的空间,自己也需要划分成多个Region。这就意味着可能有多个RegionServer在管理.META(每个RegionServer都有自己的.META)怎么办?在ZooKeeper里面存储所有管理.META.的RegionServer地址让Client自己去遍历?HBase并不是这么做的。

HBase的做法是用另外一个表来记录.META.的Region信息,就和.META.记录用户表的Region信息一模一样。这个表就是-ROOT-表。这也解释了为什么-ROOT-和.META.拥有相同的表结构,因为他们的原理是一模一样的。

假设.META.表被分成了两个Region,那么-ROOT-的内容看上去大概是这个样子的:

-ROOT-行记录结构

这么一来Client端就需要先去访问-ROOT-表。所以需要知道管理-ROOT-表的RegionServer的地址。这个地址被存在ZooKeeper中。默认的路径是:/hbase/root-region-server 。-ROOT-只会有一个Region,这个Region的信息也是被存在HBase内部的。 

关于Region的查找,早期的设计(0.96)之前是被称之为三层查询架构,如下图所示:

从ZooKeeper得到-ROOT-的RegionServer => 
从-ROOT-表中查到RowKey最接近(小于).META.,Table2,RK10000,99999999999999的一条Row,并得到.META.的RegionServer => 
从.META.表中查到RowKey最接近(小于)Table2,RK10000, 99999999999999的一条Row,并得到Table2的RegionServer => 
从Table2中查到RK10000的Row  

步骤:

(1)用户通过查找zk(zookeeper)的/hbase/root-region-server节点来知道-ROOT-表在什么RegionServer上。

(2)访问-ROOT-表,查看需要的数据在哪个.META.表上,这个.META.表在什么RegionServer上。

(3)访问.META.表查看查询的rowkey在什么Region范围里面。,并得到Table2的RegionServer 

(4)连接具体的数据所在的RegionServer,这回就真的开始用Scan来遍历row了。 

Client访问ZK,根据ROOT表获取meta表所在Region的位置信息,并将该位置信息写入Client Cache。 
(注:为了加快数据访问速度,我们将元数据、Region位置等信息缓存在Client Cache中。)

为了让客户端找到包含特定主键的region,Hbase0.96之前提供了两张特殊的目录表-ROOT-和.META表

root表用来查询所有meta表中热region的位置。meta表则是用来查找所有table的region的位置。Hbase原来的设计中只有一个root region,则root从不拆分,从而保证类似于B+树结构的三层查找结构:第一层是zookeeper中包含root region位置信息的节点,第二层是从root表中查找对应meta表的region的位置,第三层是从meta表中查找用户表对应region的位置。

既然0.96之前是这么做的,那为什么就舍弃了呢?

1、BigTable的论文论述了meta的region大小为128M时,可以定位2^34个region,这是怎么计算的呢?

.META.表每行保存一个region的位置信息,row key 采用表名+表的最后一样编码而成。

为了加快访问,.META.表的全部region都保存在内存中。

假设,.META.表的一行在内存中大约占用1KB。并且每个region限制为128MB。

那么上面的三层结构可以保存的region数目为:一个region的root和一个region的meta

(128MB/1KB) * (128MB/1KB) = = 2^32个region

2、除了三层架构定位的数据过多之外,还有网络请求的原因。

虽然客户端缓存了region的地址,但是初始化需求的时候需要重新查找region(client上的缓存全部失效),例如:当缓存过期了,并发生了region的拆分、合并或者移动。客户端使用递归查找的方式从目录中重新定位当前region的位置,它从对应的meta表region中查找对应行键的地址。如果对应的meta的region地址无效,它就向root请求当前对应meta表的位,最后,如果连root都没有用了,就回向zookeeper节点查询root表的新地址。在最坏的情况下,客户端需要6次网络往返请求(其中三次用来发现缓存失效,另外三次用来获取位置信息)。来定位一个用户region,这也是三层架构的一个弊端之一。

 在0.96之后,将root表去接去掉了 

没有了root表,直接从meta查询,和上面条件一个,假设一个region有128M,一行地址数据1KB,那么就可以定位128M/1kB个region,有2^24的大小,有16T,因为meta表肯定不止一个region,一个region肯定不止128M,所以,从meta来定位的数据大小远大于16T,对于一个Hbase集群来说,完全够了。

而且,少了一层root,网络请求次数肯定会减少,这也是优势之一。

二层架构的定位步骤如下:

(1)用户通过查找zk(zookeeper)的/hbase/meta-region-server节点查询哪台RegionServer上有hbase:meta表。

(2)客户端连接含有hbase:meta表的RegionServer。Hbase:meta表存储了所有Region的行健范围信息,通过这个表就可以查询出你要存取的rowkey属于哪个Region的范围里面,以及这个Region又是属于哪个RegionServer。

(3)获取这些信息后,客户端就可以直连其中一台拥有你要存取的rowkey的RegionServer,并直接对其操作。

(4)客户端会把meta信息缓存起来,下次操作就不需要进行以上加载HBase:meta的步骤了。 

一、读数据的流程:get

1)Client先访问zookeeper,从meta表所处位置(ip,找到对应的HRegionServer)

2)访问meta表,然后读取meta表中的数据。根据namespace、tablename、rowkey信息,在meta表中找到该Row数据对应的region信息;获取管理这个Region的RegionServer地址。

3)找到这个region对应的regionserver,查找对应的region;

4)先从MemStore找数据,如果没有,再到BlockCache里面读;

5)BlockCache还没有,再到StoreFile上读(为了读取的效率);

6)如果是从StoreFile里面读取的数据,不是直接返回给客户端,而是先写入BlockCache,再返回给客户端。 

二、写数据的流程:Put

1)Client先访问zookeeper,从meta表所处位置(ip),zookeeper中存储了meta表的region信息,从meta表获取相应region信息,然后找到meta表的数据

2)访问meta表,然后读取meta表中的数据。meta中又存储了用户表的region信息;根据namespace、TableName、rowkey在meta表中找到对应的region信息;通过一定算法计算出要写入的Region。

3)找到该Region对应的RegionServer并进行连接。客户端Clint 向HRegionServer请求写数据 

4)HregionServer将数据分别写到HLog和MemoryStore中。为了数据的持久化和恢复;

8)反馈Client写成功。

5)每当MemoryStore中的大小达到阈值时(内存中的数据128M,时间),会生成一个StoreFile。将数据Flush到硬盘中,并同时删除内存和hlog中的历史数据。若MemStore中的数据有丢失,则可以总HLog上恢复

6.当StoreFile的数量超过一定时,会进行StoreFile的合并(Compact),将多个StoreFile文件合并成一个StoreFile,当HDFS中的数据块达到4块的时候,Hmaster将数据加载到本地进行一个合并

6)当StoreFile的文件大小超过一定阈值时(默认10G256M),会进行Region的切分(Split),由Master将新Region分配到相应不同的RegionServer中,实现负载均衡。使得原先1个Region的压力得以分流到2个Region上

7)当HRegionServer宕机后,将HRegionServer上的hlog重新分配给不同的HRegionServer进行加载(修改.META文件中关于数据所在server的信息)。注意:hlog会同步到HDFS中。

8)HBase只是增加数据,有所得更新和删除操作,都是在Compact阶段做的,所以,用户写操作只需要进入到内存即可立即返回,从而保证I/O高性能。

补充1:HStore存储是HBase存储的核心,其中由两部分组成,一部分是MemStore,一部分是StoreFiles。

由此过程可知,HBase只是增加数据,没有更新和删除操作,用户的更新和删除都是逻辑层面的,在物理层面,更新只是追加操作,删除只是标记操作。

用户写操作只需要进入到内存即可立即返回,从而保证I/O高性能。

2、HLog的功能:

在分布式系统环境中,无法避免系统出错或者宕机,一旦HRegionServer意外退出,MemStore中的内存数据就会丢失,引入HLog就是防止这种情况。

工作机制:每个HRegionServer中都会有一个HLog对象,HLog是一个实现Write Ahead Log的类,每次用户操作写入Memstore的同时,也会写一份数据到HLog文件,HLog文件定期会滚动出新,并删除旧的文件(已持久化到 StoreFile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper感知,HMaster首先处理遗留的 HLog文件,将不同region的log数据拆分,分别放到相应region目录下,然后再将失效的region(带有刚刚拆分的log)重新分配,领取到这些region的 HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。

补充3:Region就是StoreFiles,StoreFiles里由HFile构成,Hfile里由hbase的data块构成,一个data块里面又有很多keyvalue对,每个keyvalue里存了我们需要的值。

3、数据Flush过程

当MemStore数据达到阈值(默认是128M,老版本是64M),将数据刷到硬盘,将内存中的数据删除,同时删除HLog中的历史数据;

有 3 个条件满足任意一个都可以触发 flush:

  1. 当一个 RegionServer 中的所有 MemStore 的大小只和超过了堆内存的 40%. 则这个 RegionServer 中所有的 MemStore 一起刷到 HFile 中,由于 HBase 底层依靠 HDFS,因此 HFile 都存储在 HDFS 之中
  2. 当有任何一个 MemStore 的存活时间超过了 1h, 则这个 RegionServer 中所有的 MemStore 一起刷到 HFile 中.
  3. 单个region里多个memstore的缓存大小,超过那么整个HRegion就会flush,默认128M

4、StoreFile合并(Compaction)

目的:减少StoreFile数量,提升数据读取效率。由于前面的刷写过程的存在, 有可能会导致磁盘上有比较多的 HFile 小文件, 而 HDFS 并不适合存储小文件, 所以就存在了一个小文件合并的过程.

Compaction分为两种:有 2 种合并:

  1. 小合并(Minor Compaction): 当一个store里面允许存的HFile的个数,超过这个个数会被写到一个新的HFile里面,也就是每个region的每个列族对应的memstore在flush为HFile的时候,默认情况下当超过3个HFile的时候就会对这些文件进行合并重写为一个新文件,设置个数越大key减少触发合并的时间,但是每次合并的时间就会越长
  2. 大合并(Major Compaction): Major compaction 指一个 region 下的所有 HFile 做归并排序, 最后形成一个大的HFile. 这可以提高读性能.  major compaction重写所有的Hfile, 占用大量硬盘IO和网络带宽. 这也被称为写放大现象(write amplification)

默认7天执行一次,将多个storefile合并,会将过期的,超出版本数量的、标记为删除的数据都进行删除(一般要在系统空闲的时候去做,因为需要大量的磁盘IO)

Major compaction 可以被调度成自动运行的模式, 但是由于写放大的问题(write amplification), major compaction通常在一周执行一次或者只在凌晨运行.

此外, major compaction的过程中, 如果发现region server负责的数据不在本地的HDFS datanode上, major compaction除了合并文件外, 还会把其中一份数据转存到本地的data node上.

5、Region 拆分(Split)

目的:实现数据访问的负载均衡。

做法:利用Middle Key将当前Region划分为两个等分的子Region。

需要指出的是:Split会产生大量的I/O操作,Split开始前和Split完成后,HRegionServer都会通知HMaster。Split完成后,由于Region映射关系已变更,故HRegionServer会更新meta表。 

按固定长度分割region,固定长度取值优先获取table的“MAX_FILESIZE” 值,若没有设定该属性,则采用在hbase-site.xml中配置的hbase.hregion.max.filesize值,在0.94版本中这个值的缺省值已经被调整为:10 * 1024 * 1024 * 1024L 也就是10G,网上很多关于 hbase.hregion.max.filesize 默认值 1G的文章应该都是基于0.92的hbase的。

最初, 每张表只有一个 region, 当一个 region 变得太大时, 它就分裂成 2 个子region。2个子 region, 各占原始 region 的一半数据, 仍然被相同的 region server管理。然后Region server向HBase master节点汇报拆分完成.

如果集群内还有其他 region server, master 节点倾向于做负载均衡, 所以master节点有可能调度新的 region 到其他 region server, 由其他 region 管理新的分裂出的region.

7、HRegionServer宕机如何处理?

1)ZooKeeper会监控HRegionServer的上下线情况,当ZK发现某个HRegionServer宕机之后会通知HMaster进行失效备援;
2)该HRegionServer会停止对外提供服务,就是它所负责的region暂时停止对外提供服务
3)HMaster会将该HRegionServer所负责的region转移到其他HRegionServer上,并且会对HRegionServer上存在memstore中还未持久化到磁盘中的数据进行恢复
4)这个恢复的工作是由WAL重播来完成,这个过程如下:

  • wal实际上就是一个文件,存在/hbase/WAL/对应RegionServer路径下
  • 宕机发生时,读取该RegionServer所对应的路径下的wal文件,然后根据不同的region切分成不同的临时文件recover.edits
  • 当region被分配到新的RegionServer中,RegionServer读取region时会进行是否存在recover.edits,如果有则进行恢复

三、Zookeeper在HBase中的作用

bin/zkcli.sh (进入zookeeper)

查看hbase集群在zookeeper记录的信息,比如:regionserver1-slave-1,regionserver2-slave-2

ls2 /hbase/rs
[slave-2,16020,1511853261863, slave-1,16020,1511853261718]
cZxid = 0x100000004
ctime = Mon Nov 27 18:08:47 CST 2017
mZxid = 0x100000004
mtime = Mon Nov 27 18:08:47 CST 2017
pZxid = 0x200000426
cversion = 22
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2

查看所有表

[zk: localhost:2181(CONNECTED) 11] ls2 /hbase/table
[aa,hbase:meta, hbase:namespace]
cZxid = 0x100000006
ctime = Mon Nov 27 18:08:47 CST 2017
mZxid = 0x100000006
mtime = Mon Nov 27 18:08:47 CST 2017
pZxid = 0x200000478
cversion = 56
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 24

查看hbase的meta表信息,内涵server信息。

[zk: localhost:2181(CONNECTED) 14] get /hbase/table/hbase:meta
�master:16000�S�!��X�PBUF
cZxid = 0x200000034
ctime = Mon Nov 27 18:16:58 CST 2017
mZxid = 0x200000035
mtime = Mon Nov 27 18:16:58 CST 2017
pZxid = 0x200000034
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 31
numChildren = 0

1.保证Master的高可用性,确保整个集群只有一个HMaster,当状态为Active的Master无法提供服务时,会立刻将状态为StandBy的Master切换为Active状态。

2.实时监控RegionServer集群,当某个RegionServer节点无法提供服务时将会通知Master,由Master进行RegionServer上的Region转移以及重新进行负载均衡。

3.当HBase集群启动后,Master和RegionServer会分别向Zookeeper进行注册,会将hbase 系统表-ROOT- 加载到 zookeeper,会在Zookeeper中存放HBase的META表数据:Region与RegionServer的关系、以及RegionServer的信息(地址等 

通过zookeeper可以获取当前系统表.META.的存储所对应的regionserver信息。进行管理

*META表中维护着TableName、RowKey和Region的关联关系。

这里面数据分区(region)存储是为了查询方便(即因为是集群所以能充分利用磁盘的IO性)。添加数据时,数据先进入Hlog–预写日志(数据只能追加不能修改)<防止数据丢失>,数据在Hlog写完后再写到内存中。 
HFile:认为是将数据进行序列化。 
StoreFile:认为是一个文件。 
HDFS:调用HDFS的客户端API来将数据传到HDFS。 

HBase采用LSM树型结构,而不是B或B+树  LSM树(Log Structured Merge Tree,结构化合并树)

关于磁盘IO

磁盘读写时涉及到磁盘上数据查找,地址一般由柱面号、盘面号和块号三者构成。也就是说移动臂先根据柱面号移动到指定柱面,然后根据盘面号确定盘面的磁道,最后根据块号将指定的磁道段移动到磁头下,便可开始读写。

整个过程主要有三部分时间消耗,查找时间(seek time) +等待时间(latency time)+传输时间(transmission time) 。分别表示定位柱面的耗时、将块号指定磁道段移到磁头的耗时、将数据传到内存的耗时。整个磁盘IO最耗时的地方在查找时间,所以减少查找时间能大幅提升性能。


四、key索引、LSM树原理(一棵LSM树就是一个个B+树合起来。)

1、插入步骤

        LSM-tree是通过将很多小文件的存取转换为连续的大批量传输,使得对于文件系统的大多数存取都是顺序性的,从而提高磁盘带宽利用率;故障恢复速度快。它对数据写入主要分以下三个阶段: 

  1. 数据的写入,append形式插入,以log追加的方式进行按顺序被保存到logfile文件,具有索引; 
  2. 一旦数据被保存到了logfile文件,会被立即保存到一块儿叫的内存缓冲区的memsotre——缓存的数据也是就说排序的
  3. 当内存中的memsotre大到一个阀值的时候,缓存数据会被以key -> record对的形式刷新到磁盘,生成一个新的存储文件持久化数据。

2、合并步骤

        LSM树由两个或以上的存储结构组成,比如在论文中为了方便说明使用了最简单的两个存储结构。一个存储结构常驻内存中,称为C0 tree,具体可以是任何方便健值查找的数据结构,比如红黑树、map之类,B-树。另外一个存储结构常驻在硬盘中,称为C1 tree,具体结构类似B树C1所有节点都是100%满的,节点的大小为磁盘块大小。 

合并过程中会使用两个块:emptying block和filling block。

        从C1中读取未合并叶子节点,放置内存中的emptying block中。从小到大找C0中的节点,与emptying block进行合并排序,合并结果保存到filling block中,并将C0对应的节点删除。

        不断执行第2步操作,合并排序结果不断填入filling block中,当其满了则将其追加到磁盘的新位置上,注意是追加而不是改变原来的节点。

        合并期间如故宫emptying block使用完了则再从C1中读取未合并的叶子节点。C0和C1所有叶子节点都按以上合并完成后即完成一次合并。

        将C0中记录滚动合并到磁盘C1中;对于多个存储结构的情况,当C1体量越来越大就向C2合并,以此类推,一直往上合并Ck。
        由于memstore中的数据每刷新一次生成一个store文件,store文件会随着时间的推移越来越多,系统对这些文件采用一种叫rolliong merge即滚动合并的模式,由后台线程将这些文件合并成一个大的store文件——文件中的数据总是按key排序存储的,这样只需经过很少的磁盘查找就可以查到结果。 

3、查找数据

        在查找数据时,首先会在memstore中的数据中查找,如果查找到则直接返回结构,否则接下来回查找保存在磁盘上的store文件中的数据,返回将结果返回——查的到或查不到。 

        但是读取时,由于不知道数据在哪棵小树上,因此必须遍历所有小树(所以才说LSM牺牲了部分读的性能),每棵小树内部数据是有序的。查询是先查内存中的部分,再去查磁盘上的部分。

3、 删除数据
         删除是一个特殊的更新操作,执行一个delete操作时,这个要删除的数据会被标记为delete marker被保存起来;当查询时会过滤掉标记为“删除”的key的数据。只有在后台线程异步的重写的数据页数据时,标记为“删除”的数据才会被删除。

三、HBase的表结构

HBase中的表由RowKey、ColumnFamily、Column、Timestamp组成。

RowKey

记录的唯一标识,相当于关系型数据库中的主键。

*RowKey最大长度为64KB且按字典顺序进行排序存储。

*HBase会自动为RowKey加上索引,当按RowKey查询时速度很快。

ColumnFamily

列簇相当于特定的一个类别,每个列簇下可以有任意数量个列,并且列是动态进行添加的,只在插入数据后存在,HBase在创建表时只需要指定表名和列簇即可。

*一个列簇下的成员有着相同的前缀,使用冒号来对列簇和列名进行分隔。

*一张表中的列簇最好不超过5个。

Column

列只有在插入数据后才存在,且列在列簇中是有序的。

*每个列簇下的列数没有限制。

Timestamp

HBase中的每个键值对都有一个时间戳,在进行插入时由HBase进行自动赋值。

四、应用场景

HBase: 

  • 瞬间写入量很大,数据库不好支撑或需要很高成本支撑的场景。
  • 数据需要长久保存,且量会持久增长到比较大的场景。
  • HBase不适用与有 join,多级索引,表关系复杂的数据模型。
  • 大数据量(100s TB级数据)且有快速随机访问的需求。如:淘宝的交易历史记录。数据量巨大无容置疑,面向普通用户的请求必然要即时响应。
  • 业务场景简单,不需要关系数据库中很多特性(例如交叉列、交叉表,事务,连接等等)。

  • 对象存储:我们知道不少的头条类、新闻类的的新闻、网页、图片存储在HBase之中,一些病毒公司的病毒库也是存储在HBase之中

  • 时序数据:HBase之上有OpenTSDB模块,可以满足时序类场景的需求

  • 推荐画像:特别是用户的画像,是一个比较大的稀疏矩阵,蚂蚁的风控就是构建在HBase之上

  • 时空数据:主要是轨迹、气象网格之类,滴滴打车的轨迹数据主要存在HBase之中,另外在技术所有大一点的数据量的车联网企业,数据都是存在HBase之中

  • CubeDB OLAP:Kylin一个cube分析工具,底层的数据就是存储在HBase之中,不少客户自己基于离线计算构建cube存储在hbase之中,满足在线报表查询的需求

  • 消息/订单:在电信领域、银行领域,不少的订单查询底层的存储,另外不少通信、消息同步的应用构建在HBase之上

  • Feeds流:典型的应用就是xx朋友圈类似的应用

  • NewSQL:之上有Phoenix的插件,可以满足二级索引、SQL的需求,对接传统数据需要SQL非事务的需求

五、HBase问题解决:

1、HBase一对多关系的表结构设计

最终的解决方案是这个表(按照官方资料): 

TableRow KeyFamilyAttributes(ColumnKeys/Qualifiers)
BlogTableIDinfo:Author, Title, URL
text:No ColumnKey,3version
comment title:Column keys are written like YYYMMDDHHmmss. Should be IN-MEMORY and have a 1 version
comment text:Same keys. 1 Version

其实了解以下两个知识点就可以了: 

1.HBase的二维表结构:三个重要概念是Column Family(以下简称为CF)和Column Key/Qualifier(以下简称为CK)还有RowKey。一个CF可以包含若干个CK。相当于CF是个合并单元格;CK才是具体的列标示,并且可以为空。Rowkey就是行标示,可以理解为主键。

2.Hbase中,对于某个Column Family中的Column Key是可以动态增加的 

存储于关系型数据库中的数据如下,简单起见某些字段删减了: 

表头 

IDAuthorTitleBody
1张三消息头这是内容Hello World!

明细表: 

IDHeadIDCommentAuthorTitleBody
11李四回复头1这是回复内容1
21王五回复头2这是回复内容2

转移到Hbase中存储,需要把以前的明细“纵向延伸”(对于同一表头,明细表一条一条向下加数据),转变为HBase的“横向延伸”(对同一RowKey,添加明细的ColumnKey),Hbase中存储的数据如下,iteye的表不会弄合并单元格,所以用excel截图来展示吧: 

结论:从图中可以看出,HBase是把以前关系数据库明细表的字段作为ColumnFamily,而明细表的主键作为ColumnKey的这种结构来达到一对多的效果的。关系型数据库,明细增多时是纵向添加数据;对于Hbase,则是通过ColumnKey的增加来添加数据 


由此可能产生的问题: 

  • 1.HBase官方不推荐多Column Family,超过3个是妥妥儿不推荐的 可是一对多的这种关系是必须用多Column Family的,这点矛盾让我到现在还很不解。。 
  • 2.RowKey的存储问题,传统数据库主键一般都是递增的方式生成的一批证书值,但是Hbase采用这种方式做为RowKey的话会导致regionserver负载过高的问题,所以RowKey的生成方式需要再讨论。
  • 3.这种一对多的方式,如果回复很多很多,比如贴吧随便一个帖子就是上W回复的,会导致ColumnKey变得很多,也就是说Hbase表会变得很宽=。= 

尽管看过帖子说HBase并不是传统意义的二维结构,就是不会单独为某个Cell为空的区域留出空间存储数据(这里我可能理解和描述的都不太贴切), 总之这种“宽”的表结构,是对传统数据库表结构意识形态的一种冲击,不知道会不会有问题。。
 

2、hbase扩容(增加节点)

二、hbase扩容

1、登陆master1,修改配置文件

$ cd /data1/usr/hbase-1.2.4/conf

$ vi regionservers 

添加新节点主机

slave4

slave5

$ for ip in 2 3 4 5;

do

scp /data1/usr/hbase-1.2.4/conf/regionservers       192.168.11.13$ip:/data1/usr/hbase-1.2.4/etc/hadoop/;

done

登陆新节点,创建目录,修改权限

2、拷贝hbase文件到新节点

登陆master1节点

$ scp -rpq /data1/usr/hbase-1.2.4  hduser@192.168.11.136:/data 

$ scp -rpq /data1/usr/hbase-1.2.4  hduser@192.168.11.137:/data

清理日志

$ cd /data1/usr/hbase-1.2.4/logs

$ rm *.out.*

3、登陆新节点,启动服务

$ cd /data1/usr/hbase-1.2.4/bin

$ ./hbase-daemon.sh start regionserver

$ ./hbase shell
 

3、HBase 宕机如何处理

答:宕机分为 HMaster 宕机和 HRegisoner 宕机,

如果是 HMaster 宕机, HMaster 没有单点问题, HBase 中可以启动多个 HMaster,通过Zookeeper 的 Master Election 机制保证总有一个 Master 运行。即 ZooKeeper 会保证总会有一个 HMaster 在对外提供服务。

如果是 HRegisoner 宕机, HMaster 会将其所管理的 region 重新分布到其他活动的 RegionServer 上,由于数据和日志都持久在 HDFS中,该操作不会导致数据丢失。所以数据的一致性和安全性是有保障的。

4、HRegionServer宕机如何处理?

1)ZooKeeper会监控HRegionServer的上下线情况,当ZK发现某个HRegionServer宕机之后会通知HMaster进行失效备援;
2)该HRegionServer会停止对外提供服务,就是它所负责的region暂时停止对外提供服务
3)HMaster会将该HRegionServer所负责的region转移到其他HRegionServer上,并且会对HRegionServer上存在memstore中还未持久化到磁盘中的数据进行恢复
4)这个恢复的工作是由WAL重播来完成,这个过程如下:

  • wal实际上就是一个文件,存在/hbase/WAL/对应RegionServer路径下
  • 宕机发生时,读取该RegionServer所对应的路径下的wal文件,然后根据不同的region切分成不同的临时文件recover.edits
  • 当region被分配到新的RegionServer中,RegionServer读取region时会进行是否存在recover.edits,如果有则进行恢复

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四月天03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值