HBase之一:HBase原理和设计

1、简介

HBase —— Hadoop Database的简称,Google BigTable的另外一种开源实现方式,从问世之初,就为了解决用大量廉价的机器高速存取海量数据、实现数据分布式存储提供可靠的方案。从功能上来说,HBase彻彻底底是一个数据库,与咱们熟悉的Oracle、MySQL、MSSQL等同样,对外提供数据的存储和读取服务。而从应用的角度来讲,HBase与通常的数据库又有所区别,HBase自己的存取接口至关简单,不支持复杂的数据存取,更不支持SQL等结构化的查询语言;HBase也没有除了rowkey之外的索引,全部的数据分布和查询都依赖rowkey。因此,HBase在表的设计上会有很严格的要求。架构上,HBase是分布式数据库的典范,这点比较像MongoDB的sharding模式,能根据键值的大小,把数据分布到不一样的存储节点上,MongoDB根据configserver来定位数据落在哪一个分区上,HBase经过访问Zookeeper来获取-ROOT-表所在地址,经过-ROOT-表获得相应.META.表信息,从而获取数据存储的region位置。html

 

2、架构

上面提到,HBase是一个分布式的架构,除去底层存储的HDFS外,HBase自己从功能上能够分为三块:Zookeeper群、HMaster群和HRegionServer群。数据库

  • Zookeeper群:HBase集群中不可缺乏的重要部分,主要用于存储Master地址、协调Master和RegionServer等上下线、存储临时数据等等。
  • HMaster群:Master主要是作一些管理操做,如:region的分配,手动管理操做下发等等,通常数据的读写操做并不须要通过Master集群,因此Master通常不须要很高的配置便可。
  • HRegionServer群:RegionServer群是真正数据存储的地方,每一个HRegionServer由若干个region组成,而一个region维护了必定区间rowkey值的数据,整个结构以下图:

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

各个组件的功能说明:api

2.一、Zookeeper:

Zookeeper Quorum存储-ROOT-表地址、HMaster地址
HRegionServer把本身以Ephedral方式注册到Zookeeper中,HMaster随时感知各个HRegionServer的健康情况
Zookeeper避免HMaster单点问题数组

2.二、HMaster:

(HMaster没有单点问题,HBase中能够启动多个HMaster,经过Zookeeper的MasterElection机制保证总有一个Master在运行。)
主要负责Table和Region的管理工做:
1 管理用户对表的增删改查操做
2 管理HRegionServer的负载均衡,调整Region分布
3 Region Split后,负责新Region的分布
4 在HRegionServer停机后,负责失效HRegionServer上Region迁移缓存

5 HDFS上的垃圾文件回收安全

6 处理schema更新请求服务器

2.三、HRegionServer:

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

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

2.四、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高性能。

2.五、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,完成数据恢复。

 

2.5.一、LogFlusher

前面提到,数据以KeyValue形式到达HRegionServer,将写入WAL,以后,写入一个SequenceFile。看过去没问题,可是由于数据流在写入文件系统时,常常会缓存以提升性能。这样,有些本觉得在日志文件中的数据实际在内存中。这里,咱们提供了一个LogFlusher的类。它调用HLog.optionalSync(),后者根据 hbase.regionserver.optionallogflushinterval (默认是10秒),按期调用Hlog.sync()。另外,HLog.doWrite()也会根据 hbase.regionserver.flushlogentries (默认100秒)按期调用Hlog.sync()。Sync() 自己调用HLog.Writer.sync(),它由SequenceFileLogWriter实现。

2.5.二、LogRoller

Log的大小经过$HBASE_HOME/conf/hbase-site.xml 的 hbase.regionserver.logroll.period 限制,默认是一个小时。因此每60分钟,会打开一个新的log文件。长此以往,会有一大堆的文件须要维护。首先,LogRoller调用HLog.rollWriter(),定时滚动日志,以后,利用HLog.cleanOldLogs()能够清除旧的日志。它首先取得存储文件中的最大的sequence number,以后检查是否存在一个log全部的条目的“sequence number”均低于这个值,若是存在,将删除这个log。

每一个region server维护一个HLog,而不是每个region一个,这样不一样region(来自不一样的table)的日志会混在一块儿,这样作的目的是不断追加单个文件相对于同时写多个文件而言,能够减小磁盘寻址次数,所以能够提升table的写性能。带来麻烦的时,若是一个region server下线,为了恢复其上的region,须要讲region server上的log进行拆分,而后分发到其余region server上进行恢复。

3、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

3.一、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部分没有这么复杂的结构,就是纯粹的二进制数据

3.二、HLog

  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.三、目录表(.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.区域分配会失效并被从新分配,如同启动时序。

C、预写日志(wal)

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

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

 

数据组织

整个架构中,ZK用于服务协调和整个集群运行过程当中部分信息的保存和-ROOT-表地址定位,Master用于集群内部管理,因此剩下的RS主要用于处理数据。
RS是处理数据的主要场所,那么在RS内部的数据是怎么分布的?其实RS自己只是一个容器,其定义了一些功能线程,好比:数据合并线程(compact thread)、storeFile分割线程(split thread)等等。容器中的主要对象就是region,region是一个表根据自身rowkey范围划分的一部分,一个表能够被划分红若干部分,也就是若干个region,region能够根据rowkey范围不一样而被分布在不一样的RS上(固然也能够在同一个RS上,但不建议这么作)。一个RS上能够包含多个表的region,也能够只包含一个表的部分region,RS和表是两个不一样的概念。
这里还有一个概念——列簇。对HBase有一些了解的人,或多或少据说过:HBase是一个列式存储的数据库,而这个列式存储中的列,实际上是区别于通常数据库的列,这里的列的概念,就是列簇,列簇,顾名思义就是不少列的集合,而在数据存储上来说,不一样列簇的数据,必定是分开存储的,即便是在同一个region内部,不一样的列簇也存储在不一样的文件夹中,这样作的好处是,通常咱们定义列簇的时候,一般会把相似的数据放入同一个列簇,不一样的列簇分开存储,有利于数据的压缩,而且HBase自己支持多种压缩方式。

原理

前面介绍了HBase的通常架构,咱们知道了HBase有ZK、Master和RS等组成,本节咱们来介绍下HBase的基本原理,从数据访问、RS路由到RS内部缓存、数据存储和刷写再到region的合并和拆分等等功能。

RegionServer定位

访问HBase经过HBase客户端(或API)进行,整个HBase提供给外部的地址,实际上是ZK的入口,前面也介绍了,ZK中有保存-ROOT-所在的RS地址,从-ROOT-表能够获取.META.表信息,根据.META.表能够获取region在RS上的分布,整个region寻址过程大体以下:

RS定位过程

  1. 首先,Client经过访问ZK来请求目标数据的地址。
  2. ZK中保存了-ROOT-表的地址,因此ZK经过访问-ROOT-表来请求数据地址。
  3. 一样,-ROOT-表中保存的是.META.的信息,经过访问.META.表来获取具体的RS。
  4. .META.表查询到具体RS信息后返回具体RS地址给Client。
  5. Client端获取到目标地址后,而后直接向该地址发送数据请求。

上述过程实际上是一个三层索引结构,从ZK获取-ROOT-信息,再从-ROOT-获取.META.表信息,最后从.META.表中查到RS地址后缓存。这里有几个问题:

  • 既然ZK中能保存-ROOT-信息,那么为何不把.META.信息直接保存在ZK中,而须要经过-ROOT-表来定位?
  • Client查找到目标地址后,下一次请求还须要走ZK  —> -ROOT- —> .META.这个流程么?

先来回答第一个问题:为何不直接把.META.表信息直接保存到ZK中?主要是为了保存的数据量考虑,ZK中不宜保存大量数据,而.META.表主要是保存Region和RS的映射信息,region的数量没有具体约束,只要在内存容许的范围内,region数量能够有不少,若是保存在ZK中,ZK的压力会很大。因此,经过一个-ROOT-表来转存到RS中是一个比较理想的方案,相比直接保存在ZK中,也就多了一层-ROOT-表的查询,对性能来讲影响不大。
第二个问题:每次访问都须要走ZK –> -ROOT- —> .META.的流程么?固然不须要,Client端有缓存,第一次查询到相应region所在RS后,这个信息将被缓存到Client端,之后每次访问都直接从缓存中获取RS地址便可。固然这里有个意外:访问的region若果在RS上发生了改变,好比被balancer迁移到其余RS上了,这个时候,经过缓存的地址访问会出现异常,在出现异常的状况下,Client须要从新走一遍上面的流程来获取新的RS地址。整体来讲,region的变更只会在极少数状况下发生,通常变更不会很大,因此在整个集群访问过程当中,影响能够忽略。

Region数据写入

HBase经过ZK —> -ROOT-  —> .META.的访问获取RS地址后,直接向该RS上进行数据写入操做,整个过程以下图:

RegionServer数据操做过程

Client经过三层索引得到RS的地址后,便可向指定RS的对应region进行数据写入,HBase的数据写入采用WAL(write ahead log)的形式,先写log,后写数据。HBase是一个append类型的数据库,没有关系型数据库那么复杂的操做,因此记录HLog的操做都是简单的put操做(delete/update操做都被转化为put进行)

HLog

HLog写入

HLog是HBase实现WAL方式产生的日志信息,其内部是一个简单的顺序日志,每一个RS上的region都共享一个HLog,全部对于该RS上的region数据写入都被记录到该HLog中。HLog的主要做用就是在RS出现意外崩溃的时候,能够尽可能多的恢复数据,这里说是尽可能多,由于在通常状况下,客户端为了提升性能,会把HLog的auto flush关掉,这样HLog日志的落盘全靠操做系统保证,若是出现意外崩溃,短期内没有被fsync的日志会被丢失。

HLog过时

HLog的大量写入会形成HLog占用存储空间会愈来愈大,HBase经过HLog过时的方式进行HLog的清理,每一个RS内部都有一个HLog监控线程在运行,其周期能够经过hbase.master.cleaner.interval进行配置。
HLog在数据从memstore flush到底层存储上后,说明该段HLog已经再也不被须要,就会被移动到.oldlogs这个目录下,HLog监控线程监控该目录下的HLog,当该文件夹下的HLog达到hbase.master.logcleaner.ttl设置的过时条件后,监控线程当即删除过时的HLog。

Memstore

数据存储

memstore是region内部缓存,其大小经过HBase参数hbase.hregion.memstore.flush.size进行配置。RS在写完HLog之后,数据写入的下一个目标就是region的memstore,memstore在HBase内部经过LSM-tree结构组织,因此可以合并大量对于相同rowkey上的更新操做。
正是因为memstore的存在,HBase的数据写入都是异步的,并且性能很是不错,写入到memstore后,该次写入请求就能够被返回,HBase即认为该次数据写入成功。这里有一点须要说明,写入到memstore中的数据都是预先按照rowkey的值进行排序的,这样有利于后续数据查找。

数据刷盘

memstore中的数据在必定条件下会进行刷写操做,使数据持久化到相应的存储设备上,触发memstore刷盘的操做有多种不一样的方式以下图:

Memstore刷写流程

以上1,2,3均可以触发memstore的flush操做,可是实现的方式不一样:

  • 1经过全局内存控制,触发memstore刷盘操做。memstore总体内存占用上限经过参数hbase.regionserver.global.memstore.upperLimit进行设置,固然在达到上限后,memstore的刷写也不是一直进行,在内存降低到hbase.regionserver.global.memstore.lowerLimit配置的值后,即中止memstore的刷盘操做。这样作,主要是为了防止长时间的memstore刷盘,会影响总体的性能。
  • 在该种状况下,RS中全部region的memstore内存占用都没达到刷盘条件,但总体的内存消耗已经到一个很是危险的范围,若是持续下去,颇有可能形成RS的OOM,这个时候,须要进行memstore的刷盘,从而释放内存。
  • 2手动触发memstore刷盘操做
  • HBase提供API接口,运行经过外部调用进行memstore的刷盘
  • 3 memstore上限触发数据刷盘
  • 前面提到memstore的大小经过hbase.hregion.memstore.flush.size进行设置,当region中memstore的数据量达到该值时,会自动触发memstore的刷盘操做。

刷盘影响

memstore在不一样的条件下会触发数据刷盘,那么整个数据在刷盘过程当中,对region的数据写入等有什么影响?memstore的数据刷盘,对region的直接影响就是:在数据刷盘开始到结束这段时间内,该region上的访问都是被拒绝的,这里主要是由于在数据刷盘结束时,RS会对改region作一个snapshot,同时HLog作一个checkpoint操做,通知ZK哪些HLog能够被移到.oldlogs下。从前面图上也能够看到,在memstore写盘开始,相应region会被加上UpdateLock锁,写盘结束后该锁被释放。

StoreFile

memstore在触发刷盘操做后会被写入底层存储,每次memstore的刷盘就会相应生成一个存储文件HFile,storeFile即HFile在HBase层的轻量级分装。数据量的持续写入,形成memstore的频繁flush,每次flush都会产生一个HFile,这样底层存储设备上的HFile文件数量将会愈来愈多。无论是HDFS仍是Linux下经常使用的文件系统如Ext四、XFS等,对小而多的文件上的管理都没有大文件来的有效,好比小文件打开须要消耗更多的文件句柄;在大量小文件中进行指定rowkey数据的查询性能没有在少许大文件中查询来的快等等。

Compact

大量HFile的产生,会消耗更多的文件句柄,同时会形成RS在数据查询等的效率大幅度降低,HBase为解决这个问题,引入了compact操做,RS经过compact把大量小的HFile进行文件合并,生成大的HFile文件。
RS上的compact根据功能的不一样,能够分为两种不一样类型,即:minor compact和major compact。

  • Minor Compact

minor compact又叫small compact,在RS运行过程当中会频繁进行,主要经过参数hbase.hstore.compactionThreshold进行控制,该参数配置了HFile数量在知足该值时,进行minor compact,minor compact只选取region下部分HFile进行compact操做,而且选取的HFile大小不能超过hbase.hregion.max.filesize参数设置。

  • Major Compact

相反major compact也被称之为large compact,major compact会对整个region下相同列簇的全部HFile进行compact,也就是说major compact结束后,同一个列簇下的HFile会被合并成一个。major compact是一个比较长的过程,对底层I/O的压力相对较大。
major compact除了合并HFile外,另一个重要功能就是清理过时或者被删除的数据。前面提到过,HBase的delete操做也是经过append的方式写入,一旦某些数据在HBase内部被删除了,在内部只是被简单标记为删除,真正在存储层面没有进行数据清理,只有经过major compact对HFile进行重组时,被标记为删除的数据才能被真正的清理。
compact操做都有特定的线程进行,通常状况下不会影响RS上数据写入的性能,固然也有例外:在compact操做速度跟不上region中HFile增加速度时,为了安全考虑,RS会在HFile达到必定数量时,对写入进行锁定操做,直到HFile经过compact降到必定的范围内才释放锁。

Split

compact将多个HFile合并单个HFile文件,随着数据量的不断写入,单个HFile也会愈来愈大,大量小的HFile会影响数据查询性能,大的HFile也会,HFile越大,相对的在HFile中搜索的指定rowkey的数据花的时间也就越长,HBase一样提供了region的split方案来解决大的HFile形成数据查询时间过长问题。
一个较大的region经过split操做,会生成两个小的region,称之为Daughter,通常Daughter中的数据是根据rowkey的之间点进行切分的,region的split过程大体以下图:

region split流程

  1. region先更改ZK中该region的状态为SPLITING。
  2. Master检测到region状态改变。
  3. region会在存储目录下新建.split文件夹用于保存split后的daughter region信息。
  4. Parent region关闭数据写入并触发flush操做,保证全部写入Parent region的数据都能持久化。
  5. 在.split文件夹下新建两个region,称之为daughter A、daughter B。
  6. Daughter A、Daughter B拷贝到HBase根目录下,造成两个新的region。
  7. Parent region通知修改.META.表后下线,再也不提供服务。
  8. Daughter A、Daughter B上线,开始向外提供服务。
  9. 若是开启了balance_switch服务,split后的region将会被从新分布。

上面1 ~ 9就是region split的整个过程,split过程很是快,速度基本会在秒级内,那么在这么快的时间内,region中的数据怎么被从新组织的?
其实,split只是简单的把region从逻辑上划分红两个,并无涉及到底层数据的重组,split完成后,Parent region并无被销毁,只是被作下线处理,再也不对外部提供服务。而新产生的region Daughter A和Daughter B,内部的数据只是简单的到Parent region数据的索引,Parent region数据的清理在Daughter A和Daughter B进行major compact之后,发现已经没有到其内部数据的索引后,Parent region才会被真正的清理。

HBase设计

HBase是一个分布式数据库,其性能的好坏主要取决于内部表的设计和资源的分配是否合理。

Rowkey设计

rowkey是HBase实现分布式的基础,HBase经过rowkey范围划分不一样的region,分布式系统的基本要求就是在任什么时候候,系统的访问都不要出现明显的热点现象,因此rowkey的设计相当重要,通常咱们建议rowkey的开始部分以hash或者MD5进行散列,尽可能作到rowkey的头部是均匀分布的。禁止采用时间、用户id等明显有分段现象的标志直接看成rowkey来使用。

列簇设计

HBase的表设计时,根据不一样需求有不一样选择,须要作在线查询的数据表,尽可能不要设计多个列簇,咱们知道,不一样的列簇在存储上是被分开的,多列簇设计会形成在数据查询的时候读取更多的文件,从而消耗更多的I/O。

TTL设计

选择合适的数据过时时间也是表设计中须要注意的一点,HBase中容许列簇定义数据过时时间,数据一旦超过过时时间,能够被major compact进行清理。大量无用历史数据的残余,会形成region体积增大,影响查询效率。

Region设计

通常地,region不宜设计成很大,除非应用对阶段性性能要求不少,可是在未来运行一段时间能够接受停服处理。region过大会致使major compact调用的周期变长,而单次major compact的时间也相应变长。major compact对底层I/O会形成压力,长时间的compact操做可能会影响数据的flush,compact的周期变长会致使许多删除或者过时的数据不能被及时清理,对数据的读取速度等都有影响。
相反,小的region意味着major compact会相对频繁,可是因为region比较小,major compact的相对时间较快,并且相对较多的major compact操做,会加速过时数据的清理。
固然,小region的设计意味着更多的region split风险,region容量太小,在数据量达到上限后,region须要进行split来拆分,其实split操做在整个HBase运行过程当中,是被不怎么但愿出现的,由于一旦发生split,涉及到数据的重组,region的再分配等一系列问题。因此咱们在设计之初就须要考虑到这些问题,尽可能避免region的运行过程当中发生split。
HBase能够经过在表建立的时候进行region的预分配来解决运行过程当中region的split产生,在表设计的时候,预先分配足够多的region数,在region达到上限前,至少有部分数据会过时,经过major compact进行清理后, region的数据量始终维持在一个平衡状态。
region数量的设计还须要考虑内存上的限制,经过前面的介绍咱们知道每一个region都有memstore,memstore的数量与region数量和region下列簇的数量成正比,一个RS下memstore内存消耗:

Memory = memstore大小 * region数量 * 列簇数量

若是不进行前期数据量估算和region的预分配,经过不断的split产生新的region,容易致使由于内存不足而出现OOM现象。

相关文章
相关标签/搜索