HBase使用入门
2015-09-18 22:22:41 阿炯

本站赞助商链接,请多关照。 Hbase是运行在Hadoop上的NoSQL数据库,它是一个分布式的和可扩展的大数据仓库,也就是说HBase能够利用HDFS的分布式处理模式,并从Hadoop的MapReduce程序模型中获益。这意味着在一组商业硬件上存储许多具有数十亿行和上百万列的大表。除去Hadoop的优势,HBase本身就是十分强大的数据库,它能够融合key/value存储模式带来实时查询的能力,以及通过MapReduce进行离线处理或者批处理的能力。进一步提高了数据的可靠性和系统的健壮性,并且发挥HBase处理大型数据的能力。HBase存储的是松散型数据,具体来说,HBase存储的数据介于映射(key/value)和关系型数据之间。HBase存储的数据从逻辑上看就是一张很大的表,并且它的数据列可以根据需要动态增加,每一个cell中的数据又可以有多个版本(通过时间戳来区别)。

谷歌曾经面对过一个挑战的问题:如何能在整个互联网上提供实时的搜索结果?答案是它本质上需要将互联网缓存,并重新定义在这样庞大的缓存上快速查找的新方法。为了达到这个目的,定义如下技术:
 谷歌文件系统GFS:可扩展分布式文件系统,用于大型的、分布式的、数据密集型的应用程序。
 BigTable:分布式存储系统,用于管理被设计成规模很大的结构化数据:来自数以千计商用服务器的PB级别的数据。
 MapReduce:一个程序模型,用于处理和生成大数据集的相关实现。

在谷歌发布这些技术的文档之后, 不久以后我们就看到了它们的开源实现版本 ,就在2007年,Mike Cafarella发布了BigTable开源实现的代码,他称其为HBase,后来HBase成为Apache的顶级项目。HDFS 为 HBase 提供底层存储支持,MapReduce 为其提供计算能力,ZooKeeper 为其提供协调服务和 failover(失效转移的备份操作)机制。Pig 和 Hive 为 HBase 提供了高层语言支持,使其可以进行数据统计(可实现多表 join 等),Sqoop 则为其提供 RDBMS 数据导入功能。

HBase不能支持 where 条件、Order by 查询,只支持按照主键 Rowkey 和主键的 range 来查询,但是可以通过 HBase 提供的 API 进行条件过滤。它不是一个关系型数据库,它需要不同的方法定义你的数据模型,HBase实际上定义了一个四维数据模型,下面就是每一维度的定义:
行键:每行都有唯一的行键,行键没有数据类型,它内部被认为是一个字节数组。

列簇:数据在行中被组织成列簇,每行有相同的列簇,但是在行之间,相同的列簇不需要有相同的列修饰符。在引擎中,HBase将列簇存储在它自己的数据文件中,所以它们需要事先被定义,此外,改变列簇并不容易。

列修饰符:列簇定义真实的列,被称之为列修饰符,你可以认为列修饰符就是列本身。

版本:每列都可以有一个可配置的版本数量,你可以通过列修饰符的制定版本获取数据。


图1.  HBase Four-Dimensional Data Model

如图1中所示,通过行键获取一个指定的行,它由一个或多个列簇构成,每个列簇有一个或多个列修饰符(图1中称为列),每列又可以有一个或多个版本。为了获取指定数据,你需要知道它的行键、列簇、列修饰符以及版本。当设计HBase数据模型时,对考虑数据是如何被获取是十分有帮助的。你可以通过以下两种方式获得HBase数据:
 通过他们的行键,或者一系列行键的表扫描。
 使用map-reduce进行批操作

这种双重获取数据的方法使得HBase变得十分强大,典型地,在Hadoop中存储数据意味着它对离线或批处理方式分析是有益的(尤其是批处理分析),但对实时获取是不必要的。HBase通过key/value存储来支持实时分析,以及通过map-reduce支持批处理分析。让我们首先来看实时数据获取,作为key/value存储,key是行键,value是列簇的集合,如图2所示。


图2.  HBase as a Key/Value Store

如你在图2中看到的,key是我们所提到过的行键,value是列簇的集合。你可以通过key检索到value,或者换句话说,你可以通过行键“得到”行,或者你能通过给定起始和终止行键检索一系列行,这就是前面提到的表扫描。你不能实时的查询一个列的值,这就引出了一个重要的话题:行键的设计。

有两个原因令行键的设计十分重要:
表扫描是对行键的操作,所以,行键的设计控制着你能够通过HBase执行的实时/直接获取量。

当在生产环境中运行HBase时,它在HDFS上部运行,数据基于行键通过HDFS,如果你所有的行键都是以user-开头,那么很有可能你大部分数据都被分配一个节点上(违背了分布式数据的初衷),因此行键应该是有足够的差异性以便分布式地通过整个部署。

你定义行键的方式取决于你想怎样存取那些行。如果你想以用户为基础存储数据,那么一个策略是利用字节队列在HBase中存储行键,所以我们可以创建一个用户ID的哈希(例如MD5或SHA-1),然后在哈希后面附上时间(long类型)。使用哈希有两个重点:
(1)是它能够将value分散开,数据能够分布式地通过簇,
(2)是它确保key的长度是一致的,以更加容易在表扫描中使用。

ColumnFamily 是“列族”,属于 schema 表,在建表时定义,每个列属于一个列族,列名用列族作为前缀“ColumnFamily:qualifier”,访问控制、磁盘和内存的使用统计都是在列族层面进行的。

Cell 是通过行和列确定的一个存储单元,值以字节码存储,没有类型。

Timestamp 是区分不同版本 Cell 的索引,64 位整型。不同版本的数据按照时间戳倒序排列,最新的数据版本排在最前面。

Hbase 在行方向上水平划分成 N 个 Region,每个表一开始只有一个 Region,数据量增多,Region 自动分裂为两个,不同 Region 分布在不同 Server 上,但同一个不会拆分到不同服务器上。

Region 按 ColumnFamily 划分成 Store,Store 为最小存储单元,用于保存一个列族的数据,每个 Store 包括内存中的 memstore 和持久化到 disk 上的 HFile。

HBase 的表数据分为多个层次:HRegion->HStore->[HFile,HFile,...,MemStore]。

在 HBase 中,一张表可以有多个 Column Family,在一次 Scan 的流程中,每个 Column Family(Store) 的数据读取由一个 StoreScanner 对象负责。每个 Store 的数据由一个内存中的 MemStore 和磁盘上的 HFile 文件组成,对应的 StoreScanner 对象使用一个 MemStoreScanner 和 N 个 StoreFileScanner 来进行实际的数据读取。

因此,读取一行的数据需要以下步骤:
 按照顺序读取出每个 Store
 对于每个 Store,合并 Store 下面的相关的 HFile 和内存中的 MemStore

这两步都是通过堆来完成。RegionScanner 的读取通过下面的多个 StoreScanner 组成的堆完成,使用 RegionScanner 的成员变量 KeyValueHeap storeHeap 表示。一个 StoreScanner 一个堆,堆中的元素就是底下包含的 HFile 和 MemStore 对应的 StoreFileScanner 和 MemStoreScanner。堆的优势是建堆效率高,可以动态分配内存大小,不必事先确定生存周期。

接着调用 seekScanners() 对这些 StoreFileScanner 和 MemStoreScanner 分别进行 seek。seek 是针对 KeyValue 的,seek 的语义是 seek 到指定 KeyValue,如果指定 KeyValue 不存在,则 seek 到指定 KeyValue 的下一个。

-------------------------------
HBase体系结构


HBase的服务器体系结构遵从简单的主从服务器架构,它由HRegion Server群和HBase Master服务器构成。HBase Master负责管理所有的HRegion Server,而HBase中的所有RegionServer都是通过ZooKeeper来协调,并处理HBase服务器运行期间可能遇到的错误。HBase Master Server本身并不存储HBase中的任何数据,HBase逻辑上的表可能会被划分成多个Region,然后存储到HRegion Server群中。HBase Master Server中存储的是从数据到HRegion Server的映射。

1)Client
HBase Client使用HBase的RPC机制与HMaster和HRegion Server进行通信,对于管理类操作,Client与HMaster进行RPC;对于数据读写类操作,Client与HRegionServer进行RPC。

2)Zookeeper
Zookeeper Quorum中除了存储了-ROOT-表的地址和HMaster的地址,HRegionServer会把自己以Ephemeral方式注册到Zookeeper中,使得HMaster可以随时感知到各个HRegionServer的健康状态。此外Zookeeper也避免了HMaster的单点问题。

3)HMaster
每台HRegionServer都会与HMaster进行通信,HMaster的主要任务就是要告诉每台HRegion Server它要维护哪些HRegion。当一台新的HRegionServer登录到HMaster时,HMaster会告诉它等待分配数据。而当一台HRegion死机时,HMaster会把它负责的HRegion标记为未分配,然后再把它们分配到其他的HRegion Server中。

HBase已经解决了HMaster单点故障问题(SPFO),并且HBase中可以启动多个HMaster,那么它就能够通过Zookeeper来保证系统中总有一个Master在运行。HMaster在功能上主要负责Table和Region的管理工作,具体包括:
 管理用户对Table的增删改查操作
 管理HRegionServer的负载均衡,调整Region分布
 在Region Split后,负责新Region的分配
 在HRegionServer停机后,负责失效HRegionServer上的Region迁移

4)HRegion
当表的大小超过设置值得时候,HBase会自动地将表划分为不同的区域,每个区域包含所有行的一个子集。对用户来说,每个表是一堆数据的集合,靠主键来区分。从物理上来说,一张表被拆分成了多块,每一块就是一个HRegion。我们用表名+开始/结束主键来区分每一个HRegion,一个HRegion会保存一个表里面某段连续的数据,从开始主键到结束主键,一张完整的表格是保存在多个HRegion上面。

当Table随着记录数不断增加而变大后,会逐渐分裂成多份splits,成为regions,一个region由[startkey, endkey]表示,不同的region会被Master分配给响应的RegionServer进行管理。

5)HRegionServer
所有的数据库数据一般都是保存在Hadoop分布式文件系统上面的,用户通过一系列HRegion服务器获取这些数据,一台机器上面一般只运行一个HRegionServer,且每一个区段的HRegion也只会被一个HRegion服务器维护。

HRegion Server主要负责响应用户的IO请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region,HRegion中由多个HStore组成。每个HStore对应了Table中的一个Column Family的存储,可以看出每个ColumnFamily其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。

HStore存储时HBas存储的核心了,其中由两部分组成,一部分是MemStore,一部分是StoreFiles。MemStore*是Sorted Memory Buffer,用户写入数据首先会放入MemStore,当MemStore满了以后会flush成一个*StoreFile(底层是HFile),当StoreFile文件数增长到一定阈值,会触发Compact合并操作,将多个StoreFile合并成一个StoreFile,合并过程中会进行版本合并和数据删除,因此可以看出HBase其实只有增加数据,所有的更新和删除操作都是后续的compact过程中进行的,这使得用户的写操作只要进入内存中就可以立刻返回,保证了HBase IO的高性能。当StoreFiles Compact后,会逐步形成越来越大的StoreFile,当单个StoreFile大小超过一定的阈值后,会触发Split操作,同时会把当前的Region Split成2个Region,父Region会下线,新Split出的2个孩子Region会被HMaster分配到响应的HRegion Server上,使得原先1个Region的压力得以分流道2个Region上。

理解上述HStore的基本原理之后,必须了解一下HLog的功能,因为上述的HStore在系统正常工作的前提下是没有问题的,但是在分布式系统环境中,无法避免系统出错或者宕机,一次一旦HRegion Server意外退出,MemStore中的内存数据将会丢失,这就需要引入HLog了。每一个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中,HLog文件定期会滚动出新的,并删除旧的文件,当HRegionServer意外终止后,HMaster会通过Zookeeper感知到,HMaster首先会处理遗留的HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应Region的目录下,然后再将失效的Region重新分配,领取到这些Region的HRegionServer在LoadRegion过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。

6)HBase存储格式
HBase中的所有数据文件都存储在Hadoop HDFS文件系统上,包括上述提到的两种文件类型:
 HFile HBase中的KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级的包装,即StoreFile底层就是HFile。
 HLogFile,HBase中WAL(Write Ahead Log)的存储格式,物理上是Hadoop的Sequence File

7)ROOT表和META表
用户表的Regions元数据被存储在.META.表中,随着Region的增多,.META.表中的数据也会增大,并分裂成多个Regions。为了定位.META.表中各个Regions的位置,把.META.表中的所有Regions的元数据保存在-ROOT-表中,最后由Zookeeper记录-ROOT-表的位置信息。所有客户端访问用户数据前,需要首先访问Zookeeper获得-ROOT-的位置,然后方位-ROOT-表获得.META.表的位置,最后根据.META.表中的信息确定用户数据存放的位置,-ROOT-表永远不会被分割,它只有一个Region,这样可以保证最多需要三次跳转就可以定位任意一个Region。为了加快访问速度,.META.表的Regions全部保存在内存中,如果.META.表中的每一行在内存中占大约1KB,且每个Region限制为128M,下图中的三层结构可以保存Regions的数目为(128M/1KB)*(128/1KB)=2^34个。

-------------------------------
HBase数据模型


HBase是一个类似于BigTable的分布式数据库,它是一个稀疏的长期存储的(存在硬盘上)、多维度的、排序的映射表。这张表的索引是行关键字、列关键字和时间戳。HBase的数据都是字符串,没有类型。

用户在表格中存储数据,每行都有一个可排序的主键和任意多的列,由于是系数存储,所以同一张表里面的每行数据都可以由截然不同的列。

列名字的格式是“<family>:<qualifier>”(<列簇>:<限定符>),都是有字符串组成的。每一张表有一个列簇(family)集合,这个集合是固定不变的,只能通过改变表结构来改变。但是限定符(qualifier)的值相对于每一行来说都是可以改变的。HBase把用一个列簇里面的数据存储在同一个目录底下,并且HBase的写操作时琐行的,每一行来说都是一个原子元素,都可以加锁。HBase所有数据库的更新都有一个时间戳标记,每个更新都是一个新的版本,HBase会保留一定数量的版本,这个值是可以设定的,客户端可以选择获取距离某个时间点最近的版本单元的值,或者一次获取所有版本单元的值。

1)逻辑模型
可以将表想象成一个大的映射关系,通过行健、行健+时间戳或者行健+列(列簇:列修饰符),就可以定位特定数据。由于HBase是稀疏存储数据的,所以某些列可以空白的。如下表,给出的是 www.cnn.com 网站的数据存放逻辑视图,表中仅有一行数据,行的唯一标识为"com.163.www" ,对这行数据的每一次逻辑修改都有一个时间戳关联对应。表中共有四列:contents:html、anchor:freeoa.net、anchor:my.lock.ca、mime:type,每一行以前缀的方式给出其所属的列簇。

行健是数据行在表中的唯一标识,并作为检索记录的主键。在HBase中访问表中的行只有三种方式:通过当个行健访问;给定行健的范围访问;全表扫描。行健可以任意字符串(最大长度64KB)并按照字典序进行存储。对那些经常一起读取的行,需要对key值精心设计,以便它们能放在一起存储。

2)概念模型
HBase是按照列存储的稀疏行/列矩阵,物理模型实际上就是把概念模型中的一行进行切割,并按照列族存储,这点在进行数据设计和程序开发的时候必须牢记。上面的逻辑视图在物理存储的时候应该表现下面的样子:

从上图可以看出空值是不被存储的,所以查询时间戳为t8的“contents:html”将返回null,同样查询时间戳为t9,"anchor:my.lock.ca"的项也返回null。如果没有指明时间戳,那么应该返回指定列的最新数据,并且最新的值在表格里也是最先找到的,因为他们是按照时间排序的。所以,如果查询“contents”而不指明时间戳,将返回t6的数据,这种存储结构还有一个优势就是可以随时向表中的任何一个列族添加新列,而不需要事先说明。

-------------------------------
hdfs技术细节


对HDFS上HBase所在的主目录下文件,以及被插入表格的region情况进行时发生了什么事情。

回溯到客户端喂入数据的开始阶段,创建表格,在HDFS上便被创建了一个与表格同名的目录,该目录下将出现第一个region,region中会以family名创建一个目录,这个目录下才存在记录具体数据的文件。同时在该表表名目录下,还会生成一个“compaction.dir”目录,该目录将在family名目录下region文件超过指定数目时用于合并region。当第一个region目录出现时,内存中最初被写入的数据将被保存到该文件中,这个间隔是由选项“hbase.hregion.memstore.flush.size”决定的,默认是64MB,该region所在的Regionserver的内存中一旦有超过64MB的数据时,就将被写入到region文件中。这个文件将不断增殖,直到超过由“hbase.hregion.max.filesize”决定的文件大小(默认是256MB,此时加上内存刷入的数据,实际最大可能到256MB+64MB)时,该region将被执行split,立即被一切为二,其过程是在该目录下创建一个名为“.splits”的目录作为标记,然后由Regionserver将文件信息读取进来,分别写入到两个新的region目录中,最后再将老的region删除。这里的标记目录“.splits”可以避免在split过程中发生其他操作,起到类似于多线程安全的锁功能。

在新的region中,从老的region中切分出的数据独立为一个文件并不再接收新的数据(该文件大小超过了64MB,最大可达到(256+64)/2=160MB)),内存中新的数据将被保存到一个重新创建的文件中,该文件大小将为64MB。内存每刷新一次,region所在的目录下就将增加一个64MB的文件,直到总文件数超过由“hbase.hstore.compactionThreshold”指定的数量时(默认为3),compaction过程就将被触发了。在上述值为3时,此时该region目录下,实际文件数只有两个,还有额外的一个正处于内存中将要被刷入到磁盘的过程中。Compaction过程是HBase的一个大动作。HBase不仅要将这些文件转移到“compaction.dir”目录进行压缩,而且在压缩后的文件超过256MB时,还必须立即进行split动作。待Compaction结束之后,后续的split依然会持续一小段时间,直到所有的region都被切割分配完毕,HBase才会恢复平静并等待下一次数据从内存写入到HDFS。

HBase在已经发布的0.90.x版对Compaction和Split机制作了调整,将Split过程提到了Compaction之前,也就是说,当region目录下,HFiles数目超过“hbase.hstore.compactionThreshold”指定值之后,Regionserver会首先计算一下Compaction之后的文件大小是否会超过“hbase.hregion.max.filesize”确定的Split上限大小,如果超过了,那么HFiles首先被切分,然后才会将切分好的文件转移到新的region中Compaction。这样将大大减小Compaction的压力,由此可以推断,HBase的性能调优必然与“hbase.hstore.compactionThreshold”和“hbase.hregion.max.filesize”这两个值的大小息息相关。

-------------------------------
HBase 数据表优化


HBase 是一个高可靠性、高性能、面向列、可伸缩的分布式数据库,但是当并发量过高或者已有数据量很大时,读写性能会下降。我们可以采用如下方式逐步提升 HBase 的检索速度。

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

Rowkey 优化
HBase中 Rowkey 是按照字典序存储,因此设计 Rowkey 时,要充分利用排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。

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

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

缓存策略 (setCaching)
创建表的时候,可以通过 HColumnDescriptor.setInMemory(true) 将表放到 RegionServer 的缓存中,保证在读取的时候被 cache 命中。

设置存储生命期
创建表的时候,可以通过 HColumnDescriptor.setTimeToLive(int timeToLive) 设置表中数据的存储生命期,过期数据将自动被删除。

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

分配合适的内存给 RegionServer 服务
在不影响其他服务的情况下,越大越好。例如在 HBase 的 conf 目录下的 hbase-env.sh 的最后添加 export HBASE_REGIONSERVER_OPTS=”-Xmx16000m $HBASE_REGIONSERVER_OPTS”,其中 16000m 为分配给 RegionServer 的内存大小。

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

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

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

客户端一次从服务器拉取的数量
通过配置一次拉去的较大的数据量可以减少客户端获取数据的时间,但是它会占用客户端内存。有三个地方可进行配置:
 在 HBase 的 conf 配置文件中进行配置 hbase.client.scanner.caching;
 通过调用 HTable.setScannerCaching(int scannerCaching) 进行配置;
 通过调用 Scan.setCaching(int caching) 进行配置。三者的优先级越来越高。

RegionServer 的请求处理 IO 线程数
较少的 IO 线程适用于处理单次请求内存消耗较高的 Big Put 场景 (大容量单次 Put 或设置了较大 cache 的 Scan,均属于 Big Put) 或 ReigonServer 的内存比较紧张的场景。较多的 IO 线程,适用于单次请求内存消耗低,TPS 要求 (每秒事务处理量 (TransactionPerSecond)) 非常高的场景。设置该值的时候,以监控内存为主要参考。在 hbase-site.xml 配置文件中配置项为 hbase.regionserver.handler.count。

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 过多影响读性能。

HBase 的单个 Region 大小建议设置大一些,推荐 2G,RegionServer 处理少量的大 Region 比大量的小 Region 更快。对于不重要的数据,在创建表时将其放在单独的列族内,并且设置其列族备份数为 2(默认是这样既保证了双备份,又可以节约空间,提高写性能,代价是高可用性比备份数为 3 的稍差,且读性能不如默认备份数的时候。


-------------------------------
参考来源:


HBase入门简介