Hbase性能调优(二)

时间:2023-12-31 12:59:50

一、HBase关键参数配置指导

如果同时存在读和写的操作,这两种操作的性能会相互影响。如果写入导致的flush和Compaction操作频繁发生,会占用大量的磁盘IO操作,从而影响读取的性能。如果写入导致阻塞较多的Compaction操作,就会出现Region中存在多个HFile的情况,从而影响读取的性能。所以如果读取的性能不理想的时候,也要考虑写入的配置是否合理。

1、提升写效率

1.1客户端调优

1.1.1 AutoFlush

参数值:setAutoFlush

解析:

  autoflush=false的原理是当客户端提交delete或put请求时,将该请求在客户端缓存,直到数据超过2M(hbase.client.write.buffer决定)或用户执行了hbase.flushcommits()时才向regionserver提交请求。因此即使htable.pu()执行返回成功,也并非说明请求真的成功了。假如还没有达到该缓存而client崩溃,该部分数据将由于未发送到regionserver而丢失。这对于零容忍的在线服务是不可接受的。

  autoflush=true虽然会让写入速度下降2-3本,但是对于很多在线应用来说这都是必须打开的,也正是hbase为什么让它默认为true的原因,每次请求都会发往regionserver,而regionserver接收到请求后第一件事情就是写HLOG。因此对IO要求是非常高的,为了提高hbase的写入速度应该尽可能地提高IO吞吐量,比如增加磁盘、使用raid卡、减少replication因子数等。

如何调优?

  经验设定:

  setAutoFlush=false

1.1.2使用PutList方式提交请求

  可以极大地提升写性能

1.2  Memstore相关

  当regionserver(以下简称为RS)收到一个写请求,会将这个请求定位到某个特定的region。每一个region存储了一系列的Row,每一个Row对应的数据分散在一个或多个ColumnFamily(以下简称为CF)。特定CF的数据都存储在对应的store里面,而每个store都是由一个memstore和数个storefile组成。memstore存储在RS的内存中,而storefile则存储在HDFS上。当一个写请求到达RS的时候,该请求对应的数据首先会被menstore存储,直到达到一定的临界条件,memstore里面的数据才会flush到storefile。

  使用memstore的主要原因是为了使存储在HDFS上的数据是有序的(按Row)。HDFS设计为顺序读写的,已有的文件不能被修改。这就意味着,因为hbase收到的写请求是无序的,所以如果直接将这些数据写到HDFS上,以后再对文件里面的内二做排序就会是一件极其困难的事情;无序的数据存储方式,又会大大影响后续的读请求性能。为了解决这种问题,hbase会将最近的某些写请求放到内存中(也就是memstore),并将这些数据在flush到storefile之前做好排序。

  除了解决排序的问题,memstore还有其他好处,比如:

  它能充当memcache的角色,缓存最近写入的数据。鉴于新数据的访问频率和几率都比旧数据高很多,这就大大的提高客户端的读效率。

  注意:每个memstore每次刷新时,都会给CF生产一个storefile。

  剩下读取就非常容易了,hbase会检查数据是否在memstore里面,否则就去storefile读取,然后返回给客户端。

1.2.1 根据memstore大小flush hfile

  参数值:hbase.hregion.memstore.flush.size

  参数解析:

    在regionserver中,当写操作内存中存在超过memstore.flush.size大小的memstore,则MemstoreFlusher就启动flush操作将该memstore以hfile的形式写入对应的store中。

  如何调优?

  默认:128M

  A、如果Regionserver的内存充足,而且活跃Region数量也不是很多的时候,可以适当增大该值,可以减少compaction的次数,有助于提升系统性能。

  B、这种flush产生的时候,并不是紧急的flush,flush操作可能会有一定延迟,在延迟期间,写操作还可以进行,Memstore还会继续增大,最大值 = “memstore.flush.size” * "hbase.hregion.memstore.block.multiplier"。

  C、当超过最大值时,将会阻塞写操作。适当增大“hbase.hregion.memstore.block.multiplier”可以减少阻塞,减少性能波动。

  参数值:hbase.regionserver.global.memstore.size

  参数解析:

    RegionServer中,负责flush操作的是MemStoreFlusher线程。该线程定期检查写操作内存,当写操作占用内存总量达到阈值,MemStoreFlusher将启动flush操作,按照从大到小的顺序,flush若干相对较大的memstore,直到所占用内存小于阈值。

    阈值=“hbase.regionserver.global.memstore.size” * "hbase.regionserver.global.memstore,size.lower.limit" * "Hbase_HEAPSIZE"

  如何调优?

    默认:0.4

    该配置与“hfile.block.cache.size”的和不能超过0.8,也就是写和读操作的内存不能超过HeapSize的80%,这样可以保证除读和写以外其他操作的正常运行。

1.2.3  Flush前进行Compaction

  参数值:hbase.hstore.blockingStoreFiles

  参数解析:

    在region flush前首先判断file文件个数,是否大于hbase.hstore.blockingStoreFiles。如果大于需要先Compaction并且让flush延时90s(这个参数可以通过hbase.hstore.blockingWaitTime进行配置),在延时过程中,将会继续写从而使得Memstore还会继续增大超过阈值(“memstore.flush.size” * "hbase.hregion.memstore.block.multiplier"),导致写操作阻塞。当完成Compaction后,可能就会产生大量写入。这样就导致性能激烈震荡。

  如何调优?

    默认:7

    增加hbase.hstore.blockingStoreFiles,可以降低Block几率。

1.3 内存相关

  Hbase利用内存完成读写操作。提高Hbase内存可以有效提高Hbase性能。

1.3.1 GC参数

  参数值:GC_OPTS

  参数解析:

    GC_OPTS主要需要调整HeapSize的大小和NewSize的大小。

    HMaster:

      - -Xms512M -Xmx1G -XX:NewSize=64M -XX:MaxNewSize=128M
    RegionServer:
      - -Xms4G -Xmx6G -XX:NewSize=64M -XX:MaxNewSize=128M

  如何调优?

    A、挑战者HeapSize大小的时候,建议将Xms和Xmx设置成相同的值,这样可以避免JVM动态调整HeapSize大小的时候影响性能。

    B、调整NewSize大小的时候,建议把其设置为HeapSize大小的1/9

    C、HMaster:当HBase集群规模越大、Region数量越多时,可以适当调大HMaster的GC_OPTS参数。

    D、RegionServer:RegionServer需要的内存一般比HMaster要大。在内存充足的情况下,HeapSize可以相对设置大一些。

  经验设定:

    主Hmaster的HeapSize为4G的时候,Hbase集群可以支持100000Region数的规模。根据经验值,单个RegionServer的HeapSize不建议超过20G。

1.4 HFile相关

1.4.1文件同步sync

参数值:hbase.regionserver.hfile.durable.sync

参数解析:

  控制HFfile文件在写入到HDFS时的同步程度。如果为true,HDFS在把数据写入到硬盘后才返回:如果为false,HDFS在把数据写入OS的缓存后就返回。

如何调优?

  默认为true

  把该值设置为false比设为true时在写入性能上会更优。

1.5 Compaction相关

  1.5.1Compact文件大小阈值

  参数值:hbase.regionserver.thread.compaction.throttle

  参数解析:

    控制一次Minor Compaction时,进行compaction的文件总大小的阈值。

  如何调优?

    默认:1.5G

    Compaction时的文件总大小会影响这一次compaction的执行时间,如果太大,可能会阻塞其他的compaction或flush操作。

  

  1.5.2 Compact文件个数阈值

  参数值:hbase.hstore.compaction.min

  参数解析:

    当一个Store中文件超过该值时,会进行compact。

  如何调优?

    默认:3

    适当增大该值,可以减少文件被重复执行compaction,但是如果过大,会导致Store中文件数过多而影响读取的性能。

  

  1.5.3 Compact文件数目

  参数值:hbase.hstore.compaction.max

  参数解析:

    控制一次compaction操作时的文件数量的最大值。

  如何调优?

    默认:10

    与“hbase.hstore.compaction.max.size”的作用基本相同,主要是控制一次compaction操作的时间不要太长。

  

  1.5.4 Compact文件大小选择

  参数值:hbase.hstore.compaction.max.size

  参数解析:

    如果一个HFle文件的大小大于该值,那么Minor Compaction操作中不会选择这个文件进行compaction操作,除非进行Major Compaction操作。

  如何调优?

    默认:2.5G

    这个值可以防止较大的HFile参与Compaction操作。在禁止Major Compaction后,一个Store中可能存在几个HFile,而不会合并成一个HFile,这样不会对数据读取造成太大的性能影响。

  1.5.5 Major Compaction执行周期

  参数值:hbase.hregion.majorcompaction
  参数解析:由于执行 Major Compaction 会占用较多的系统资源,如果正在处于系统繁忙时期,会影响系统的性能 。

  如何调优?

    默认: 24 小时    

    A. 如果业务没有较多的更新、删除、回收过期数据空间时, 建议设置为 0,以禁止Major Compaction。

    B. 如果必须要执行 Major Compaction,以回收更多的空间,可以适当增加该值,同时配置参数“hbase.offpeak.end.hour”和“hbase.offpeak.start.hour”以控制 Major Compaction 发生在业务空闲的时期。

1.6 HLog相关

  RS 上有一个 Write-ahead Log (以下简称 WAL),数据会持续的默认写到这个文件中。它包含了所有已经提交到 RS 的,已经保留在 memstore 中但是尚未 flush 到 storefile 的数据编辑历史。

这些在 memstore 中的,尚未持久化的数据,在 RS 发生错误时我们需要借助它进行恢复,它能重现这些尚未持久化的数据的编辑轨迹。 .

当 WAL(Hlog)变得非常大时,重现它的记录会花费非常多的时间。因此,我们需要限制WAL 的大小,当达到这个大小时,会触发 memstore 的 flush。

当数据 flush 到磁盘后,WAL 的大小就会变小,因为我们不需要再保存这些已经完成持久化的数据编辑记录。

  1.6.1 文件同步sync

  参数值:hbase.regionserver.wal.durable.sync

  参数解析:

    控制 HLog 文件在写入到 HDFS 时的同步程度。如果为 true, HDFS 在把数据写入到硬盘后才返回;如果为 false, HDFS 在把数据写入 OS 的缓存后就返回。

  如何调优?

    把该值设置为 false 比 true 在写入性能上会更优。
   

  1.6.2 Hlog Flush条件

  参数值:hbase.regionserver.maxlogs             hbase.regionserver.hlog.blocksize
  参数解析:

    A、表示一个RegionServer上未进行Flush的Hlog的文件数量的阈值,如果大于该值,RegionServer会强制进行flush操作。

    B、表示每个Hlog文件的最大大小。如果Hlog文件大小大于该值,就会滚动出一个新的Hlog,旧的将被禁用并归档。

  如何调优?

    这两个参数共同决定了RegionServer中可以存在的未进行Flush的hlog数量。WAL的最大容量 = hbase.regionserver.maxlogs * hbase.regionserver.hlog.blocksize。当达到这个容量的时候,memstore flush就会被触发。因此,你在调整memstore的设置的时候,你同样需要调整这些值来适应那些编号。否则,WAL容量达到限制可能导致memstore flush的罪魁祸首,你专门配置memstore参数所增加的资源可能永远无法被物尽其用。这个时候可以适当调整这两个参数的大小。以避免出现这种强制flush的情况。

  经验设定:

    hbase.regionserver.maxlogs:默认32,建议调整为100

    hbase.regionserver.hlog.blocksize:默认64M,建议调整为128M

1.7 表设计相关

  1.7.1压缩算法

  参数值:COMPRESSION

  参数解析:配置数据的压缩算法,这里的压缩是HFile中block级别的压缩。对于可以压缩的数据,配置压缩算法可以有效减少磁盘的IO,从而达到提高性能的目的。

  如何优化?

    默认:None

    并非所有数据都可以进行有效的压缩。例如一张图片的数据,因为图片一般已经是压缩后的数据,所以压缩效果有限。推荐使用SNAPPY,因为它有较好的Encoding / Decoding 速度和可以接受的压缩率。

    实例:create 'test_table',{NAME => 'cf1', COMPRESSION => 'SNAPPY'}

  1.7.2 Block大小

  参数值:BLOCKSIZE

  参数解析:

    配置HFile中block块的大小,不同的block块大小,可以影响HBase读写数据的效率。越大的block块,配合压缩算法,压缩的效率就越好;但是由于HBase的读取数据是以block块为单位的,所以越大的block块,对应随机读的情况,性能可能会比较差。

  如何调优?

    默认:64Kb

    如果要提升写入性能,一般扩大到128kb或者256kb,可以提升写数据的效率,也不会影响太大的随机读性能。

    实例:create 'test_table',{NAME => 'cf1', BLOCKSIZE => '32768'}
  

  1.7.3 缓存内存

  参数值:IN_MEMORY

  参数解析:

    配置这个表的数据有限缓存在内存中,这样可以有效提升读取的性能。

  如何调优?

    默认:false

    对于一些小表,而且需要频繁进行读取操作的,可以设置此配置项

    实例:create 'test_table',{NAME => 'cf1', IN_MEMORY => 'true'}

2、提升读效率

2.1 客户端调优

A、Scan数据时需要设置caching(一次从服务端读取的记录条数,默认是1),若使用默认值读性能会降到极低。

B、当不需要读一条数据所有列时,需要指定读取的列,以减少网络IO

C、只读取Rowkey时,可以为Scan添加一个只读取Rowkey的filter(FirstKeyOnlyFilter或者KeyOnlyFilter)。

D、在客户端代码中,可以设置caching和batch用来提升查询效率。

   例如:Scan.setCaching(caching);scan.setBatch(batch); 当 caching 和 batch 都为 1 的时候,我们要返回 10 行具有 20 列的记录,就要进行 201 次 RPC, 因为每一列都作为一个单独的 Result 来返回,这样是我们不可以接受的(还有一次 RPC 是用来确认 scan 已经完成) 。

a) RPC 次数公式: RPCs = (Rows * Cols per Row) / Min(Cols per Row, Batch Size)/Scanner Caching

2.2 内存相关

Hbase利用内存完成读写操作。提高HBase内存可以有效提高HBase性能。

2.2.1 GC参数

参数值:GC_OPTS

参数解析:

  GC_OPTS主要需要调整HeapSize的大小和NewSize的大小。

  HMaster:
    - -Xms512M -Xmx1G -XX:NewSize=64M -XX:MaxNewSize=128M
  RegionServer:
    - -Xms4G -Xmx6G -XX:NewSize=64M -XX:MaxNewSize=128M

如何调优?

  A. 调整 HeapSize 大小的时候,建议将 Xms 和 Xmx 设置成相同的值,这样可以避免 JVM动态调整 HeapSize 大小的时候影响性能。

  B. 调整 NewSize 大小的时候,建议把其设置为 HeapSize 大小的 1/9。

  C. HMaster:当 HBase 集群规模越大、 Region 数量越多时,可以适当调大 HMaster 的GC_OPTS 参数。

  D. RegionServer: RegionServer 需要的内存一般比 HMaster 要大。在内存充足的情况下,HeapSize 可以相对设置大一些。

经验设定:

主 HMaster 的 HeapSize 为 4G 的时候, HBase 集群可以支持 100000Region 数的规模。根据经验值,单个 RegionServer 的 HeapSize 不建议超过 20GB

2.3 缓存相关

  参数值:hfile.block.cache.size

  参数解析:

    HBase缓存区大小,主要影响查询性能。根据查询模式以及查询记录分布情况来解决缓存区的大小。

  如何调优?

    默认:0.25

    如果采用随机查询使得缓存区的命中率较低,可以适当降低缓存区大小。

3、关键参数配置指导--案例

3.1 活跃Region对集群的影响

  HBase在设计上,遵循了LSM-TREE的原理:写数据阶段,尽最大努力先将每一个Region的数据保留在内存(MemStore)中,等达到一定的阈值(默认为128M)之后,再 将这些数据固化(Flush)到文件(HFile)中,在这过程中,为了保证数据的安全性,通过将数据写入到一个人日志文件(Hlog)中:

Hbase性能调优(二)

在当前时间段可能被写入用户数据的Region,称作“活跃"Region”。

举例:

如果一个用户表的Region是按天划分的,那么,第一天的用户数据,只会被写入到第一天的Region中,则这些Region就是活跃的Region。此时,对于其它天的Region,都处于一种“空闲”的状态。

集群中每一个物理节点的内存资源都是有限的,每一个Region的数据都是暂时先保留在内存中然后再固化到HFile文件中的,因此,我们需要控制一个时间段的活跃的Region数目。如果Region过多的话,会导致内存资源紧张,每一个Region在内存中的数据可能还没有达到预先设置阈值的大小就被提前触发Flush操作,这会导致Flush频率升高,产生大量的小HFile(小文件过多会导致读取性能的直线下降,也会加大Compaction的频率和压力)。相反活跃Region过少的话,也会导致并发度提升不上去,读写性能偏低。

如何设置最合理的活跃Region数目?

  需要根据MemStore Flush的阈值大小,以及RegionServer堆内存的大小、预留MemStore空间的大小进行合理的计算。

  如下列子可以说明这种计算方法:

  经验举例:

    假设分配给RegionServer堆内存的大小为8G,MemStore所占空间比例为40%,MemStore Flush的阈值大小为128M,则合理的活跃Region数目约为8*1024*0.4/128=26(个/节点)。

    以用户交易记录表为例。每一条用户交易记录关联一个USER_ID,也关联一个确切的交易时间点。

      如果我们在设计Key值的时候,采用“USER_ID+TIME”的格式,则划分Region的时候,一定会按照USER_ID的范围划分的。对于任意一天的交易记录,可能涉及到各个范围内的USER_ID,即可能涉及到所有的Region,因此所有的Region都可能是活跃的,就会导致前面提到的那种活跃Region过多的问题,而且这种问题会随着时间的持续而不断恶化下去。

Hbase性能调优(二)

如果RowKey采用格式“DAY+USER_ID_TIME”的话,Region一定是按天划分的,那么,第N天的用户交易记录数据只会设计到第N天的Region,也只有这一天的Region是活跃的,这样就有力的控制了活跃Region数目:

             Hbase性能调优(二)

4、定位调优

4.1日志收集

日志分类介绍:

  当前HBase的日志保存在/var/log/Bigdata/HBase和/var/log/Bigdata/audit/hbase目录下,具体如下:

  Hbase性能调优(二)

Hbase性能调优(二)

4、2调优定位

  对于读写性能定位和调优,主要查看Regionserver的hbase-XXX-regionserver-XXX.log 运
行日志。

  日志中是否出现过以下信息?

  **Flush thread woke up with memory above low water.

  日志中出现这个信息说明有部分写过程出现过阻塞等待的现象,造成这个现象的原因是各个Region的Memstore使用的大小加起来超过了总的阈值,于是阻塞,并开始找一个Region进行Flush,,这个过程会需要消耗掉一段时间,通常来说造成这个的原因是单台Region server上的Region数太多了,因此单台Region server上最好不要放置过多的Region,一种调节方法是调大split的fileSize,这样可以适当的减少Region数,但需要关注调整后读性能的变化。

  **delaying flush up to

  当日志中出现这个信息时,可能会造成出现下面的现象,从而产生影响,这个通常是StoreFile太多造成的,通常可以调大点StoreFile个数的阈值。

  **Blocking updates for

  当日志中出现这个信息时,表示写动作已被阻塞,造成这个现象的原因是memStore中使用的大小已超过其阈值的2倍,通常是由于上面的delaving flush up to 造成的,或者是region数太多造成的,或者是太多的Hlog造成的,这种情况下会造成很大的影响,如内存够用的话,可以调大阈值,如果是其他原因,就对症下药。

4、3、定位调优思路

  针对HBase读写变慢的场景,可以按照如下思路进行定位、调优:

  开始-->对比性能差距-->查看监控信息-->查看相关日志-->确定具体场景-->进行参数调优-->后续观察

4.3.1通过客户端程序,记录写入、读取速度

  在客户端程序中,可以记录HBase写入/读取速度,关注性能差距。或者,通过HMaster的页面来查看各个RegionServer的RPC请求。

Hbase性能调优(二)

4.3.2查看HBase监控信息

  Region的分裂、compaction、flush次数过多、flush耗时高、硬件资源抢占等众多元素都会影响性能,因此,需要从Manager监控页面中,查看各个RegionServer的各类监控指标,需要重点关注:RegionServer GC时间、RegionServer GC次数、节点CPU/内存利用率、Compaction的次数,Flush文件次数、Flush操作的平均耗时、Split次数等信息。

                Hbase性能调优(二)

4.3.3查看相关日志

  结合HBase的监控信息,查看RegionServer的运行日志。

4.3.4举例

4.3.4.1背景说明

某个HBase测试集群,客户端主要是put写入操作,发现写入性能较慢。只有一张hbase表t1,表结构简单(一个cf,一个qualifier),建表时预分5个Region。

4.3.4.2性能差距比较

通过客户端put对t1表put数据计算出,单节点写入速度为416条/s左右。

4.3.4.3监控信息展示

发现各个RegionServer的flush次数较多

Hbase性能调优(二)

RegionServer的内存占用并不高

Hbase性能调优(二)

4.3.4.4日志分析定位

可以查看RegionServer的运行日志,发现Flush被延长90000ms字样:

2016-04-22 02:35:33,820 | WARN | MemStoreFlusher.0 | Region
t1,04,1461259167461.b6e781003392195313a5ec8e39c6bf77. has too many store files;

delaying flush up to 90000ms |
org.apache.hadoop.hbase.regionserver.MemStoreFlusher.flushRegion(MemStoreFlusher.jav
a:448)

Hbase性能调优(二)

初步分析结论:在内存利用不高的情况下,仍然有过多的Flush操作,并且看到有的Flush被延迟。因此,主要根据1.2章节内容,对MemStore相关参数,进行调优。

4.3.4.5参数调整&测试

调整前的参数为:
hbase.regionserver.global.memstore.size=0.1
hbase.hstore.blockingStoreFiles=2
调整后的参数为:
hbase.regionserver.global.memstore.size=0.4
hbase.hstore.blockingStoreFiles=7
调整后,用同样的客户端对同一张表 t1 进行 put 写入测试, 发现写入性能得到提升, 单
节点处理性能达到 1280 条/s

4、4常见问题处理

4.4.1 OOM(内存溢出)

4.4.1.1问题现象

当运行bulkload任务或开启Region操作时,在RegionServer端产生如下的日志:

“java.lang.OutOfMemoryError:Direct buffer memory”

4.4.1.2问题定位过程

由于各种操作,HBase需要许多内存。I/O操作实验direct buffer memory,因此为了更好的性能和提高并发数需要给RegionServer提供更多的direct buffer memory和heap memory。

检查JVM参数,按照使用场景增加heap memory(-Xms/-Xmx)和direct buffer memory(-XX:MaxDirectMemorySize)

4.4.1.3问题解决方法

增加heap memory和direct buffer memory来避免OutOfMemory异常

  eg:-Xms32G -Xmx32G -XX:MaxDirectMemorySize=2048M

经验设定:

  按照使用场景来修改GC_OPTS,RegionServer并发读写操作越多,需要的内存越大,经验表明一般地上述示例配置能支撑单个RegionServer支持30个长期并发的需求。