美文网首页
HBase——性能调优

HBase——性能调优

作者: 小波同学 | 来源:发表于2023-03-27 00:03 被阅读0次

一、客户端优化

1.1 读优化

HBase 读数据共有两种方式,Get 与 Scan。

在通用层面,在客户端与服务端建连需要与 zookeeper 通信,再通过 meta 表定位到 region 信息,所以在初次读取 HBase 的时候 rt 都会比较高,避免这个情况就需要客户端针对表来做预热,简单的预热可以通过获取 table 所有的 region 信息,再对每一个 region 发送一个 Scan 或者 Get 请求,这样就会缓存 region 的地址;

rowkey 是否存在读写热点,若出现热点则失去分布式系统带来的优势,所有请求都只落到一个或几个 HRegion 上,那么请求效率一定不会高;

读写占比是如何的。如果写重读轻,浏览服务端 RegionServer 日志发现很多 MVCC STUCK 这样的字样,那么会因为 MVCC 机制因为写 Sync 到 WAL 不及时而阻塞读。

1.1.1 Get 请求优化

  • 将 Get 请求批量化,减少 rpc 次数,但如果一批次的 Get 数量过大,如果遇到磁盘毛刺或者 Split 毛刺,则 Get 会全部失败(不会返回部分成功的结果),抛出异常。
  • 指定列族,标识符。这样可以服务端过滤掉很多无用的 scanner,减少 IO 次数,提高效率,该方法同样适用于 Scan。

1.1.2 scan 请求优化

  • 设定合理的 startRow 与 stopRow 。如果 scan 请求不设置这两个值,而只设置 filter,则会做全表扫描。
  • 设置合理的 caching 数目, scan.setCaching(100)。 因为 Scan 潜在会扫描大量数据,因此客户端发起一次 Scan 请求,实际并不会一次就将所有数据加载到本地,而是分成多次 RPC 请求进行加载。默认值是 100。用户如果确实需要扫描海量数据,同时不做逻辑分页处理,那么可以将缓存值设置到 1000,减少 rpc 次数,提升处理效率。如果用户需要快速,迭代地获取数据,那么将 caching 设置为 50 或者 100 就合理。

二、服务端优化

2.1 COMPRESSION

配置数据的压缩算法,这里的压缩是HFile中block级别的压缩。对于可以压缩的数据,配置压缩算法可以有效减少磁盘的IO,从而达到提高性能的目的。但是并不是所有数据都可以进行有效压缩,如图片,因为图片一般是已经压缩后的数据,所以压缩效果有限。常用的压缩算法是SNAPPY,因为它有较好的压缩和解压速度和可以接受的压缩率。

2.2 IN_MEMORY

配置表的数据优先缓存在内存中,这样可以有效提升读取的性能。适合小表,而且需要频繁进行读取操作的。

2.3 预分区

在HBase中数据是分布在各个Region中的,每个Region都负责一个起始RowKey和结束Rowkey的范围,在向HBase中写数据的时候,会根据RowKey请求到对应的Region上,如果写请求都集中在某一个Region或某几个Region上的时候,性能肯定不如写请求均匀分布在各个Region上好。默认情况下,创建的HBase的只有一个Region分区,会随着数据量的变大,进行split,拆分成多个Region,最开始的性能肯定会很不好

建议在设计HBase的的时候,进行预分区,并设计一个良好的Rowkey生成规则(关于RowKey设计,可以参考之前的博客,尽量将数据分散到各个Region上,那样在进行HBase的读写的时候,对性能会有很好的改善。

2.4 合理设置WAL存储级别

数据在写入HBase的时候,先写WAL,再写入缓存。通常情况下写缓存延迟很低,WAL机制一方面是为了确保数据即使写入缓存后数据丢失也可以通过WAL恢复,另一方面是为了集群之间的复制。默认WAL机制是开启的,并且使用的是同步机制写WAL。

如果业务不特别关心异常情况下部分数据的丢失,而更关心数据写入吞吐量,可考虑关闭WAL写,这样可以提升2~3倍数据写入的吞吐量。

如果业务不能接受不写WAL,但是可以接受WAL异步写入,这样可以带了1~2倍性能提升。

HBase中可以通过设置WAL的持久化等级决定是否开启WAL机制、以及HLog的落盘方式。

WAL的持久化等级分为如下四个等级:

  • SKIP_WAL:只写缓存,不写HLog日志。这种方式因为只写内存,因此可以极大的提升写入性能,但是数据有丢失的风险。在实际应用过程中并不建议设置此等级,除非确认不要求数据的可靠性。
  • ASYNC_WAL:异步将数据写入HLog日志中。
  • SYNC_WAL:同步将数据写入日志文件中,需要注意的是数据只是被写入文件系统中,并没有真正落盘,默认。
  • FSYNC_WAL:同步将数据写入日志文件并强制落盘。最严格的日志写入等级,可以保证数据不会丢失,但是性能相对比较差。

同样,除了在创建表的时候直接设置WAL存储级别,也可以通过客户端设置WAL持久化等级,代码:

put.setDurability(Durability.SYNC_WAL);

2.5 BLOCKSIZE

配置HFile中block块的大小,不同的block大小,可以影响HBase读写数据的效率。越大的block块,配置压缩算法,压缩的效率就越好;但是由于HBase的读取数据时以block块为单位的,所以越大的block块,对于随机读的情况,性能可能会比较差,如果要提升写入的性能,一般扩大到128kb或者256kb,可以提升写数据的效率,也不会影响太大的随机读性能。

2.6 DATA_BLOCK_ENCODING

配置HFile中block块的编码方法。当一行数据中存在多个列时,一般可以配置为"FAST_DIFF",可以有效的节省数据存储的空间,从而提升性能。

2.7 BloomFilter

优化原理:BloomFilter主要用来过滤不存在待检索RowKey或者Row-Col的HFile文件,避免无用的IO操作。它会告诉你在这个HFile文件中是否可能存在待检索的KeyValue,如果不存在,就可以不用小号IO打开文件进行seek。通过设置BloomFilter可以提升读写的性能。

BloomFilter是一个列族级别的配置属性,如果列族设置了BloomFilter,那么HBase会在生成StoreFile时包含一份BloomFilter的结构的数据,称为MetaBlock(一旦写入就无法更新)。MetaBlock和DataBlock(真实的KeyValue数据)一起由LRUBlockCache维护,所以开启了BloomFilter会有一定的存储即内存cache开销。

HBase利用BloomFilter可以节省必须读磁盘过程,可以提高随机读(get)的性能,但是对于顺序读(scan)而言,设置BloomFilter是没有作用的(0.92版本以后,如果设置了BloomFilter为ROWCOL,对于执行了qualifier的scan有一定的优化)

BloomFilter取值有两个,ROW和ROWCOL,需要根据业务来确定具体使用哪种。

  • 如果业务大多数随机查询仅仅使用row作为查询条件,BloomFilter一定要设置为ROW。
  • 如果大多数随机查询使用row+col作为查询条件,BloomFilter需要设置为ROWCOL。
  • 如果不确定业务查询类型,设置为ROW。‘

2.8 GC_OPTS

HBase是利用内存完成读写操作。提高HBase内存可以有效提高HBase性能。GC_OPTS主要需要调整HeapSize和NewSize的大小。调整HeapSize大小的时候,建议将Xms和Xmx设置成相同的值,这样可以避免JVM动态调整HeapSize大小的时候影响性能。调整NewSize大小的时候,建议把其设置为HeapSize大小的1/9。

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

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

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

# HMaster、RegionServer GC_OPTS配置如下:HMaster: -Xms2G -Xmx2G -XX:NewSize=256M -XX:MaxNewSize=256M RegionServer: -Xms4G -Xmx4G -XX:NewSize=512M -XX:MaxNewSize=512M复制代码

2.9 RegionServer并发请求处理数量

hbase.regionserver.handler.count表示RegionServer在同一时刻能够并发处理多少请求。如果设置过高会导致激烈的线程竞争,如果设置过小,请求将会在RegionServer长时间等待,降低处理能力。应该根据资源情况,适当增加处理线程数。

建议根据CPU的使用情况,可以设置为100至300之间的值。

2.10 控制MemStore的大小

hbase.hregion.memstore.flush.size默认值128M,单位字节,一旦有MemStore超过该值将被flush,如果regionserver的jvm内存比较充足(16G以上),可以调整为256M。在内存足够put负载大情况下可以调整增大。

2.11 BlockCache优化

BlockCache作为读缓存,合理设置对于提高读性能非常重要。默认情况下,BlockCache和MemStore的配置各占40%,可以根据集群业务进行修正,比如读多写少业务可以将BlockCache占比调大。另外BlockCache的策略也很重要,不同策略对读性能来说影响并不大,但是对GC的影响 却很显著。

HBase缓存区大小,主要影响查询性能。根据查询模式以及查询记录分布情况来决定缓存区的大小。如果采用随机查询使得缓存区的命中率较低,可以适当降低缓存大小。

hfile.block.cache.size,默认0.4,用来提高读性能hbase.regionserver.global.memstore.size,默认0.4,用来提高写性能复制代码

2.12 控制HFile个数

MemStore在flush之前,会进行StoreFile的文件数量校验(通过hbase.hstore.blockingStoreFiles参数配置),如果大于设定值,系统将会强制执行Compaction操作进行文件合并,在合并的过程中会阻塞MemStore的数据写入,等待其他线程将StoreFile进行合并。通常情况下发生在数据写入很快的情况下。

hbase.hstore.compactionThreshold表示启动Compaction的最低阈值,该值不能太大,否则会积累太多文件,一般建议设置为5~8左右。

hbase.hstore.blockingStoreFiles默认设置为7,可以适当调大一些。

2.13 Split优化

hbase.hregion.max.filesize表示HBase中Region的文件总大小的最大值。当Region中的文件大于该参数时,将会导致Region分裂。

  • 如果该参数设置过小时,可能会导致Split操作频繁
  • 如果该参数设置过大时,会导致Compaction操作需要处理的文件个数增大,影响Compaction执行效率

2.14 Compaction优化

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

hbase.hstore.compaction.max控制一次Compaction操作时的文件数据量的最大值。

hbase.hstore.compaction.max.size如果一个HFile文件的大小大于该值,那么在Minor Compaction操作中不会选择这个文件进行Compaction操作,除非进行Major Compaction操作。这个值可以防止较大的HFile参与Compaction操作。在禁止Major Compaction后,一个Store中可能存在几个HFile,而不会合并成为一个HFile,这样不会对数据读取造成太大的性能影响。

原则是:尽量要减小Compaction的次数和Compaction的执行时间

三、架构优化

3.1 异构存储

HBase 资源隔离 + 异构存储。SATA 磁盘的随机 iops 能力,单次访问的 RT,读写吞吐上都远远不如 SSD,那么对 RT 极其敏感业务来说,SATA 盘并不能胜任,所以我们需要 HBase 有支持 SSD 存储介质的能力。

为了 HBase 可以支持异构存储,首先在 HDFS 层面就需要做响应的支持,在 HDFS 2.6.x 以及之后的版本,提供了对 SSD 上存储文件的能力,换句话说在一个 HDFS 集群上可以有 SSD 和 SATA 磁盘并存,对应到 HDFS 存储格式为 [ssd] 与 [disk]。然而 HBase 1.2.6 上并不能对表的列族和 RegionServer 的 WAL 上设置其存储格式为 [ssd], 该功能在社区 HBase 2.0 版本之后才开放出来,所以我们从社区 backport 了对应的 patch ,打到了我们有赞自己的 HBase 版本之上。支持 [ssd] 的 社区 issue 如下:

https://issues.apache.org/jira/browse/HBASE-14061?jql=text ~ “storage policy” 。

添加 SSD 磁盘之后,HDFS 集群存储架构示意图如下图所示:


理想的混合机型集群异构部署,对于 HBase 层面来看,文件存储可选三种策略:HOT, ONE_SSD, ALL_SSD, 其中 ONE_SSD 存储策略既可以把三个副本中的两个存储到便宜的 SATA 磁盘介质之上来减少 SSD 磁盘存储成本的开销,同时在数据读取访问本地 SSD 磁盘上的数据可以获得理想的 RT ,是一个十分理想的存储策略。HOT 存储策略与不引入异构存储时的存储情况没有区别,而 ALL_SSD 将所有副本都存储到 SSD 磁盘上。 在有赞我们目前没有这样的理想混合机型,只有纯 SATA 与 纯 SSD 两种大数据机型,这样的机型对应的架构与之前会有所区别,存储架构示意图如下图所示。

基于这样的场景,我们做了如下规划:

  • 将 SSD 机器规划成独立的组,分组的 RegionServer 配置 hbase.wal.storage.policy=ONE_SSD,保证 wal 本身的本地化率;
  • 将 SSD 分组内的表配置成 ONE_SSD 或者 ALL_SSD;
  • 非 SSD 分组内的表存储策略使用默认的 HOT

具体的配置策略如下:在 hdfs-site.xml 中修改

<property>      
    <name>dfs.datanode.data.dir</name>      
    <value>[SSD]file:/path/to/dfs/dn1</value> 
</property>

在 SSD 机型 的 RegionServer 中的 hbase-site.xml 中修改

<property>      
    <name>hbase.wal.storage.policy</name>      
    <value>ONE_SSD</value> 
</property>

其中 ONE_SSD 也可以替代为 ALL_SSD。 SATA 机型的 RegionServer 则不需要修改或者改为 HOT。

3.2 HDFS 短路读

开启 HDFS 的短路读模式。该特性由 HDFS-2246 引入。我们集群的 RegionServer 与 DataNode 混布,这样的好处是数据有本地化率的保证,数据第一个副本会优先写本地的 Datanode。在不开启短路读的时候,即使读取本地的 DataNode 节点上的数据,也需要发送 RPC 请求,经过层层处理最后返回数据,而短路读的实现原理是客户端向 DataNode 请求数据时,DataNode 会打开文件和校验和文件,将两个文件的描述符直接传递给客户端,而不是将路径传递给客户端。客户端收到两个文件的描述符之后,直接打开文件读取数据,该特性是通过 UNIX Domain Socket 进程间通信方式实现。

该特性内部实现比较复杂,设计到共享内存段通过 slot 放置副本的状态与计数,这里不再详细展开。

开启短路读需要修改 hdfs-site.xml 文件:

<property>        
    <name>dfs.client.read.shortcircuit</name>        
    <value>true</value>    
</property>    
<property>        
    <name>dfs.domain.socket.path</name>         
    value>/var/run/hadoop/dn.socket</value>    
</property>

3.3 HDFS Hedged Read

开启 Hedged Read 模式。当我们通过短路读读取本地数据因为磁盘抖动或其他原因读取数据一段时间内没有返回,去向其他 DataNode 发送相同的数据请求,先返回的数据为准,后到的数据抛弃,这也可以减少磁盘毛刺带来的影响。默认该功能关闭,在 HBase 中使用此功能需要修改 hbase-site.xml

<property>       
    <name>dfs.client.hedged.read.threadpool.size</name>       
    <value>50</value>     
</property>    

<property>       
    <name>dfs.client.hedged.read.threshold.millis</name>       
    <value>100</value>    
</property>

线程池大小可以与读 handler 的数目相同,而超时阈值不适宜调整的太小,否则会对集群和客户端都增加压力。同时可以通过 Hadoop 监控查看 hedgedReadOps 与 hedgedReadOps 两个指标项,查看启用 Hedged read 的效果,前者表示发生了 Hedged read 的次数,后者表示 Hedged read 比原生读要快的次数。

3.4 高可用读

HBase 是一个 CP 系统,同一个 region 同一时刻只有一个 regionserver 提供读写服务,这保证了数据的一致性,即不存在多副本同步的问题。但是如果一台 regionserver 发声宕机的时候,系统需要一定的故障恢复时间 deltaT, 这个 deltaT 时间内,region 是不提供服务的。这个 deltaT 时间主要由宕机恢复中需要回放的 log 的数目决定。

HBase 提供了 HBase Replication 机制,用来实现集群间单方向的异步数据复制我们线上部署了双集群,备集群 SSD 分组和主集群 SSD 分组有相同的配置。当主集群因为磁盘,网络,或者其他业务突发流量影响导致某些 RegionServer 甚至集群不可用的时候,就需要提供备集群继续提供服务,备集群的数据可能会因为 HBase Replication 机制的延迟,相比主集群的数据是滞后的,按照集群目前的规模统计,平均延迟在 100ms 以内。所以为了达到高可用,放弃了强一致性,选择了最终一致性和高可用性,在第一版采用的方案如下:

在客户端层面,他们只希望一个 Put 或者 Get 请求正常送达且返回预期的数据即可,那么就需要高可用客户端封装一层降级,熔断处理的逻辑,这里我们采用 Hystrix 做为底层熔断处理引擎,在引擎之上封装了 HBase 的基本 API,用户只需要配置主备机房的 ZK 地址即可,所有的降级熔断逻辑最终封装到 ha-hbase-client 中,原理类似上图。

参考:
https://blog.csdn.net/weixin_42011858/article/details/129410514

https://blog.csdn.net/qq_33208851/article/details/105341196

https://blog.csdn.net/asd136912/article/details/101168177

相关文章

网友评论

      本文标题:HBase——性能调优

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