`
flyingdutchman
  • 浏览: 353195 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

《Hbase权威指南》深入学习hbase:性能调优概览

阅读更多
        在本节里,开始学习HBase的性能调优的思想及相关的参数设置。
        JVM垃圾收集器调优
        HBase是一个的Hadoop的数据库,给用户提供实时的读写请求。在生产环境中,Region Servers都会配置比较大的JVM堆,Javer们都知道,大多数的垃圾收集器(CMS除外)在收集垃圾时都会暂停其他所有的工作线程(即发生“Stop The World”),由于堆特别大(《Hbase权威指南》中指出,Region Servers的堆不要大于12G),那么即使使用了多线程的并行垃圾收集器,也会造成“长”时间的GC时间。在实时系统中暂停客户端线程一段比较(相对的)“长”的时间,会给客户非常不好的用户体验。
        通过相关的虚拟机参数调整,使HBase运行的更高效,给用户更好的体验。
        默认情况下,JRE并不能给Region Servers提供更好的性能支持,特别是对于那些“写”操作比较繁重的节点,在数据的时候发生Full GC,从而使JVM“假死”相当长的一段时间,这有可能使Zoonkeeper认为该节点“死”了,然后将该节点从“活着”的Region servers队列中删除。
        早前我们已经讨论过《HotSpot JVM虚拟机:垃圾收集算法、垃圾收集器及其应用》(详见http://flyingdutchman.iteye.com/blog/1856846),ParNew + CMS垃圾收集器的组合是“用户响应优先”首选的Hotspot JVM垃圾收集器的组合,其中ParNew是多线程的并行的垃圾收集器,CMS时多线程的并发的不会暂停工作线程的垃圾收集器。
        在当前使用的所有的上用的JVM都使用的是分代的垃圾收集算法,给新生代设置128M-512M大小是合适的,比如将之设置为:
           -XX:NewSize=256M -XX:MaxNewSize=256M,或-Xmn256M
这样以你新生代的Minor GC的JVM暂停时间大致为20ms-40ms,这个10ms级别的暂停时间是可以接受的。将Region Servers的堆大小设置为比如8G大小:
           -Xmx8G -Xms8g
新生代和老年代的垃圾收集器设置为:
           -XX:+UseParNewGC -XX:UseConcMarkSweepGC
老年代的垃圾收集器是并发的,何为“并发”?就是垃圾收集器线程和工作线程同时工作,而不会暂停工作线程直到垃圾收集器线程工作完毕才继续执行。另外CMS是基于“标记-清理”算法的,每次触发CMS执行,都可能会生成“内存碎片”,接着我们对CMS设置两外两个参数:
           -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=15
参数-XX:+UseCMSCompactAtFullCollection意味着每次垃圾收集后再执行一次内存压缩操作来清除产生的内存碎片,而-XX:CMSFullGCsBeforeCompaction=15参数意味着每15次CMS垃圾收集后才进行一次老年代的内存碎片压缩整理。接着我们可能想知道,有没有参数来控制老年代的垃圾收集呢?答案事是无额定的,这个参数就是-XX:CMSInitiatingOccupanyFraction,该参数的默认值是68,意思就是当老年代中的所有对象的达到老年代总大小的68%时触发老年代的垃圾回收操作,可以根据实际的应用来调整该参数的大小。
        综上所述可以给Region Servers的虚拟机参数设置为:
                export HBASE_REGIONSERVER_OPTS="-Xms8g -Xmx8g -Xmn256m
                                   -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
                                   -XX:+UseCMSCompactAtFullCollection
                                   -XX:CMSFullGCsBeforeCompaction=15
                                   -XX:CMSInitiatingOccupanyFraction=70"


        文件压缩
        HBase可以激活一些压缩算法,提供列族级别的文件压缩,因为HBase的表是按列族来存储其数据的。除非有确定的需要(如保存图片),否则HBase要求使用压缩算法来压缩要保存的数据,这个会给HBase带来整体的性能提升。
        下面是google在2005年发布的几个常用的压缩算法的测试结果:

        在Snappy压缩算法在2011年在Hadoop中应用之前,LZO算法是在Hadoop ecosystem中首选的压缩算法,虽然LZO并没最好的压缩率。
        从上图中我们可以看出:
        1)、GZIP的压缩率最高,是CPU密集型的算法,对CPU的消耗比其他算法要多,压缩和解压速度也慢
        2)、LZO的压缩率居中,比GZIP低一些,但是压缩和解压速度明显要比GZIP快很多,特别解压速度快的更多;
        3)、Snappy(Zippy)的压缩率最低,而压缩和解压速度要稍微比LZO要快一些。
Snappy是由google用C++开发的基于BSD License的算法,已经被集成到HBase 0.92中了,之前的版本需要用户动手编译安装。现在该算法是Hadoop ecosystem的首先压缩算法。选择Snappy压缩算法,用户需要在所有的Region Servers上安装Snappy的原生库,以提供更好的压缩性能,毕竟原生的要交java非原生的要好的不是一星半点儿。
        用户可以通过hbase-site.xml配置文件来配置压缩算法,如下:
                <property>
                    <name>hbase.regionserver.codecs</name>
                    <value>snappy</value>
                </property>

        优化分片(Splits)和压缩合并(Compactions)
        虽然HBase内置的机制已经提供了可以预期的比合理的默认的性能,但是,可以通过调整来取得更好的性能。
        管理分片(splits):
        HBase会在regions的大小达到配置给region的最大值时,这样的region会自动被分成2个大小相等的regions,这是HBase默认的操作行为,在大多情况下自动分片是也是合适的。
        但是,在某些时候,这会引起“分片/合并风暴(split/compaction storm)”:当你将HBase表的最大的size配置成相同的大小时,并且在差不多相同时被自动执行分片操作,会引起大量的合并操作以重写新的分片region。
        我们可以关闭自动分片和Major compaction,使用手工调用分片操作和Major 合并操作。可以给所有regions设置一个全局的参数hbase.hregion.max.filesize作用于整个集群,也可以在定义表时设置每个一个表设置一个region的最大值100G。
        Region 托管(splits):
        在侦测到在集群中有热点Region Servers时,手动将热点Region服务器上的hot region移动到其他不热的Region Servers。
        预分区regions:
        在向HBase中大量导入数据时,可以先通过估算预先生成N个regions,在数据导入时减少自动分片的此时,使用最少的时间将全部数据全部导入HBase数据库。
        有两种方式来对预分区做预分区:
        1)、使用HBaseAdmin默认的策略:
              byte[] startKey = ...;   	// your lowest keuy
              byte[] endKey = ...;   		// your highest key
              int numberOfRegions = ...;	// # of regions to create
              admin.createTable(table, startKey, endKey, numberOfRegions);
        

        2)、用户自己动手写方法来做预分区:
              public static boolean createTable(HBaseAdmin admin, HTableDescriptor
                                   table, byte[][] splits)throws IOException {  
                   try {  
                       admin.createTable(table, splits);  
                       return true;  
                   } catch (TableExistsException e) {  
                        System.err.println("Error: " + e); 
                        return false;  
                   }  
              }  
   
              public static byte[][] getHexSplits(String startKey, String endKey,
                                                  int numRegions) {  
                   byte[][] splits = new byte[numRegions-1][];  
                   BigInteger lowestKey = new BigInteger(startKey, 16);  
                   BigInteger highestKey = new BigInteger(endKey, 16);  
                   BigInteger range = highestKey.subtract(lowestKey);  
                   BigInteger regionIncrement =  
                                    range.divide(BigInteger.valueOf(numRegions));  
                   lowestKey = lowestKey.add(regionIncrement);  
                   for(int i=0; i < numRegions-1;i++) {  
                       BigInteger key =  
                   lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i)));  
                       byte[] b = String.format("%016x", key).getBytes();  
                       splits[i] = b;  
                   }  
                   return splits;  
              }  
        


        负载均衡:
        HBase的Master内置有一项功能,叫做均衡器blancer。默认情况下,每五分钟运行一次blancer,可以由参数hbase.blanceer.period配置,一旦开始运行,它会试图让每个Region Server上负载相同数量的regions。如果Region Servers上的regions不均衡了,balancer会生成一个安排计划,决定将哪些regions安排到其他Region Servers上。
       balancer有一个决定其最大执行时间的上限,有配置参数hbase.balancer.max.balancing决定,默认是hbase.blanceer.period配置参数的值的一半即2分30秒。     
       用户可以通过命令行(调用命令balance_switch)或API的方法balanceSwitch()关闭或激活balancer功能。
       balancer有一个缺点,就是它只能是使Region Servers上托管的regions数量保持大体均衡,但是不能避免hot Region Servers的产生。要避免在集群中出现hot Region Servers,可以通过API(move())或命令行将热点服务器上的hot regions移动到“冷点”Region Servers上。

       Merging Regions:
       用户可以手动merge那些下线的regions,命令行命令:
                $ ./bin/hbase org.apache.hadoop.hbase.util.merge,table_name,region1 region2      
       
       Client API:最佳实践
       在你在Java client使用API读取数据时,可以许多优化项参数以获得更好的性能,来下面是一些列这样的参数优化操作:
       关闭auto-flush功能:
       默认情况下,HBase的自动刷新功能是处于激活状态的。则样每一个单个的Put都会自动调用一次RPC向server发送一次请求,为性能计,可以关闭自动刷新功能(setAutoFlush(false)),这样会客户端的write buffer已“满”或客户端强制flushComits()刷新再或者调用HTable的close()时才调用RPC一次把多个Put操作发送给服务器。
       使用scanner的缓存功能:
       默认情况下,scanner会只处理一条记录,可以给Scan通过setCaching()设置一个大于1的参数,比如说200,这就意味着每次向客户端传送200条符合条件的数据,这些数据会在客户端和服务器两端被缓存到内存中,cache缓存的数量要权衡考虑,并不是越大越好。

       限制scan返回的列族或列:
       值返回客户端真正需要的最少的数据,可以避免不必要的网络带宽和I/O。
  
       关闭ResultScanners:
       每次遍历完Scan的返回结果集后,都不要忘了关闭ResultScanner对象,否则会引发问题。
  
       使用Block cache:
       Scan可以通过setCacheBlocks(true)方法在Region Server端使用 block cache。但是在MapReduce job中使用Scan是是出于禁用状态的,对于经常要查询的数据,建议打开此项功能设置。

       关闭WAL
       在Put操作保存数据时,可以考虑关闭WAL的功能——调用writeToWAL(false),这意味着在写数据时不会讲数据先写到WAL日志文件,直接写入memstore,这可以提高一些性能。但是者会带来一些副作用,那就是当Region Server出问题时,没有写log的数据会丢失,这在保存重要数据时会带来很大的危险,只有在保存不南无重要的数据时才考虑这样做。
       通常情况下建议还是不要关闭此项设置。

      
       参数配置
       Decrease Zookeeper timout:
       在默认情况下,Region servers每三分钟向Zookeeper发送一次“心跳”,来告ZK自己还“活着”,这意味着如果一个服务器向Zookeeper发送心跳的时间超过3分钟,那么zookeeper就会任务该节点已经“死了”,而不管这个节点是否怎的creash,或则由于GC执行时间太长。
       可以通过调整zookeeper.session.tomeout的值来调整这个发送心跳的时间的周期。但是在调整该参数之前,要确保JVM GC在控制之下,先确保不会是因为JVM的heap设置的太大而引起长时间的GC垃圾回收造成工作线程长时间被暂停而造成心跳时间过期。如果是由于JVM参数设置不但股引起的,那么一方面可以调优JVM是暂停时间尽可能地短,另一方面可以适当的调大该数值。
      
       增大Region Server的线程连接数:
       hbase.regionserver.handler.count参数用来配置每个Region Server允许的最大的客户线程响应数,默认为10。这是一个比较低的连接数,适用于内存紧张和单次请求要耗费大量内存的场景,否则应该更具实际情况将之调大。

      
       使用数据压缩:
       在大多数的使用场景中,都应该使用数据压缩,Snappy算法是首选,LZO算法次之。

       增大region size:
       默认情况下region的大小被配置为256M,在当前,这是想的有些小了,应该增大其size,如1G或2G。可以通过调整hbase.hregion.max.filesize来改变region大小。

       调整block cache的大小:
       默认情况下,blockcache占Heap堆的20%,可以通过perf.hfile.block.cache.size调整其大小,该值直接影响读性能
       在读多写少的情况下,可以适当的调大该值;如果读写较均衡,0.3左右。设置这个值的时候,你同时要参考 hbase.regionserver.global.memstore.upperLimit ,该值是memstore占heap的最大百分比,两个参数一个影响读,一个影响写。如果两值加起来超过80-90%,会有OOM的风险,谨慎设置此项。
  • 大小: 33.6 KB
分享到:
评论
2 楼 jd2bs 2013-11-05  
-XX:CMSInitiatingOccupancyFraction=70"

是博主写错了
1 楼 wubo2qml 2013-11-04  
很感谢博主的文章,文章中有个属性的单词是不是写错了?
-XX:CMSInitiatingOccupanyFraction=70"
应该是:
-XX:CMSInitiatingOccupancyFraction=70"

相关推荐

Global site tag (gtag.js) - Google Analytics