0%

Hbase数据压缩

本文主要包括:

  • Hbase数据压缩

Hbase数据压缩

压缩格式的选择

常用的几种压缩格式:lzo,gzip,snappy,bzip2,我们简单做一下对比,方便我们在实际场景中选择不同的压缩格式。

  1. 支持特性对比:
    压缩格式特性对比
  • 压缩相关codec实现在org.apache.hadoop.io.compress包下面
  • gzip算法hadoop内置支持,使用时直接处理文本数据一样,使用方便,压缩比高,缺点就是不支持split。如果压缩后文件与块大小相当,可以考虑使用gzip压缩,比如:小时原始日志压缩成gzip文件,使用方便。
  • bzip2 支持split,压缩比高,支持多文件,缺点就是慢。
  • lzo 压缩/解压速度也比较快,合理的压缩率;支持split(需要建索引,文件修改后需要重新建索引),支持hadoop native库,需要自己安装;
  • snappy 压缩/解压速度也比较快,合理的压缩率,不支持split,支持hadoop native库,需要自己安装。可以用于map中间结果的压缩。
  1. 性能对比
    数据压缩压缩比
    是否压缩数据以及使用何种压缩格式对性能具有重要的影响,一般原则:
  • 需要平衡压缩和解压缩数据所需的能力、读写数据所需的磁盘 IO,以及在网络中发送数据所需的网络带宽。正确平衡这些因素有赖于集群和数据的特征,以及您的使用模式。
  • 如果数据已压缩(例如 JPEG 格式的图像),则不建议进行压缩。事实上,结果文件实际上可能大于原文件。
  • GZIP 压缩使用的 CPU 资源比 Snappy 或 LZO 更多,但可提供更高的压缩比。GZIP 通常是不常访问的冷数据的不错选择。而 Snappy 或 LZO 则更加适合经常访问的热数据。
  • BZip2 还可以为某些文件类型生成比 GZip 更多的压缩,但是压缩和解压缩时会在一定程度上影响速度。HBase 不支持 BZip2 压缩。
  • Snappy 的表现通常比 LZO 好。应该运行测试以查看您是否检测到明显区别。
  • 对于 MapReduce,如果您需要已压缩数据可拆分,BZip2、LZO 和 Snappy 格式都可拆分,但是 GZip 不可以。可拆分性与 HBase 数据无关。
  • 对于 MapReduce,可以压缩中间数据、输出或二者。相应地调整您为 MapReduce 作业提供的参数。

压缩方式

创建表的时候指定

  1. 直接在hbase建表
    create 'gjc_test',{NAME=>'f1',COMPRESSION=>'Snappy'}
  2. 在phoenix建表
    create table ORACLEARCHIVESPACECOLLECTED_LATEST_BAK(
    EID                  VARCHAR,
    DEVICEID             VARCHAR,
    FLUMETIMESTAMP       VARCHAR,
    COLLECTEDTIME        VARCHAR,
    COLLECTCONFIGID      VARCHAR,
    UPLOADDATAMODELCODE  VARCHAR,
    SOURCE_DB_ID         VARCHAR,
    DF_FILE_SYSTEM       VARCHAR,
    DF_BLOCKS            VARCHAR,
    DF_USED              VARCHAR,
    DF_AVAILABLE         VARCHAR,
    DF_PERCENT_USE       VARCHAR,
    DF_MOUNTED_ON        VARCHAR,
    CMDNOTEXIST          VARCHAR,
    EXECERROR            VARCHAR,
    DF_PERCENT_USE_VALUE VARCHAR,
    CONSTRAINT my_pk PRIMARY KEY(EID,DEVICEID,FLUMETIMESTAMP,SOURCE_DB_ID)
    ) column_encoded_bytes=0, COMPRESSION='SNAPPY';

    对已有的表的数据进行压缩

  3. 在hbase中压缩
    # 禁用表
    disable 'device_logs'
    # 修改info列族的压缩格式
    alter 'device_logs' ,{NAME=>'f1',COMPRESSION=>'Snappy'}
    # 启用表
    enable 'device_logs'
    # 查看表信息
    describe 'device_logs'
    # 手动触发major_compaction
    major_compact 'device_logs'
  4. 通过phoenix方式压缩
    ALTER TABLE SNMP_BIZ_CPU_LATEST SET COMPRESSION='SNAPPY';
    -- 在phoenix执行完后,如果想要数据文件立刻复制,需要手动触发major_compaction,在hbase执行
    major_compact 'SNMP_BIZ_CPU_LATEST'
    注意:
    这里踩了一个坑,如果hbase的表是使用phoenix建表的,那么数据压缩也需要使用phoneix去压缩,这里使用hbase压缩了100多个表,导致所有压缩的表在phoenix无法查询
    原因: phoneix的数据编码和hbase的底层编码不一样。使用hbase数据压缩,相当于让hbase按照自己的编码格式去解析phoneix的底层数据,数据就乱了
    这里使用了各种办法,最后都没有把数据恢复回来,最后没办法,把数据重写了。把roekey从表里其他字段获取出来
    create table WINDOWSSECURITYCEV20201472COLLECTED(
        ROWKEY VARCHAR not null primary key,
        DEVICEID VARCHAR,
        EID VARCHAR,
        COLLECTEDTIME VARCHAR,
        COLLECTCONFIGID VARCHAR,
        UPLOADDATAMODELCODE VARCHAR,
        DEVICECOLLECTDETAILID VARCHAR,
        CODE VARCHAR,
        MESSAGE VARCHAR,
        PS_CODE VARCHAR,            
        DATA     VARCHAR,            
        ERROR_MESSAGE   VARCHAR,     
        OPERATING_SYSTEM  VARCHAR,   
        DOMAIN_CONTROLLER    VARCHAR,
        UPDATE_STATE_MESSAGE VARCHAR,
        COMPLIANCE          VARCHAR, 
        ENFORCEMENT       VARCHAR   
    ) column_encoded_bytes=0, COMPRESSION='SNAPPY';
    hbase org.apache.hadoop.hbase.mapreduce.CopyTable --new.name=WINDOWSSECURITYCEV20201472COLLECTED_BAK WINDOWSSECURITYCEV20201472COLLECTED
    
    upsert into WINDOWSSECURITYCEV20201472COLLECTED
    select DEVICEID  || to_char(to_number(to_date(COLLECTEDTIME,'yyyy-MM-dd hh:mm:ss','GMT+8')),'#')      ,
           DEVICEID             ,
           EID                  ,
           COLLECTEDTIME        ,
           COLLECTCONFIGID      ,
           UPLOADDATAMODELCODE  ,
           DEVICECOLLECTDETAILID,
           CODE                 ,
           MESSAGE              ,
           PS_CODE              ,
           DATA                 ,
           ERROR_MESSAGE        ,
           OPERATING_SYSTEM     ,
           DOMAIN_CONTROLLER    ,
           UPDATE_STATE_MESSAGE ,
           COMPLIANCE           ,
           ENFORCEMENT          
    from WINDOWSSECURITYCEV20201472COLLECTED_BAK

    使用YCSB测试Hbase读写性能

    YCSB工具安装:
    # 到githup上下载ycsb-hbase20-binding-0.17.0.tar.gz
    https://github.com/brianfrankcooper/YCSB/releases/tag/0.17.0
    cd /root/gujc/ycsb-hbase20-binding-0.17.0/workloads
    cat workloada
    recordcount=150000
    operationcount=150000
    workload=site.ycsb.workloads.CoreWorkload
    
    readallfields=true
    
    readproportion=0.5
    updateproportion=0.5
    scanproportion=0
    insertproportion=0
    
    requestdistribution=zipfian
    # 生成数据
    bin/ycsb load hbase20 -P workloads/workloada -cp /etc/hbase/conf/ -p table=gjc_test -p columnfamily=info
    # 测试数据
    bin/ycsb run hbase20 -P workloads/workloada -cp /etc/hbase/conf/ -p table=gjc_test -p columnfamily=info

    HBase中的Compaction详解

    HBase是基于一种LSM-Tree(Log-Structured Merge Tree)存储模型设计的,写入路径上是先写入WAL(Write-Ahead-Log)即预写日志,再写入memstore缓存,满足一定条件后执行flush操作将缓存数据刷写到磁盘,生成一个HFile数据文件。随着数据不断写入,磁盘HFile文件就会越来越多,文件太多会影响HBase查询性能,主要体现在查询数据的io次数增加。为了优化查询性能,HBase会合并小的HFile以减少文件数量,这种合并HFile的操作称为Compaction,这也是为什么要进行Compaction的主要原因。

    Compaction的作用

    其实Compaction操作属于资源密集型操作特别是IO密集型,这点后面也会提及到,Compaction其实就是以短时间内的IO消耗,以换取相对稳定的读取性能。

    Compaction 分类

    HBase Compaction分为两种:Minor Compaction 与 Major Compaction,通常我们简称为小合并、大合并。
    hbase集群告警-压缩队列
    Minor Compaction:指选取一些小的、相邻的HFile将他们合并成一个更大的HFile。默认情况下,minor compaction会删除选取HFile中的TTL过期数据。
    Major Compaction:指将一个Store中所有的HFile合并成一个HFile,这个过程会清理三类没有意义的数据:被删除的数据(打了Delete标记的数据)、TTL过期数据、版本号超过设定版本号的数据。另外,一般情况下,Major Compaction时间会持续比较长,整个过程会消耗大量系统资源,对上层业务有比较大的影响。因此,生产环境下通常关闭自动触发Major Compaction功能,改为手动在业务低峰期触发。

    这里值得关注,默认情况下Minor Compaction也会删除数据,但只是删除合并HFile中的TTL过期数据。Major Compaction是完全删除无效数据,包括被删除的数据、TTL过期数据以及版本号过大的数据。

    Compaction 触发条件

    HBase触发Compaction的条件有三种:
  5. memstore Flush
    可以说compaction的根源就在于flush,memstore 达到一定阈值或其他条件时就会触发flush刷写到磁盘生成HFile文件,正是因为HFile文件越来越多才需要compact。HBase每次flush之后,都会判断是否要进行compaction,一旦满足minor compaction或major compaction的条件便会触发执行。
  6. 后台线程周期性检查
    后台线程 CompactionChecker 会定期检查是否需要执行compaction,检查周期为hbase.server.thread.wakefrequency * hbase.server.compactchecker.interval.multiplier,这里主要考虑的是一段时间内没有写入请求仍然需要做compact检查。其中参数 hbase.server.thread.wakefrequency 默认值 10000 即 10s,是HBase服务端线程唤醒时间间隔,用于log roller、memstore flusher等操作周期性检查;参数 hbase.server.compactchecker.interval.multiplier 默认值1000,是compaction操作周期性检查乘数因子。10 * 1000 s 时间上约等于2hrs, 46mins, 40sec。
  7. 手动触发
    是指通过HBase Shell、Master UI界面或者HBase API等任一种方式 执行 compact、major_compact等命令。(这里主要指的是Major Compact)

注意:HBase RS内部设计了两个线程池:large compactions与small compactions,用来分开处理Compaction操作,如果待合并文件的总大小大于(2 * hbase.hstore.compaction.max * hbase.hregion.memstore.flush.size)则交给large compactions线程池处理,否则交给small compactions线程池处理。

Compaction 参数解析

Major Compaction 参数

Major Compaction涉及的参数比较少,主要有大合并时间间隔与一个抖动参数因子,如下:

  1. hbase.hregion.majorcompaction:Major compaction周期性时间间隔,默认值604800000,单位ms。

表示major compaction默认7天调度一次,HBase 0.96.x及之前默认为1天调度一次。设置为 0 时表示禁用自动触发major compaction。需要强调的是一般major compaction持续时间较长、系统资源消耗较大,对上层业务也有比较大的影响,一般生产环境下为了避免影响读写请求,会禁用自动触发major compaction。

  1. hbase.hregion.majorcompaction.jitter:Major compaction抖动参数,默认值0.5

这个参数是为了避免major compaction同时在各个regionserver上同时发生,避免此操作给集群带来很大压力。 这样节点major compaction就会在 + 或 - 两者乘积的时间范围内随机发生。

Minor Compaction 参数

Minor compaction涉及的参数比major compaction要多,各个参数的目标是为了选择合适的HFile:

  1. hbase.hstore.compaction.min : 一次minor compaction最少合并的HFile数量,默认值 3。

    表示至少有3个符合条件的HFile,minor compaction才会启动。一般情况下不建议调整该参数。如果要调整,不建议调小该参数,这样会带来更频繁的压缩,调大该参数的同时其他相关参数也应该做调整。早期参数名称为 hbase.hstore.compactionthreshold。

  2. hbase.hstore.compaction.max: 一次minor compaction最多合并的HFile数量,默认值 10。

    这个参数也是控制着一次压缩的时间。一般情况下不建议调整该参数。调大该值意味着一次compaction将会合并更多的HFile,压缩时间将会延长。

  3. hbase.hstore.compaction.min.size:文件大小 < 该参数值的HFile一定是适合进行minor compaction文件,默认值 128M(memstore flush size)

    意味着小于该大小的HFile将会自动加入(automatic include)压缩队列。一般情况下不建议调整该参数。但是,在write-heavy就是写压力非常大的场景,可能需要微调该参数、减小参数值,假如每次memstore大小达到1~2M时就会flush生成HFile,此时生成的每个HFile都会加入压缩队列,而且压缩生成的HFile仍然可能小于该配置值会再次加入压缩队列,这样将会导致压缩队列持续很长。

  4. hbase.hstore.compaction.max.size:文件大小 > 该参数值的HFile将会被排除,不会加入minor compaction,默认值Long.MAX_VALUE

    没有什么限制。一般情况下也不建议调整该参数。

  5. hbase.hstore.compaction.ratio:这个ratio参数的作用是判断文件大小 > hbase.hstore.compaction.min.size的HFile是否也是适合进行minor compaction的,默认值1.2

    更大的值将压缩产生更大的HFile,建议取值范围在1.0~1.4之间。大多数场景下也不建议调整该参数。

  6. hbase.hstore.compaction.ratio.offpeak: 此参数与compaction ratio参数含义相同,是在原有文件选择策略基础上增加了一个非高峰期的ratio控制,默认值5.0。

    这个参数受另外两个参数 hbase.offpeak.start.hour 与 hbase.offpeak.end.hour 控制,这两个参数值为[0, 23]的整数,用于定义非高峰期时间段,默认值均为-1表示禁用非高峰期ratio设置。

Compaction 总结

HBase Compaction操作是为了数据读取做的优化,总的来说是以牺牲磁盘io来换取读性能的基本稳定。Compaction操作分为minor compaction与major compaction,其中major compaction消耗资源较大、对读写请求有一定影响,因此一般是禁用自动周期性执行而选择业务低峰期时手动执行。

具体可以参考HBase Compaction的前生今世-身世之旅
Hbase的MinorCompact过程解析及参数调优

hbase性能优化

在阿里云正式区做数据压缩的时候,因为这个集群内有一张表单表数据量就有6T,表太大了,不敢随便压缩,并且,hbase集群一直在告警
hbase集群告警-压缩队列

分析原因

这里分析了一下告警原因:

5.6 T    6.3 T    /hbase/data/default/TraceV2

TraceV2这张表每个小时能增长40G的数据,并且,该表设置了TTL,也就是说,每小时它要写40G数据,然后还要清理掉40G的数据。这么频繁的写操作,就会造成频繁的compaction

解决方法

因此需要对hbase做性能优化