(官方文档整理)

系统级调优

1.保证充足的RAM

2.64位的操作系统

3.Linux的swappiness设置为0 :

sysctl vm.swappiness=10

vim /etc/sysctl.conf 加上 vm.swappiness=0

网络级调优

当集群的扩容的时候,应该同时注意交换机的硬件资源也能够跟上。

Java GC 调优

Long GC pauses 由GC导致的长时间的进程停滞,时间过长会导致Region Server和Zookeeper的连接断掉,引发异常。所以应该对GC进行优化,避免这种情况。

有两种典型的场景会造成Long GC,第一个是hbase-env.sh 中的CMSInitiatingOccupancyFraction 参数的值,这个值越小,引发的GC越多。第二个是MSLAB功能(在hbase-site.sh中可配),这项功能本来是为了提升GC的效率,但是在极端情况,当有成千上万的region以及很多的列簇的时候,过多的MSLAB实例(每一个memstore对应一个MSLAB)会造成OOM异常,这种情况下需要禁用MSLAB,或者减小MSLAB chunksize的大小(hbase-site中配置),或者减少每个region server的region数目。

HBase 配置文件调优(略,一般使用Ambari给出的推荐值)

表 schema 设计调优

Schema的设计非常重要,直接影响了HBase日常使用的性能。

1.关于Table的设计实践

  • 使每一个region的大小在10到50GB之间
  • 不要使每一个单元的值超过10MB,如果使用MOB存储,不要超过50MB,如果超过了应该把数据存在HDFS中,HBase存储对应地址
  • 一个典型的HBase表是1到3个列簇(HBase目前对超过3个以上的列簇不能高效处理,所以应该强制限制列簇在3个以下),不要把HBase表设计成RDBMS
  • 一个1到2个列簇的表的region数目在50到100之间,记住一个region是一个列簇的一段连续区间
  • 保持列簇名字尽量的短,因为每一个值都会保存列簇的名字,所以不要像RDBMS那样给列簇命名
  • 如果你存储基于时间的硬件数据或者是日志数据,并且rowkey是基于设备id或服务id 加上时间,你可以在结尾加上固定的表达式来避免某些保存老数据的region发生额外的重写

2.Rowkey的设计实践

  • Hotspotting 现象

    HBase中的所有行都是按照RowKey的字典序排序的。这种设计本意是为了优化scan操作,将相关的行存在一起读写。但是不好的设计会造成Hotspotting的现象。Hotspotting现象即大量的客户端读写及其他操作请求被打到了集群中某一个节点上,这些请求耗费了该节点机器的所有资源来处理那一个region,导致性能下降问题及其潜在的这个region不可用的风险。所以需要设计一个良好的数据访问规则来保证集群的充分利用。

    为了避免写数据时候的Hotspotting,在设计rowkey的时候,只有在必要的时候才让所有的rowkey放在同一个region中,一般在大表中,rowkey是被写到集群中的不同的region中去的。下面是一些避免Hotspotting现象的方法,这些方法有利有弊:

    1. Salting salting是一个很简单的处理措施,就是在rowkey的前面加上数据,一般是加上随机前缀。这样能够打乱rowkey的排序。前缀的随机范围大小决定了划分数据的regions数量。这种方法适用于当有少量的常用的rowkey,但是要频繁的存储这些rowkey的值的情况。比如说,有4个这样的rowkey: foo001,foo002,foo003,foo004。直接存的话,这4个rowkey都会存到同一个region当中去,现在我们想把这4个rowkey分散到不同的region中。我们在创建表的时候将该表进行region预分割:create 'sp_test','f',SPLITS => ['a','b','c','d'],那么这张表按字典序被分成了5个部分。给rowkey随机加上前缀之后: b-foo001,a-foo002,c-foo003,d-foo004,那么这4个rowkey就会存到不同的region当中去,也就是相当于吞吐量比原来大了4倍。之后所有过来的rowkey都给它加上一个随机的前缀。这种方案的结果是给rowkey加上了随机的前缀,所以读的时候会有点麻烦。
    2. Reversing the key 如果rowkey是一串固定长度的字符串或者数字的话,那么先将rowkey的串进行倒转,这样频繁变化的末尾字串移到前面来了。这样有利于rowkey的随机分配,但是会增加对rowkey排序的消耗。

      总的原则就是记住HBase的表会先按照rowkey的字典序进行排序,然后对rowkey进行分段来划分region,我们可以对rowkey字串进行一些预处理,来避免rowkey全部集中到了某几个region中而造成性能问题。
  • 单调递增的rowkey/时间序列数据

    在一张很大的表中,单调递增的rowkey是有问题的,因为这样会发生数据在某个region的堆积,以及旧region间的数据迁移的现象。如果要使用时间序列数据的话,可以参考OpenTSDB的做法,将rowkey设计成 [metric_type][event_timestamp] 这样的格式,metric_type的类别有几十到几百种。这样就能打散rowkey了。
  • 使用较短的column family ,column qualifier的命名,保证使用的前提下尽可能减少rowkey的长度
  • 选择合适的value类型,在region中存储的都是字节数组,不同的value类型会有不用字节数组长度,比如用long存储的数字串比用string存储的数字串有更小的字节数组。
  • rowkey和region splits 一般是开启自动region splitting,让region server自动对region进行分割,但是如果表一开始的数据量就很大的话,在建表的时候,一般会对表进行预分割,对表进行预分割的时候需要事先要对表数据的rowkey有个大致的了解。比如有一个表rowkey的取值范围为("0000000000000000" to "ffffffffffffffff"),将这个范围分割成10个region。这样的问题在于,所有的rowkey都会落到前两个和最后一个region。对照asc码表,可以找出原因,‘0’的asc值为48,’f’的asc值为102,asc码值58到96为大写字母和一些符号,而这些都是我们的rowkey中不会出现的字符(我们的rowkey为[0-9]和[a-f]),中间的region绝对不会被用到。所以在对表进行预分割的时候应该保证所有的region都能被rowkey平均使用到。

3.Bloom Filter的使用

布隆过滤器默认是开启的,有三种级别,NONE、ROW、ROWCOL,ROW是默认的级别。布隆过滤器是为了能够更快的找到某一行或者某一行中的某个列簇,一般ROW级别的布隆过滤器能满足大部分需求,但是有时候你需要使用ROWCOL级别的布隆过滤器,比如说当有大量列簇的Put操作的时候,但是使用的时候需要权衡,ROWCOL级别的布隆过滤器占用更多的存储空间。当有大量删除操作的时候,不适合使用布隆过滤器。

存储Medium-sized Objects (MOB)

数据有很多种形式,也有很多种大小,比如说二进制的图片以及文档数据是很常见的应用场景。一般情况下,HBase是不擅长处理100KB以上大小的数据的。

HBase的MOBs功能为这样的应用场景提供了解决方案。使用非常简单,只需要将特定的列簇指定为存储MOB的模式即可。客户端的代码不需要做任何的改动。

  • 指定某列存储MOB

    hbase> create 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400}

    hbase> alter 't1', {NAME => 'f1', IS_MOB => true, MOB_THRESHOLD => 102400}

    HColumnDescriptor hcd = new HColumnDescriptor(“f”);

    hcd.setMobEnabled(true);

    hcd.setMobThreshold(102400L);

MOB_THRESHOLD MOB的阈值,大于这个值的存储对象视为MOB对象,默认大小为100KB.

  • 测试MOB存储的性能

    可以使用系统提供的类来测试HBase的MOB性能:

    hbase hbase org.apache.hadoop.hbase.IntegrationTestIngestWithMOB

    -threshold 1024

    -minMobDataSize 512

    -maxMobDataSize 5120
  • MOB缓存调优

    MOB file在regionserver中使用了读缓存机制,为了使读MOB性能更好,有时候需要对相关参数进行一些手动配置。例如:

    hbase.mob.file.cache.size 被缓存的文件句柄,默认为1000

    hbase.mob.cache.evict.period 缓存的失效时间,默认为3600秒

    hbase.mob.cache.evict.remain.ratio 一个比例,当缓存句柄达到最大值时,被保留的缓存比例(0.0-1.0)
  • 手动进行compact

    有时候需要手动对MOB存储进行campact来清理小文件,保证性能

    hbase> compact 't1', 'c1’, ‘MOB’

    hbase> major_compact 't1', 'c1’, ‘MOB’
05-04 07:10