HBase笔记4(调优)

Master/Region Server调优

  JVM调优

    默认的RegionServer内存是1G,而Memstore默认占40%,即400M,实在是太小了,可以通过HBASE_HEAPSIZE参数修改(CDH界面也可以修改)

    1)通用调整,同时调整MASTER Region Server

    vim $HBASE_HOME/conf/hbase-env.sh

      export HBASE_HEAPSIZE=8G   ===> 会生效HBASE的所有实例,MASTER和Region Server

    2)Permsize调整

    hbase-env.sh中含有配置如下:

    HBase笔记4(调优)

    意思为配置MAster Region Server的永久对象区(Permanent Generation,这个区域在非堆内存里面)占用128M的内存,这个配置在JDK7下运行,JDK8无需设置,设置也无用

    3)设置JVM使用的最大内存

    export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -Xms4g -Xmx4g"   设置MASTER的JVM内存为4G  可以设置为其他大小

    export HBASE_REGIONSERVER_OPTS="$HBASE_MASTER_OPTS -Xms8g -Xmx8g"  设置Region server内存为8G

    注:系统需要至少10%内存进行必要操作

      如何根据机器内存大小设置合适的Master或Region Server内存大小

          官方参考:16G内存机器。同时包含MR ,Region Server ,DataNode服务

        建议配置: 2G 系统

             8G MR(1G=6*map+2*reduce)

               4G    HBase RegionServer

              1G    TaskTracker

              1G    DataNode

        若同时运行MR任务,Region Server将是除MR以外使用内存最大的服务,若无MR,Region Server可以调到大概一半的服务器内存

    4)Full GC问题

    JVM越大,Full GC时间越长,Full GC时,JVM会停止响应任何请求,所以这种暂停叫Stop-The-World(STW),这会导致Region Server不响应Zookeeper的心跳,让Zookeeper误认自己宕机

    ,为防止脑裂,Region Server会叫停自己(自杀)

      GC回收策略优化

        JVM提供4种GC回收器:串行回收器   并行回收器(针对年轻代优化,JDK8默认)   并发回收器(CMS,针对年老带)    G1GC回收器(针对大内存32G上优化)

            组合方案1:并行GC+CMS

          年轻代使用并行回收器   年老代使用CMS

          $HBASE_HOME/conf/hbase-env.sh 中 HBASE_REGIONSERVER_OPTS内加入  -XX:+UseParNewGC  -XX:+UseConcMarkSweepGC

             -XX:+UseParNewGC   并行GC回收器

              -XX:+UseConcMarkSweepGC  CMS并发回收器

       组合方案2:G1GC

          内存小于4G,直接使用方案1

          内存大于32G且JDK版本大于1.7,可考虑G1GC方案

          引入原因:如下2中情况还是会触发Full GC

            A.  CMS工作时,一些对象从年轻代移动到年老代,但是年老代空间不足,此时只能触发Full Gc

            B.  当回收掉的内存空间太碎太细小,导致新加入年老代的对象放不进去,只能触发Full GC来整理空间

          G1GC策略通过把堆内存划分为多个Region,然后对各个Region单独进行GC,这样整体的Full GC可以被最大限度避免,该策略可以指定MaxGCPauseMillis参数来控制一旦发生  

          Full GC时的最大暂停时间,避免长时间暂停造成Region Server自杀,设置方式为 HBASE_REGIONSERVER_OPTS中添加参数 -XX:MaxGCPauseMillis=100

          调试时加上调试参数: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy

            参考参数:  32G heap时   -XX:G1NewSizePercent=3

            64G heap时 -XX:G1NewSizePercent=2

            100G+       -XX:G1NewSizePercent=1

            其他参数:

            -XX:+UseG1GC   -XX:MaxGCPauseMillis=100 -XX:+parallelRefProcEnabled -XX:-ResizePLAB -XX:ParallelGCThreads=8+(40-8)(5/8)=28  -XX:G1NewSizePercent=1

      5)memstore专属JVM策略MSLAB

        100G内存使用CMS策略还发生Full GC原因

          A.   同步模式失败

            新生代过快的转化为老生代对象时发现老生代可用空间不够,此时会停止并发收集过程,转为单线程的STW(stop the world)暂停,这回到Full GC过程

            可以设置 -XX:CMSInitiating0ccupancyFraction=N    ,N代表当JVM启动来及回收时堆内存的占用百分比,设置越小,JVM越早启动垃圾回收,一般设置为70

              B. 碎片化造成失败

            memstore 定期刷写成一个HFile,memstore 占用的内存空间就会被回收,但memstore 占用的空间不是连续的且可能很小,就会出现碎片化

            JVM提出了一个TLAB解决方案:当使用TLAB时,每个线程都会分配一个固定大小的内存空间,这样就不会出现特别小的碎片空间,但是会导致内存空间利用率低

            HBASE实现了一个MSLAB方案,继承了TLAB,引入如下概念:

              chunk: 一块内存,大小2M

              RegionServer维护一个全局的MemStoreChunkPool实例,是一个chunk池

              每个Memstore实例里又一个MemStoreLAB实例

              当MemStore接收到keyvalue数据时,先从chunk pool中申请一个chunk,然后放到这个chunk里

              如果这个chunk满了,再申请一个

              memstore因为刷写而释放内存,则按chunk来清空内存

              设置参数:  hbase.hregion.memstore.mslab.enabled=true   打开MSLAB,默认为true

                     hbase.hregion.memstore.mslab.chunksize=2M  设置每个chunk大小,默认2M

                     hbase.hregion.memstore.mslab.max.allocation=256K  能放入chunk的最大单元格大小,默认256K

                     hbase.hregion.memstore.chunkpool.maxsize=0.0  在整个memstore可以占用的堆内存中,chunkpool可以占用的比例(0.0~1.0),默认0.0

                    hbase.hregion.memstore.chunkpool.initialsize=0.0. regionserver启动时可以预分配一些空的chunk出来到chunk pool里面待使用,该值代表了预分配chunk占总chunkpoll的比例

    Region性能优化

      Region的自动拆分

        1)按照固定大小拆分

        0.94版本的HBase只有一种拆分策略,按照固定大小拆分,参数 hbase.hregion.max.filesize.region=10G  ,当region超过10G则HBase拆分成2个Region

        2)限制不断增长的文件尺寸策略

        文件的尺寸限制是动态的,依赖以下公式计算: Math.min(tableRegionsCount^3*initialSize,defaultRegionMaxFileSize)

          tableRegionCount : 表在region server上拥有的region数量总和

          initialize: 若定义了 hbase.increasing.policy.initial.size,则使用这个数值,否是就用memstore 刷写的2倍,即hbase.hregion.memstore.flush.size*2

          defaultRegionMaxFileSize: region得最大大小,即hbase.hregion.max.filesize

          math.min 取这2个数值得最小值

        3)自定义拆分点(依据行键前缀)

          保证拥有相同前缀得rowkey不会被拆分到2个不同得region里面 ,涉及参数keyPrefixRegionSplitPolicy.prefix_length   前缀得长度

          该策略会依据前缀长度参数截取rowkey最为分组依据,同一个组得数据不会被划分到不同region上

        4)依据行键得分隔符(也是根据行键前缀进行切分)

          这个策略需要表定义以下属性:DelimitedKeyPrefixRegionSplitPolicy.delimiter 前缀分隔符

          例: 定义分隔符 _, host1_001得前缀为host1

        5)访问频率拆分(热点拆分)

          涉及参数: hbase.busy.policy.blockRequests:请求阻塞率,即请求被阻塞得严重程度,取值0.0~1.0,默认0.2,20%请求被阻塞

               hbase.busy.policy.minAge:拆分得最小年龄,防止在判断是否拆分时出现短时间得访问频率波峰,结果没必要拆分Region被拆

               hbase.busy.policy.aggWindow 计算是否繁忙得时间窗口,单位毫秒,默认5min,用以控制计算频率

          计算Region是否繁忙得计算方法:

              当前时间-上次检测时间=>hbase.busy.policy.aggWindow,则进行如下计算:这段时间被阻塞得请求/这段时间得总请求 = 请求得被阻塞率,如果请求得被阻塞率 > hbase.busy.policy.blockRequests ,则该Region为繁忙

        6)永不拆分策略

      Region的手动拆分

        手动拆分有2种情况,预拆分和强制拆分

        Region的预拆分

          建表时定义拆分点的算法,叫预拆分,使用org.apache.hadoop.hbase.util.RegionSplitter类创建表,并传入拆分点算法就可以在建表同时定义拆分点算法

          ex:hbase org.apache.hadoop.hbase.util.RegionSplitter my_split_table HexStringSplit -c 10 -f mycf

            新建表my_split_table,并根据HexStringSplit拆分点算法预拆分为10个Region,同时建立一个列族mycf

        拆分点算法:

          HexStringSplit    算法参数  n:要拆分的region数量

            把数据从00000000到FFFFFFFF之间的数据长度按照n等分之后,算出每一段的起始rowkey和结束rowkey,以此作为拆分点

          UniformSplit

            起始rowkey是ArrayUtils.EMPTY_BYTE_ARRAY

            结束rowkey是new byte[] {xFF,xFF,xFF,xFF,xFF,xFF,xFF,xFF}

            最后调用Bytes.split把起始行键和结束行键之间长度n等分,然后取每一段的起始和结束作为拆分点

          手动指定拆分点:建表时指定SPLITS参数

            create 'table1','mycf2',SPLITS=>['aaa','bbb']

       Region强制拆分

        ex: split 't1,c,14764.96dd8‘,’999'  把t1,c,14764.96dd8这个region从新的拆分点999处进行拆分

        split方法的调用方式:

          split ‘表名’

          split ‘namespace:tablename’

          split 'regionName' #format: 'tableName,startKey,id'

          split 'tableName','splitKey'

          split 'regionName','splitKey'

       推荐方案

          预拆分导入初始数据。然后使用自动拆分让HBase管理Region

     Region的合并

       通过merge进行合并(冷合并)

        通过使用org.apache.hadoop.hbase.util.Merge类实现

        ex: hbase  org.apache.hadoop.hbase.util.Merge tablename  regionname1 regionname2    (需要先停止Hmaster,Hregionserver)

      热合并

        hbase shell提供了online_merge 来实现热合并,参数是region的hash值

        ex:  merge_region  region1hash值   region2hash值     ====》2个region都需要上线

      HBase笔记4(调优)

        HBase笔记4(调优)

      

    WAL优化

      WAL文件的数量当增长到一定程度时会出现滚动,清除旧日志

        WAL优化参数:hbase.regionserver.maxlogs:  Region种最大WAL文件数量,默认32

                  新版HBase会自动设置,公式

HBase笔记4(调优)

               hbase.regionserver.hlog.blocksize: HDFS块大小,不设定则使用HDFS的设置值

               hbase.regionserver.logroll.multiplier WAL 文件大小因子,默认0.95

               每个WAL文件大小=HDFS块大小*WAL文件大小因子

   BlockCache优化
    一个region server只有一个blockcache 
    HBase笔记4(调优)

    读请求到达HBase之后,先查询Block Cache,如果获取不到就去HFile和Memstore中获取,如果获取到了则在返回数据的同时把Block块缓存到Block Cache中

    Block Cache默认开启,若要某个列族禁止使用Block Cache,执行alter 't1',CONFIGURATION=> {NAME=> 'cf',BLOCKCACHE=>'false'}

    Block Cache实现方案:

       1)LRUBlock Cache (基于JVM heap    近期最少使用算法缩写, 一级缓存)

          LRUBlock Cache的3个区域

          HBase笔记4(调优)

          hfile.block.cache.size.LRUBlockCache  占用内存比例,默认0.4

            设置hfile.block.cache.size时需要注意Memstore+BlockCache内存占用比例不能超过0.8,即80%

            hfile.regionserver.global.memstore.size+hfile.block.cache.size <=0.8

        2)SlabCache (堆外内存尝试方案)

          调用nio的DirectByteBuffers,把堆外内存按照80%,20%比例划分为2个区域: 存放大小约1个blocksize默认值的Block;存放大小约2个blocksize默认值的block

          该方案可用性不大,放弃

        3)Bucket Cache  (二级缓存)

          BucketCache分配了14种区域,存放大小分别为4K,8K,16K,32K,40K,48K,56K,64K,96K,128K,192K,256K,384K,512K的Block

          可以手动配置  hbase.bucketcache.bucket.sizes属性来定义

          Bucket Cache存储可以通过hbase.bucketcache.ioengine进行设置,为堆heap,堆外offheap,文件file

          每个Bucket的大小上限为最大尺寸的Block*4,每种类型的Bucket至少要一个Bucket

          HBase笔记4(调优)

          BucketCache可以自己划分内存空间,自己管理内存空间,所以内存碎片少

          配置项:默认开启

          列族关闭BucketCache:

             alter 'table',CONFIGURATION => {CACHE_DATA_IN_L1=>'true'}

          hbase.bucketcache.ioengine:使用的存储介质 ,可选heap,offheap(默认),file

          hbase.bucketcache.combinedcache.enabled 是否打开组合模式,默认true

          hbase.bucketcache.size    bucketcache所占大小  ,0关闭  0.0~1.0 代表占堆内存百分比  ,大于1,代表实际的大小,单位MB

          hbase.bucketcache.bucket.sizes 定义所有block种类,默认14种

          -XX:MaxDirectMemorySize   JVM启动参数,定义JVM可获取堆外内存的上限,必须比hbase.bucketcache.size大

         4)组合模式

          具体来说:把不同类型的Block分别存放到LRUCache BucketCache中

          合理介质:一级缓存->二级缓存->硬盘     数据从小到大   存储介质由快到慢

              LRUCache使用内存-> BucketCache 使用SSD-> HFile使用机械硬盘

          查看缓存命中率: hbase.regionserver.blockCacheHitRatio 取值范围0.0~1.0

      MemStore优化

        读写中的memstore

          memstore实现的目的是维持数据结构

          开启Block Cache,读取数据先查询Block Cache,Block Cache查询失败后,则查询memstore+HFile数据,由于有些数据还未刷写HFile,

          所以memstore+HFile才是所有数据集合

        memstore的刷写

          memstore的优化核心在于理解memstore的刷写flush,大部分性能问题是写操作被block,无法写入Hbase

          memstore触发刷写机制:

            1. 大小达到刷写阈值 hbase.hregion.memstore.flush.size

              由于刷写是定期检查的,所以无法及时触发阈值刷写,若数据增长太快,提前超出阈值,会触发阻塞机制,此时数据无法写入memstore

                  阻塞机制的阈值=hbase.hregion.memstore.flush.size*hbase.hregion.memstore.block.multiplier

                      =刷写阈值(默认128M)*倍数

              数据到达阻塞阈值,直接触发刷写并阻塞所有写入该store的写请求

            2.  整个Region Server的memstore总和达到阈值

              触发刷写阈值=globalMemstoreLimitLowMarkPercent*globalMemStoreSize

              =全局memstore刷写下限 (百分比0.0~1.0)  *  全局memstore容量

              全局memstore容量=hbase_heapsize(RegionServer占用堆内存大小)*hbase.regionserver.global.memstore.size(默认0.4)

              触发阻塞阈值= globalMemStoreSize

             3. WAL 数量大于maxLogs
              maxLogs计算公式:    
                                                  HBase笔记4(调优)

             4. memstore达到刷写时间间隔

              hbase.regionserver.optionalcacheflushinterval   memstore刷写时间间隔,默认1个小时,设置为0,则关闭自动定时刷写

            5. 手动触发flush

              flush 'table_name'  刷写单个表

              flush ‘region_name’ 刷写单个region

            memstore性能优化主要是防止触发阻塞,避免对业务造成灾难性性后果

         HFile性能优化(合并) compaction

            Hfile文件过多,读取数据寻址就多了,为了防止过多的寻址动作,适当减少碎片文件,需进行合并操作

            合并分为2种操作:

              Minor Compaction: 将多个HFile合并为一个HFile.在这个过程中达到TTL的数据会被移除,但是手动删除的数据不会被移除,触发频率高

              Major Compaction:合并一个store所有的HFile为1个,手动删除的数据会被移除,同时删除单元格内版本超过maxversion版本数据,触发频率低,7天一次,但是消耗的性能较大

            0.96版本后提出一个合并算法 ExploringCompactionPolicy算法

              该算法修改合并文件挑选条件:  该文件 < (所有文件大小总和 - 该文件大小)  * 比例因子

              若果该文件的大小小于最小合并大小(minCompactionSize),则直接进入待合并列表

              最小合并大小: hbase.hstore.compaction.min.size   若没有设置则使用hbase.hregion.memstore.flush.size

              以组合作为计算单元:  被挑选的文件必须通过筛选条件,并且组合内含有文件数必须大于hbase.hstore.compaction.min

                  小于hbase.hstore.compaction.max   (就是选择一个组合内几个文件进行合并)

              FIFOCompactionPolicy

                本质是一种删除策略,最终效果是 : 过期的块被整个删除,没过期的块完全没有操作

                 不能应用的环境: 1)表没有设置TTL,或TTL=forever

                          2) 表设置了MIN_VERSION,并且MIN_VERSION > 0

              DateTiredCompactionPolicy

                配置项:hbase.hstore.compaction.date.tiered.base.window.millis  基本的时间窗口时长,默认6小时,即从现在开始的6个小时内HFile都在同一个时间窗口里面

                    hbase.hstore.compaction.data.tiered.window.per.tier  层次的增长倍数,分层时越老的时间窗口越宽

                    同一个窗口里面的文件如果达到最小合并数量(hbase.hstore.compaction.min)就会进行合并,根据hbase.hstore.compaction.date.tiered.window.policy.(所定义的合并规则来合并),默认ExploringCompactionPolicy

                    hbase.hstore.compaction.date.tiered.max.tier.age.millis  最老的层次时间,当文件老到超出定义的时间,就不进行合并

                    如果一个文件跨时间线的时候,该文件计入下一个时间窗口(更老更长的时间窗口)

              StripeCompactionPolicy   适合读性能

                  每一层文件大概是上一层的10倍

                  合并时会把keyvalue从level 0(L0) 读取出来,然后插到level1 的FILE文件中,level1是根据键位范围(rowkey range)来划分

                HBase笔记4(调优)

                  适用场景: Region很大,Row Key具有统一的格式

              Compaction的吞吐量限制参数

                compaction机制会造成IO突然降低问题

                相关可设置参数:  hbase.regionserver.throughtput.controller  限制的类型对应类名,可选 PressureAwareCompactionThroughtController控制合并相关指标    和    PressureAwareFlushThroughtputController  控制刷写相关指标,默认为PressureAwareCompactionThroughtputController

                        hbase.hstore.blockingStoreFiles  当StoreFile数量达到该值,阻塞刷写动作,默认7

                          该参数设定不当可能造成memstore占用内存数量急剧上升,到达上限,集群就会挂掉,可设置20-50

                        hbase.hstore.compaction.throughtput.lower.bound 合并占用吞吐量下限

                        hbase.hstore.compaction.throughtput.higher.bound 合并占用吞吐量上限

                  合并/刷写吞吐量限制机制:

                      HBase 计算 合并/刷写 占用的吞吐量,当吞吐量过大时会适当休眠

                      hbase.offpeak.start.hour 每天的非高峰起始时间,取值0-23

                      hbase.offpeak.end.hour 每天非高峰结束时间,取值0-23

                      休眠吞吐量的阈值=lowerBound + (upperBound - lowerBound) * pressureRatio

                        lowerBound :

                          hbase.hstore.compaction.throughput.lower.bound 合并占用吞吐量下限 默认10MB/s

                        upperBound:

                          hbase.hstore.compaction.throughtput.higher.bound 合并占用的吞吐量下限 默认20MB/S

                        pressureRatio 压力比  限制合并时,该参数就是合并压力,显示刷写时,该参数就是刷写压力,取值0-1.0

                      压力比越大,HFile堆积的越多,或即将产生越多的HFile

                      压力比分为 : 合并压力  刷写压力

                      合并压力计算:=(storefilecount - minFilesToCompact)/(blockingFileCount - minFilesToCompact)

                        storefilecount  当前storeFile数量

                        minFilesToCompact:单次合并文件数量下限,即hbase.hstore.compaction.min

                        blockingFileCount  = hbase.hstore.blockingStoreFiles

                      刷写压力计算:= globalMemstoreSize/memstoreLowerLimitSize

                        globalMemstoreSize 当前memstore大小

                        memstoreLowerLimitSize  Memstore刷写下限,当全局memstore达到这个内存占用数量时开始刷写

              HBase 合并文件流程:

                1)获取需要合并的Hfile列表

                  获取列表时需要除掉带锁的HFile,锁分为读锁 写锁

                  以下操作会上锁:  用户scan查询,上Region锁 ;Region切分,region先关闭上写锁;Region关闭,写锁;Region导入,写锁

                2)由列表创建StoreFileScanner

                  HRegion 会创建一个Scanner,读取本次要合并的所有StoreFile上的数据

                3)把数据从HFile中读出,并放到tmp目录(临时文件夹)

                  HBase 会在临时目录创建新的HFile,并使用建立的Scanner从旧HFile上读取数据,放入新HFile

                  以下数据不会读取: 数据过期了   带墓碑标记的数据

                4)用合并后的HFile来替换合并前的HFile

              Major compaction:

                  hbase.hregion.majorcompaction       majorcompaction发生的周期,默认7天  ,等于0则为关闭

                  hbase.hregion.majorcompaction.jitter   周期抖动参数  0-1.0,可以让major compaction发生时间更灵活,默认0.5

                  major compaction对系统的压力还是很大,建议关闭自动选择手动触发方式

                

          

          

  

  

        

    

    

  

上一篇:使用Typescript重构axios(二十)——请求取消功能:实现第一种使用方式


下一篇:使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式