带你快速上手HBase
随着大数据的越来越普及,HBase也变得越来越流行。使用HBase并不困难,但是如何用好HBase,这确是一个难点。为了合理地使用HBase,尽可能发挥HBase的功能,我们需要根据不同的场景对HBase进行不同地优化以最大程度上提升系统的性能。本文重点介绍列族设计有关的优化。我们先来了解下HBase列族具有哪些属性配置。
列族属性配置

版本数量(VERSIONS)
每个列族可以单独设置行版本数,默认是3。这个设置很重要,因为HBase是不会去覆盖一个值的,它只会在后面追加写,用时间戳(版本号)来区分,过早的版本会在执行 Major Compaction
时删除。这个版本的值可以根据具体的场景来增加或减少。
不推荐将版本最大值设置成一个很高的水平,除非老数据对你也非常重要。过多的版本,会导致存储文件变大,以至于影响查询效率。
最小版本数(MIN_VERSIONS )
每个列族可以设置最小版本数,最小版本数缺省值是0,表示禁用该特性。最小版本数参数和存活时间是一起使用的,允许配置“ 如保存最后T秒有价值的数据,最多N个版本,但最少M个版本 ”(M是最小版本,M HBase支持配置版本数据的存活时间(TTL),TTL设置了一个基于时间戳的临界值,HBase会自动检查TTL值是否达到上限,如果TTL达到上限,则该数据会在 Major Compaction过程 中被删除。 hbase默认的块大小是64kb,不同于HDFS默认64MB的块大小。原因是hbase需要支持随机访问,一旦找到了行键所在的块,接下来就会定位对应的单元格。使用64kb的块扫描的速度显然优于64MB大小的块。 对于不同的业务数据,块大小的合理设置对读写性能有很大的影响。如果业务请求以Get请求为主,可以考虑将块大小设置较小;如果以Scan请求为主,可以将块大小调大;默认的64K块大小是在Scan和Get之间取得的一个平衡。 注意: 默认块大小适用于多种数据使用模式,调整块大小是比较高级的操作。配置错误将对性能产生负面影响。因此建议在调整之后进行测试,根据测试结果决定是否可以线上使用。 默认是true。缓存是内存存储,hbase使用块缓存将最近使用的块加载到内存中。块缓存会根据 最近最久未使用(LRU) ”的规则删除数据块。 如果你的使用场景是经常顺序访问或者很少被访问,可以关闭列族的缓存。列族缓存默认是打开的。 HBase可以选择一个列族赋予更高的优先级缓存,激进缓存(表示优先级更高), 这个参数通常适合较小的列族。 HBase在写入数据块到HDFS之前会首先对数据进行压缩,再落盘,从而减少磁盘空间使用量。而在读数据的时候首先从HDFS中加载出block块之后进行解压缩,然后再缓存到BlockCache,最后返回给用户。 使用压缩其实就是 使用CPU资源换取磁盘空间资源 。 HBase支持三种压缩方式: LZO 、 Snappy 和 GZIP 。 默认为NONE,不适用压缩, 其中: GZIP的压缩率最高,但是其实CPU密集型的,对CPU的消耗比其他算法要多,压缩和解压速度也慢; LZO的压缩率居中,比GZIP要低一些,但是压缩和解压速度明显要比GZIP快很多,其中解压速度快的更多; Snappy的压缩率最低,而压缩和解压速度要稍微比LZO要快一些。 综合来看,Snappy的压缩率最低,但是编解码速率最高,对CPU的消耗也最小,目前一般建议使用Snappy。 HBase提供了跨级群同步的功能,本地集群的数据更新可以及时同步到其他集群。复制范围(replication scope)的参数默认为0,表示复制功能处于关闭状态。 在默认情况下,HBase表在刚刚被创建的时候,只有1个分区(Region),当一个Region的大小达到阈值(通过 HBase提供了预分区的功能,用户可以在创建表的时候对表按照一定的规则提前进行分区。这样是进行HBase数据读写的时候,会按照Region分区情况,在集群内做数据的负载均衡。 常用分区方法: BloomFilter主要用来过滤不存在待检索RowKey或者Row-Col的HFile文件,避免无用的IO操作。它会告诉你在这个HFile文件中是否可能存在待检索的KV,如果不存在,就可以不用消耗IO打开文件进行seek。 通过设置BloomFilter可以提升随机读写的性能。 BloomFilter是一个列族级别的配置属性,如果在表中设置了BloomFilter,那么HBase会在生成StoreFile时包含一份BloomFilter结构的数据,称其为 BloomFilter取值有两个, 如果业务大多数随机查询时仅仅使用row作为查询条件,BloomFilter一定要设置为row; 如果大多数随机查询使用row+cf作为查询条件,BloomFilter需要设置为rowcol; 如果不确定查询类型,建议设置为row。 不要在一张表中定义太多的列族。目前HBase并不能很好的处理2~3以上的列族, 当一个列族操作大量数据的时候会引发一个flush,它邻近的列族也会因关联效应被触发flush,尽管它没有操作多少数据。compaction操作是根据一个列族下的全部文件的数量触发的,而不是根据文件大小触发的。 当很多的列族在flush和compaction时,会造成很多没用的IO负载。 尽量在模式中只针对一个列族进行操作。将使用率相近的列归为一个列族,这样每次访问就只用访问一个列族,既能提升查询效率,也能保持尽可能少的访问不同的磁盘文件。 如果一个表存在多个列族,要注意列族之间基数(如行数)相差不要太大。例如列族A有100万行,列族B有10亿行,按照RowKey切分后,列族A可能被分散到很多很多Region(及RegionServer),这导致扫描列族A十分低效。 列族名和列名越短越好,冗长的名字虽然可读性好,但是更短的名字在HBase中更好。 一个具体的值由存储该值的行键、对应的列( 根据HBase列族的这些属性配置,结合我们的使用场景,HBase列族可以进行如下优化: 列族不宜过多,将相关性很强的key-value都放在同一个列族下,; 尽量最小化行键和列族的大小; 提前预估数据量,再根据Rowkey规则,提前规划好Region分区,在创建表的时候进行预分区; 在业务上没有特别要求的情况下,只使用一个版本,即最大版本和最小版本一样,均为1; 根据业务需求合理设置好失效时间(存储的时间越短越好); 根据查询条件,设置合理的BloomFilter配置; 合理设计RowKey,可以参考《 一篇文章带你快速搞懂HBase RowKey设计 》。 存活时间(TTL)
数据块大小(BLOCKSIZE )
块缓存(BLOCKCACHE)
激进缓存的配置(IN_MEMORY)
IN_MEMORY
默认是false。如果设置为true,hbase会尝试将整个列族保存在内存中,只有在需要保存是才会持久化写入磁盘。但是在运行时hbase会尝试将整张表加载到内存里。 压缩(COMPRESSION)
压缩算法
压缩比率
压缩速度
解压速度
GZIP
13.4%
21 MB/s
118 MB/s
LZO
20.5%
135 MB/s
410 MB/s
Snappy
22.2%
172 MB/s
409 MB/s
复制范围(REPLICATION_SCOPE )
预分区(SPLITS )
hbase.hregion.max.filesize
参数控制),Region会进行split,分裂成2个Region。但是在进行split的时候,会消耗大量的资源,频繁的split会对HBase的性能造成巨大的影响。 create 'table','cf', SPLITS => ['1', '2', '3', '4', '5', '6', '7', '8', '9']
create 'table','cf', { NUMREGIONS => 8 , SPLITALGO => 'UniformSplit' }
create 'table','cf', { NUMREGIONS => 10, SPLITALGO => 'HexStringSplit' }
BLOOMFILTER
MetaBlock
和 DataBlock
(真实KeyValue数据)一起由LRUBlockCache维护。所以开启BloomFilter会有一定的存储即内存Cache的开销。 row
和 rowcol
,需要根据业务来确定具体使用哪种。
列族设置
列族数量
flush
和 compaction
操作是针对一个Region的。 列族的基数
列族名、列名长度
列族:列
)以及该值的时间戳决定。HBase中索引是为了加速随机访问的速度,索引的创建是基于“ 行键+列族:列+时间戳+值
”的,如果行键和列族的大小过大,甚至超过值本身的大小,那么将会增加索引的大小。并且在HBase中数据记录往往非常之多,重复的行键、列将不但使索引的大小过大,也将加重系统的负担 总结
好文推荐: