美文网首页
Apache Phoenix(二十)因加SALT导致的HFile

Apache Phoenix(二十)因加SALT导致的HFile

作者: 我知他风雨兼程途径日暮不赏 | 来源:发表于2020-03-05 15:02 被阅读0次

    起因:在每张临时表上增加SALT_BUCKETS = 16,导致三个节点的hbase集群出现了3000多个region,出现的几种表象:

    • 多region节点zookeeper日志:connect reset by peer
    • phoenix进的去,但是查询处于卡死
    • 多region节点HRegionServer处于CPU百分百状态
    • 频繁GC

    HBASE原理

    HBASE架构图
    Client
    • 包含访问HBase的接口并维护cache来加快对HBase的访问

    Zookeeper

    • 保证任何时候,集群中只有一个master
    • 存贮所有Region的寻址入口。
    • 实时监控Region server的上线和下线信息。并实时通知Master
    • 存储HBase的schema和table元数据

    Master

    • 为Region server分配region
    • 负责Region server的负载均衡
    • 发现失效的Region server并重新分配其上的region
    • 管理用户对table的增删改操作

    RegionServer

    • Region server维护region,处理对这些region的IO请求
    • Region server负责切分在运行过程中变得过大的region

    HLog(WAL log)

    • HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是 HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和 region名字外,同时还包括sequence number和timestamp,timestamp是” 写入时间”,sequence number的起始值为0,或者是最近一次存入文件系 统中sequence number。
    • HLog SequeceFile的Value是HBase的KeyValue对象,即对应HFile中的 KeyValue

    Region

    • HBase自动把表水平划分成多个区域(region),每个region会保存一个表 里面某段连续的数据;每个表一开始只有一个region,随着数据不断插 入表,region不断增大,当增大到一个阀值的时候,region就会等分会 两个新的region(裂变)
    • 当table中的行不断增多,就会有越来越多的region。这样一张完整的表 被保存在多个Regionserver上。

    Memstore 与 storefile

    • 一个region由多个store组成,一个store对应一个CF(列族)
    • store包括位于内存中的memstore和位于磁盘的storefile写操作先写入 memstore,当memstore中的数据达到某个阈值,hregionserver会启动 flashcache进程写入storefile,每次写入形成单独的一个storefile
    • 当storefile文件的数量增长到一定阈值后,系统会进行合并(minor、 major compaction),在合并过程中会进行版本合并和删除工作 (majar),形成更大的storefile。
    • 当一个region所有storefile的大小和超过一定阈值后,会把当前的region 分割为两个,并由hmaster分配到相应的regionserver服务器,实现负载均衡。
    • 客户端检索数据,先在memstore找,找不到再找storefile
    • HRegion是HBase中分布式存储和负载均衡的最小单元。最小单元就表 示不同的HRegion可以分布在不同的HRegion server上。
    • HRegion由一个或者多个Store组成,每个store保存一个columns family。
    • 每个Strore又由一个memStore和0至多个StoreFile组成。
      如图:StoreFile 以HFile格式保存在HDFS上。


      region、memestore和store对应关系
      hbase和hdfs文件对应关系

    发生原因

    我们知道一个RegionServer上有n个region,每个region会根据不同的col family数拥有不同的store,每个store有一块自己的memstore内存区和多个HFile文件,所以在region很多的情况下,平均RegionServer分担的Region就会多了,那么一台RegionServer上资源是优先的,并且多个region都有自己的memstore,所以就会争抢资源,一直与memstore比较小了,所以在memstore很小的时候,就会频繁的刷HFile,那么memstore刷出来的HFile也就相应的变小了,所以为了保证HFile的数量合理,就会发生大规模的合并,那么合并就会拖慢性能,甚至导致Full GC的发生.这就会造成RegionServer与ZK可能发生失联,那么就会造成一系列的错误。

    开发整改

    对于大量需要临时表的业务,整改成单个临时表,结合phoenix的动态列进行。以当前公司的业务为例子,一个工程包含多个运行流程,每个运行流程的算子都可能发生变化,于是乎会影响中间的建表情况,在这种情况下我们需要建的表如下:

    -- 创建自增pk
    CREATE SEQUENCE my_sequence;
    CREATE TABLE temporaryData(
    -- 自增PK
       pk bigint not null,
     -- 运行流程ID
        processId bigint ,
    -- 工程ID
        projectId bigint,
    -- 算子ID
        algorithmId  bigint,
    -- 工程算子ID
        onlyalgorithmId  bigint,
    -- 表名
        tableName varchar,
    -- 创建时间
        createDate date,
    -- 创建者ID
        createBy varchar,
    -- 备注
        remark varchar
        CONSTRAINT pk PRIMARY KEY (pk))SALT_BUCKETS=3,COLUMN_ENCODED_BYTES=0;
    

    模拟数据写入

    可以看到我的表是不存在name和age的,但是我可以这样插入进去:

    upsert into temporaryData (pk,processId,projectId ,algorithmId,onlyalgorithmId,tableName,createDate ,createBy ,remark,
      name varchar,
      age integer) 
    values(NEXT VALUE FOR my_sequence,1,1,1,1,'student','2020-03-04 14:00:00','admin','暂无','李四',23);
    

    模拟数据读出

    select pk,PROCESSID,projectId,tableName,age  
    from temporaryData (NAME VARCHAR(255),AGE INTEGER) where PROCESSID = 2;
    

    Linux 调优

    vm.swappiness

    echo "vm.swappiness = 0" >> /etc/sysctl.conf
    

    vm.swappiness 参数被用于定义多少积极内存页被交换到磁盘。它接收从 0 到 100 的任何值 - 一个更低的值意味着内核将更少的交换,但是一个更高的值使得内核应用更经常的交换。默认值是 60。
    我们在步骤 1 中把 vm.swappiness 设置成 0,这将使得内核避免把进程尽可能的从物理内存中交换出去。这对 HBase 是非常有用的,因为 HBase 的进程消费大量的内存,一个高的 vm.swappiness 值将使得 HBase 交换很多并遭遇非常慢的垃圾回收。随着 ZooKeeper session 超时,这可能会导致 RegionServer 进程被杀死。我们建议你设置它为 0 或者任何更低的数字(比如,10)并观察 swapping 状态。
    注意该值被 sysctl 命令设置仅仅会持久化直到服务器下次重启。你需要在 /etc/sysctl.conf 文件设置 vm.swappiness,以至于该设置无论服务器什么时候重启都会生效。

    JVM调优

    HBASE_HEAPSIZE

    $ vi $HBASE_HOME/conf/hbase-env.sh
    export HBASE_HEAPSIZE=8000
    export HBASE_OPTS="$HBASE_OPTS -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/usr/local/hbase/logs/gc-hbase.log"
    

    加大堆内存,可以加大到linux服务器内存的2/3,并且指定gc日志,方便以后调试优化。

    hbase-site.xml配置调优

    hbase.hregion.majorcompaction

    推荐设置:0
    配置major合并的间隔时间,默认为1天,可设置为0,禁止自动的major合并,可手动或者通过脚本定期进行major合并,有两种compact:minor和major,minor通常会把数个小的相邻的storeFile合并成一个大的storeFile,minor不会删除标示为删除的数据和过期的数据,major会删除需删除的数据,major合并之后,一个store只有一个storeFile文件,会对store的所有数据进行重写,有较大的性能消耗。

    hbase.regionserver.handler.count

    推荐设置:100
    该设置决定了处理RPC的线程数量,默认值是10,通常可以调大,比如:150,当请求内容很大(上MB,比如大的put、使用缓存的scans)的时候,如果该值设置过大则会占用过多的内存,导致频繁的GC,或者出现OutOfMemory,因此该值不是越大越好。

    hbase.hregion.max.filesize

    推荐设置:按照数据量/1000
    配置region大小,0.94.12版本默认是10G,region的大小与集群支持的总数据量有关系,如果总数据量小,则单个region太大,不利于并行的数据处理,如果集群需支持的总数据量比较大,region太小,则会导致region的个数过多,导致region的管理等成本过高,如果一个RS配置的磁盘总量为3T*12=36T数据量,数据复制3份,则一台RS服务器可以存储10T的数据,如果每个region最大为10G,则最多1000个region,如此看,94.12的这个默认配置还是比较合适的,不过如果要自己管理split,则应该调大该值,并且在建表时规划好region数量和rowkey设计,进行region预建,做到一定时间内,每个region的数据大小在一定的数据量之下,当发现有大的region,或者需要对整个表进行region扩充时再进行split操作,一般提供在线服务的hbase集群均会弃用hbase的自动split,转而自己管理split。

    file.block.cache.size

    推荐设置:暂无
    RS的block cache的内存大小限制,默认值0.25,在偏向读的业务中,可以适当调大该值,具体配置时需试hbase集群服务的业务特征,结合memstore的内存占比进行综合考虑。

    hbase.hstore.compactionThreshold

    推荐设置:6
    HStore的storeFile数量>= compactionThreshold配置的值,则可能会进行compact,默认值为3,可以调大,比如设置为6,在定期的major compact中进行剩下文件的合并。
    hbase.hstore.blockingStoreFiles
    HStore的storeFile的文件数大于配置值,则在flush memstore前先进行split或者compact,除非超过hbase.hstore.blockingWaitTime配置的时间,默认为7,可调大,比如:100,避免memstore不及时flush,当写入量大时,触发memstore的block,从而阻塞写操作。

    hbase.hregion.memstore.block.multiplier

    推荐设置:4
    默认值2,如果memstore的内存大小已经超过了hbase.hregion.memstore.flush.size的2倍,则会阻塞memstore的写操作,直到降至该值以下,为避免发生阻塞,最好调大该值,比如:4,不可太大,如果太大,则会增大导致整个RS的memstore内存超过memstore.upperLimit限制的可能性,进而增大阻塞整个RS的写的几率。如果region发生了阻塞会导致大量的线程被阻塞在到该region上,从而其它region的线程数会下降,影响整体的RS服务能力

    hbase.hregion.memstore.flush.size

    推荐设置:128M
    默认值128M,单位字节,超过将被flush到hdfs,该值比较适中,一般不需要调整。

    hbase.regionserver.global.memstore.upperLimit

    推荐设置:0.4
    默认值0.4,RS所有memstore占用内存在总内存中的upper比例,当达到该值,则会从整个RS中找出最需要flush的region进行flush,直到总内存比例降至该数限制以下,并且在降至限制比例以下前将阻塞所有的写memstore的操作,在以写为主的集群中,可以调大该配置项,不建议太大,因为block cache和memstore cache的总大小不会超过0.8,而且不建议这两个cache的大小总和达到或者接近0.8,避免OOM,在偏向写的业务时,可配置为0.45,memstore.lowerLimit保持0.35不变,在偏向读的业务中,可调低为0.35,同时memstore.lowerLimit调低为0.3,或者再向下0.05个点,不能太低,除非只有很小的写入操作,如果是兼顾读写,则采用默认值即可。
    hbase.hregion.memstore.flush.size 这个参数的作用是当单个Region内所有的memstore大小总和超过指定值时,flush该region的所有memstore。RegionServer的flush是通过将请求添加一个队列,模拟生产消费模式来异步处理的。那这里就有一个问题,当队列来不及消费,产生大量积压请求时,可能会导致内存陡增,最坏的情况是触发OOM。这个参数的作用是防止内存占用过大,当ReigonServer内所有region的memstores所占用内存总和达到heap的[40%]时,HBase会强制block所有的更新并flush这些region以释放所有memstore占用的内存

    hbase.regionserver.global.memstore.lowerLimit

    推荐设置:0.35
    默认值0.35,RS的所有memstore占用内存在总内存中的lower比例,当达到该值,则会从整个RS中找出最需要flush的region进行flush,配置时需结合memstore.upperLimit和block cache的配置。同upperLimit,只不过lowerLimit在所有region的memstores所占用内存达到Heap的[35%]时,不flush所有的memstore。它会找一个memstore内存占用最大的region,做个别flush,此时写更新还是会被block。lowerLimit算是一个在所有region强制flush导致性能降低前的补救措施。在日志中,表现为 “** Flush thread woke up with memory above low water.”

    hfile.block.index.cacheonwrite

    推荐设置:false
    在index写入的时候允许put无根(non-root)的多级索引块到block cache里,默认是false,设置为true,或许读性能更好,但是是否有副作用还需调查。

    io.storefile.bloom.cacheonwrite

    推荐设置:false
    默认为false,需调查其作用。
    6.13、hbase.regionserver.regionSplitLimit
    推荐设置:默认即可
    控制最大的region数量,超过则不可以进行split操作,默认是Integer.MAX,可设置为1,禁止自动的split,通过人工,或者写脚本在集群空闲时执行。如果不禁止自动的split,则当region大小超过hbase.hregion.max.filesize时会触发split操作(具体的split有一定的策略,不仅仅通过该参数控制,前期的split会考虑region数据量和memstore大小),每次flush或者compact之后,regionserver都会检查是否需要Split,split会先下线老region再上线split后的region,该过程会很快,但是会存在两个问题:1、老region下线后,新region上线前client访问会失败,在重试过程中会成功但是如果是提供实时服务的系统则响应时长会增加;2、split后的compact是一个比较耗资源的动作。

    zookeeper.session.timeout

    推荐设置:180000
    默认值:3分钟(180000ms);RegionServer与Zookeeper间的连接超时时间。当超时时间到后,ReigonServer会被Zookeeper从RS集群清单中移除,HMaster收到移除通知后,会对这台server负责的regions重新balance,让其他存活的RegionServer接管.这个timeout决定了RegionServer是否能够及时的failover。设置成1分钟或更低,可以减少因等待超时而被延长的failover时间。不过需要注意的是,对于一些Online应用,RegionServer从宕机到恢复时间本身就很短的(网络闪断,crash等故障,运维可快速介入),如果调低timeout时间,反而会得不偿失。因为当ReigonServer被正式从RS集群中移除时,HMaster就开始做balance了(让其他RS根据故障机器记录的WAL日志进行恢复)。当故障的RS在人工介入恢复后,这个balance动作是毫无意义的,反而会使负载不均匀,给RS带来更多负担。特别是那些固定分配regions的场景。

    相关文章

      网友评论

          本文标题:Apache Phoenix(二十)因加SALT导致的HFile

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