HBase优化策略及协处理器

作者: Alukar | 来源:发表于2018-06-20 21:48 被阅读24次

    服务端优化

    什么导致HBase性能下降

    Jvm内存分配与GC回收策略

    HBase运行机制相关的配置分配不合理

    表结构设计及用户使用方式不合理

    HBase数据存储过程

    HBase写入时当memstore达到一定大小会flush到磁盘保存成HFile,当HFile小文件太多回执行compact操作进行合并(compact就是将很多小文件合并成一个大文件的过程。compact分为minor compaction和major compaction)

    当Region的大小达到某一阈值之后,回执行split操作

    当HBase做compact和split操作时需要优化

    常见服务端配置优化

    Jvm设置与GC设置

    hbase-site.xml部分属性配置

    属性简介建议

    hbase.regionserver.handler.countrpc请求的线程数量,默认值是10

    hbase.hregion.max.filesize当region的大小大于设定值后hbase就会开始split建议手动split

    hbase.hregion.majorcompactionmajor compaction的执行周期将值设置成0,在业务低峰手动执行majorcompaction

    hbase.hstore.compaction.min一个store里的storefile总数超过该值,会触发默认的合并操作默认3

    hbase.hstore.compaction.max一次合并最多合并多少个storeFile

    hbase.hstore.blockingStoreFiles一个region中的Store(CoulmnFamily)内有超过多少个storeFile时,则block所有的写请求进行compaction

    hfile.block.cache.sizeregionserver的block cache的内存大小限制在偏向读的业务中可调大该值

    hbase.hregion.memstore.flush.sizememstore超过该值将被flush

    hbase.hregion.memstore.block.multiplier如果memstore的内存大小超过flush.size*multiplier,会阻塞该memstore的写操作建议设置成5,设置太大会有内存溢出的风险

    常用优化策略

    预先分区

    HBase默认创建表的时候会自动创建一个Region分区

    创建表时预先创建一些空的Region,并指定Rowkey的存储范围。这样可以减少Split操作,减少IO操作

    Rowkey优化

    利用HBase默认排序特点,将一起访问的数据放到一起

    防止热点问题,避免使用时序或者单调的递增递减等

    Column优化

    列族的名称和列的描述命令尽量简单

    同一张表的列族不要超过三个

    读写优化

    写优化策略

    同步批量提交(默认)

    异步批量提交 (会提升性能,但可能存在数据丢失,在一些业务中可以采用)

    WAL优化,是否必须开启(默认开启),持久化等级

    读优化策略

    客户端:Scan缓存设置,批量获取

    服务端:BlockCache配置是否合理,HFile是否过多(通过服务端的配置进行设置)

    表结构设计问题

    HBase协处理器

    协处理器简介

    HBase协处理器受BigTable协处理器的启发,为用户提供类库和运行时环境,使得代码能够在HBase RegionServer和Master上处理(使用协处理器需要谨慎,可能会导致性能下降甚至数据丢失)

    协处理分为系统协处理器 and 表协处理器

    系统协处理器:全局加载到RegionServer托管的所有表和Region上(是属于所有的表)

    表协处理器:用户可以指定一张表使用协处理器(只是针对一张表)

    观察者(Observer):类似于关系数据库的触发器

    终端(Endpoint):动态的终端有点像存储过程

    2.实现一个ResionObserver类型的协处理器

    引入pom:

      org.apache.hbase

      hbase-common

      1.2.4

      org.apache.hbase

      hbase-server

      1.2.4

    一个简单demo

    package com.imooc.bigdata.hbase.coprocessor.observer;

    import java.awt.image.ImagingOpException;

    import java.io.IOException;

    import java.util.Arrays;

    import java.util.List;

    import org.apache.hadoop.hbase.Cell;

    import org.apache.hadoop.hbase.CellUtil;

    import org.apache.hadoop.hbase.CoprocessorEnvironment;

    import org.apache.hadoop.hbase.client.Delete;

    import org.apache.hadoop.hbase.client.Durability;

    import org.apache.hadoop.hbase.client.Get;

    import org.apache.hadoop.hbase.client.Put;

    import org.apache.hadoop.hbase.client.Result;

    import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;

    import org.apache.hadoop.hbase.coprocessor.ObserverContext;

    import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;

    import org.apache.hadoop.hbase.regionserver.wal.WALEdit;

    import org.apache.hadoop.hbase.util.Bytes;

    /**

    * Created by xt on 18-6-18.

    */

    public class RegionObserverTest extends BaseRegionObserver {

      private byte[] columnFamily = Bytes.toBytes("cf");

      private byte[] countCol = Bytes.toBytes("countCol");

      private byte[] unDeleteCol = Bytes.toBytes("unDeleteCol");

      private RegionCoprocessorEnvironment environment;

      //regionserver 打开region前执行

      @Override

      public void start(CoprocessorEnvironment e) throws IOException {

        environment = (RegionCoprocessorEnvironment) e;

      }

      //RegionServer关闭region前调用

      @Override

      public void stop(CoprocessorEnvironment e) throws IOException {

      }

      /**

      * 1. cf:countCol 进行累加操作。 每次插入的时候都要与之前的值进行相加

      */

      @Override

      public void prePut(ObserverContext e, Put put, WALEdit edit,

          Durability durability) throws IOException {

        if (put.has(columnFamily, countCol)) {

          //获取old countcol value

          Result rs = e.getEnvironment().getRegion().get(new Get(put.getRow()));

          int oldNum = 0;

          for (Cell cell : rs.rawCells()) {

            if (CellUtil.matchingColumn(cell, columnFamily, countCol)) {

              oldNum = Integer.valueOf(Bytes.toString(CellUtil.cloneValue(cell)));

            }

          }

          //获取new countcol value

          List cells = put.get(columnFamily, countCol);

          int newNum = 0;

          for (Cell cell : cells) {

            if (CellUtil.matchingColumn(cell, columnFamily, countCol)) {

              newNum = Integer.valueOf(Bytes.toString(CellUtil.cloneValue(cell)));

            }

          }

          //sum AND update Put实例

          put.addColumn(columnFamily, countCol, Bytes.toBytes(String.valueOf(oldNum + newNum)));

        }

      }

      /**

      * 2. 不能直接删除unDeleteCol    删除countCol的时候将unDeleteCol一同删除

      */

      @Override

      public void preDelete(ObserverContext e, Delete delete,

          WALEdit edit,

          Durability durability) throws IOException {

        //判断是否操作cf列族

        List cells = delete.getFamilyCellMap().get(columnFamily);

        if (cells == null || cells.size() == 0) {

          return;

        }

        boolean deleteFlag = false;

        for (Cell cell : cells) {

          byte[] qualifier = CellUtil.cloneQualifier(cell);

          if (Arrays.equals(qualifier, unDeleteCol)) {

            throw new IOException("can not delete unDel column");

          }

          if (Arrays.equals(qualifier, countCol)) {

            deleteFlag = true;

          }

        }

        if (deleteFlag) {

          delete.addColumn(columnFamily, unDeleteCol);

        }

      }

    }

    相关文章

      网友评论

        本文标题:HBase优化策略及协处理器

        本文链接:https://www.haomeiwen.com/subject/fyhfyftx.html