Hbase 线上集群 OutOfMemory 性能优化

线上HBase集群在大数据写入时频繁遭遇OutOfMemory错误。通过了解HBase数据存储机制和compaction机制,针对磁盘IO和内存写入性能进行参数优化,包括调整`hbase.regionserver.handler.count`、`hbase.client.write.buffer`等。增加RegionServer节点数量至10台,关闭自动Major Compaction,改为手动触发,并结合业务层面对写入流量进行管控,有效降低了OutofMemory错误的发生。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线上状况

服务器信息

本人使用的各组件版本如下:
操作系统版本:centos7
CM版本:6.3.1
CDH版本:6.3.2(5.16.2版本实测也可以)
JDK版本:openjdk version “1.8.0_262”

服务器配置:

服务器CPU内存磁盘
cmserver8核24G/home/app 挂载300G
master014核24G/home/app 挂载300G
master024核24G/home/app 挂载300G
slave014核24G/home/hdfsdata/data1 挂载50T
slave024核24G/home/hdfsdata/data1 挂载50T
slave034核24G/home/hdfsdata/data1 挂载50T
slave044核24G/home/hdfsdata/data1 挂载50T

注意:salve节点合理的内存配置是32G,这里写的24G是参数调整之前的配置。

线上的hbase集群运行时发现,当数据量写入比较大时,经常会报:OutOfMemory errors 的错误
报错截图如下:
在这里插入图片描述

报错时的集群负载情况如下:
HDFS写入情况如下,集群连续几天处于高负荷状态,每个DataNode平均读写总量约为200M/s。
在这里插入图片描述

集群网络IO情况如下,各网络接口中的总传送的字节数约为187M/s,各网络接口中的总接收的字节数约为232M/s。
在这里插入图片描述

可以看到,一天时间内,RegionServer 多次因内存不足而退出。
在这里插入图片描述

各RegionServer 的web响应时间如下,从图中可以看出响应时间有一定的波动,并且跟上图 RegionServer 因内存不足而退出在时间上是相对应的,当发生因内存不足而退出时,web响应时间也变的很高,会导致客户度读写超时。
在这里插入图片描述

Region Server占用的内存如下,基本稳定在4G左右,因为配置的最大内存就是4G。在发生因内存不足而退出的时间点上,驻留内存会有一些的降低。
在这里插入图片描述

hbase数据存储机制

要对HBASE集群进行调优之前,需要先了解HBASE的数据存储机制。

hbase compaction机制

hbase compaction参考文章:
https://blog.csdn.net/u011598442/article/details/90632702

Compaction机制的由来
HBase基于LSM-Tree(Log-Structured Merge Tree)存储模型,写入数据时是先写入WAL(Write-Ahead-Log)即预写日志,再写入Memstore缓存,满足一定条件后执行flush操作将缓存数据吸入到磁盘,每次flush就会生成一个HFile数据文件。HFile文件数过多会导致查询的数据来源分散到很多不同的HFile中,增加了查询数据的IO次数,影响HBase查询性能。因此HBASE设计了Compaction机制,将小的HFile文件合并成大文件减少HFile文件数量,来提高查询性能。

hbase compaction原理图:
在这里插入图片描述

Compaction分类

  • Mini Compaction
    选取一些小的、相邻的HFile将他们合并成一个更大的HFile。minor compaction会删除选取HFile中的TTL过期的数据。

  • Major Compaction
    将一个Store中所有HFile合并成一个HFile。major compaction会清理被删除的数据、TTL过期的数据、版本号超过设定版本号的数据。
    Major Compaction持续时间较长,并消耗大量系统资源,生产环境建议关闭自动触发Major Compaction,改为在业务低峰期手动触发。

Compaction触发条件

  • MemStore Flush
    每次MemStore Flush都会产生HFile文件,当HFile文件数超过 hbase.hstore.compactionThreshold 设置的值,就会触发Compaction;
  • 后台线程定期检查
    默认7天触发一次Major Compaction,生产环境建议关闭自动触发Major Compaction,关闭需将参数 hbase.hregion.majorcompection置为0;
  • 手动触发
    生产环境推荐业务低峰期手动触发Major Compaction;

集群参数调优

要解决该问题需要先对 Hbase集群的参数有些了解,重要的一些参数如下:

  • hbase.regionserver.handler.count:
    regionserver上用于等待响应用户表级请求的线程数,CDH安装时的默认值是30。这个值的大小取决于每次读写的数据量大小,当请求内容很大(上MB,比如大的put、使用缓存的scans)的时候,该值设置过大则会占用过多的内存,导致频繁的GC,或者出现OutOfMemory,因此该值需要根据实际业务作判断。

  • hbase.client.write.buffer:
    写入缓冲区大小(以字节为单位),默认值为2M。较大缓冲区需要客户端和服务器中有较大内存,因为服务器将实例化已通过的写入缓冲区并进行处理,这会降低远程过程调用 (RPC) 的数量。为了估计服务器已使用内存的数量,请用值“hbase.client.write.buffer”乘以“hbase.regionserver.handler.count”。

大量数据写入阻塞相关优化

磁盘IO写入性能优化参数

  • hbase.hregion.max.filesize:
    HStoreFile 最大大小。如果列组的任意一个 HStoreFile 超过此值,则托管 HRegion 将分割成两个,默认大小是10G。region的大小与集群支持的总数据量有关系,如果总数据量小,则单个region太大,不利于并行的数据处理,如果集群需支持的总数据量比较大,region太小,则会导致region的个数过多,导致region的管理等成本过高。
    如果HBASE集群有三台Region Server服务器,每台Region Server配置12T的磁盘,数据备份3份,则每台Region Server最多存储12T的数据(有效数据只有4T,其余8T空间用于数据备份)。HStoreFile 最大大小为10G,每台Region Server最多管理1200个region。通常region的数量不要超过1000个,过多的region。如果Region Server配置的磁盘比12T更大,可以考虑调大HStoreFile 的最大大小。

  • hbase.hstore.compactionThreshold:
    HStore 压缩阈值,默认值为3。如在任意一个 HStore 中有超过此数量的 HStoreFiles,则将触发mini compaction以将所有 HStoreFiles 文件作为一个 HStoreFile 重新写入。(每次 memstore 刷新都会生成一个 HStoreFile)您可通过指定更大数量延长压缩,但压缩将运行更长时间。在压缩期间,更新无法刷新到磁盘。长时间压缩需要足够的内存,以在压缩的持续时间内记录所有更新。否则压缩期间客户端会超时。

  • hbase.regionserver.thread.compaction.small:
    RegionServer 完成Mini Compact的线程数,增大可以加快Mini compact速度,默认值为1。对于写入压力比较大的业务,可以调大到8

  • hbase.hstore.blockingStoreFiles:
    HStore 阻塞存储文件数,默认值16。如在任意 HStore 中有超过此数量的 HStoreFiles,则会阻止对此 HRegion 的数据写入更新操作,直到完成压缩或直到超过为 ‘hbase.hstore.blockingWaitTime’ 指定的值。对于写入压力比较大的业务,强烈建议调大该值,但该值越大数据读取耗时也越长,建议设置到500,避免当写入大量数据时,memstore不能及时flush,触发memstore的block,从而阻塞写操作。

内存写入性能优化参数

  • HBase RegionServer 的 Java 堆栈大小:
    Region Server java堆大小会限制memstore内存的上限,内存充足的情况下,该值要尽可能设置大一些,有条件的可以设置成10G或者以上

  • hbase.regionserver.global.memstore.upperLimit:
    RS所有memstore占用内存在总内存中的上限比例,默认值0.4。当达到该值,会从整个RS中找出最需要flush的region进行flush,直到总内存比例降至该数限制以下,并且在降至限制比例以下前将阻塞所有的写memstore的操作。如果集群写入量比较大可以调高该参数。
    一个regionserver上有一个blockcache和N个memstore,它们的大小之和必须小于heapsize(HBase RegionServer 的 Java 堆栈大小)* 0.8,否则hbase不能启动,因为仍然要留有一些内存保证其它任务的执行。因此 hbase.regionserver.global.memstore.upperLimit + hfile.block.cache.size 之和必须小于0.8,因此需要根据业务偏向于读操作还是偏向于写操作调整两者的比例。兼顾读和写的场景可以两者都设置为0.4。

  • hfile.block.cache.size:
    Region Server中的block cache的内存大小限制,默认值0.4。在偏向读的业务中,可以适当调大该值。但是该值和hbase.regionserver.global.memstore.upperLimit之和不能超过0.8。

  • hbase.hregion.memstore.block.multiplier:
    HBase Memstore 块乘法器,默认值为4。如 memstore 的内存大小超过 ‘hbase.hregion.block.memstore’ 乘以 ‘hbase.hregion.memstore.flush.size’ 字节的值,则会阻塞该Menstore的写入操作,避免大量数据写入内存导致内存溢出。同时该内存大小也受到hbase.regionserver.global.memstore.upperLimit上限的限制。内存充足的情况下建议 hbase.hregion.block.memstore 设置为8,hbase.hregion.memstore.flush.size 设置为256M。

  • hbase.hregion.memstore.flush.size:
    HBase Memstore 刷新大小,默认值128M,如果 memstore 大小超过此值,Memstore 中的数据将写入到磁盘中。该值比较适中,一般不需要调整,Region Server的jvm内存比较充足(10G以上),可以调整为256M,避免频繁触发flush,导致频繁触发compact操作

解决方案

集群调优

  1. 增大RegionServer的内存
    HBASE官方推荐的RegionServer内存大小为32G,我分配的线上服务器是24G是有点不够用的;
    官方文档地址:https://hbase.apache.org/book.html#regionserver_sizing_rules_of_thumb
    在这里插入图片描述

  2. 单台 RegionServer 推荐的Region数量
    Region数量推荐官方建议文档:https://hbase.apache.org/book.html#regions.arch
    在这里插入图片描述
    简单来说就是,官方文档推荐每台RegionServer管理的Region数据不要超过200个,这个推荐值确实比较小,实际生产大于建议值也能运行,不过数据量写入比较大时集群会有内存溢出的风险,生产上RegionServer管理的Region数量不要超过1000个

  3. 集群参数调优
    参数调整:

# CPU处理方面调参
hbase.regionserver.handler.count=50

# 内存方面调参
# 内存充足的情况下,RegionServer 的Java堆内存要尽可能大(最好可以设置10G以上)
HBase RegionServer 的 Java 堆栈大小=13G
# 内存充足的情况下,可适当提高,避免频繁触发flush,导致频繁触发compact操作
hbase.hregion.memstore.flush.size=256M
# 在偏向写的业务中,可以适当调大该值。但是该值和hfile.block.cache.size之和不能超过0.8
hbase.regionserver.global.memstore.upperLimit=0.4
# 在偏向读的业务中,可以适当调大该值。但是该值和hbase.regionserver.global.memstore.upperLimit之和不能超过0.8
hfile.block.cache.size=0.4
# 提高HBase Memstore 块乘法器数量,避免大量数据写入时会阻塞该Menstore的写入操作
hbase.hregion.memstore.block.multiplier=8

# 增加Mini Compact的处理线程数,加快处理速度
hbase.regionserver.thread.compaction.small=8
# 降低写入阻塞的阈值
hbase.hstore.blockingStoreFiles=500
# 提高 MemStore Flush 触发compaction的阈值
#hbase.hstore.compactionThreshold=3
# 关闭自动majorCompaction,改为在业务低峰期手动触发
hbase.hregion.majorcompaction=0
  1. 增加RegionServer节点数量
    我线上部署的RegionServer节点数是4台,是不够用的,又增加到了10台。每台配备20T的磁盘空间。
    按照单台RegionServer管理1000个Region,每个Region大小为10G,数据备份数为2来计算,10台RegionServer可以存储的有效数据量为:10x1000x10G/2=5000G≈50T

  2. 关闭自动majorCompaction,改为在业务低峰期手动触发
    hbase major compaction触发脚本(需手动执行):

#!/bin/bash
source /etc/profile
sh hbase shell <<EOF
# Compact all regions in a table
major_compact 'table_name1'
major_compact 'table_name2'
EOF
  1. HBASE写入流量管控
    还需要结合业务层面对HBASE写入的流量进行控制。我是通过NGINX限流对最前端的数据上传作流量管控,并且使用线程池控制业务上处理数据的并发数两个方面来控制集群写入的流量。
    NGINX限流配置参考文章:https://blog.csdn.net/weixin_39338423/article/details/125317886

调整效果

调整后效果(这个还是不增加集群节点之后的情况)
调整后集群发生 OutOfMemory errors 的情况大幅降低,在长时间持续写入大量数据的情况下偶尔还是会有发生,此时需要增加RegionServer节点或者给RegionServer添加额外的磁盘(必须是物理磁盘,RegionServer下挂载多块物理磁盘可以增加并发写入的速度)。

调整过后的集群内存占用情况如下:
在这里插入图片描述

数据节点Region数量:
在这里插入图片描述

30天被平均每个 RegionServer 压缩队列情况:
我实际测试了,当每台数据节点服务器Region数量达到1200的时候,集群的压缩队列一直处于很高的状态。
在这里插入图片描述

平均每个 RegionServer 刷新队列情况:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值