互联网技术 / 互联网资讯 · 2024年3月19日

线上 Hbase 问题分析与解决案例

大家好,欢迎阅读本篇文章。本篇回顾一次 hbase 线上问题的分析与解决,聚焦 KeyValue size too laRge 的原因与解决方法,并分享查看开源组件不同版本差异点的方法。

希望各位有所收获,感谢关注!

01 Hbase 简介

Hbase 作为 Hadoop 生态中的一个数据库组件,是开源、分布式、可扩展的非关系型数据库管理系统,面向大数据场景,具备多版本和实时读写能力,是 Google Bigtable 的 Java 版开源实现。

Hbase 的底层存储引擎基于 HDFS,可以在普通商用服务器硬件上提供对超大表的随机实时读写访问,表的数据规模可达到百万行级别甚至更大。

Hbase 具有以下特征:模块化的线性扩展性、强一致性并发读写支持、可配置的表自动分区、RegionServer 之间的自动故障转移、基于 Block Cache 和 Bloom 过滤器的实时读取、基于服务器端过滤器的查询谓词下推。

凭借上述特征,Hbase 在各行业有广泛的线上应用,常用于需要大量稀疏列且需要实时并发读写的场景,例如车联网等领域的应用实践。

题外话:

Nosql 数据库常见的几大类及典型代表包括:Hbase、Elasticsearch、MongoDB 等。

有趣的现象是,国内用户对 Hbase 的使用较多,国外则在 Cassandra 等产品上更活跃一些。

02 一次线上 Hbase 问题的现象

某线上应用通过 Hive 映射表到 HBase,在使用 InseRt OverRwRite 将数据从 Hive 查询后插入 HBase 时,出现错误。

结合 Hive 背后 YARN 作业的日志,主要错误信息为 java.lang.IllegalArgumentException: KeyValue size too laRge。相关报错片段及日志如下:

记录一次 Hbase 线上问题的分析和解决

2020-04-08 09:34:38,120 Error MAIn ExecReducer: org.apache.hadoop.hive.ql.Metadata.HiveException: Hive Runtime Error While Processing Row (tag=0) {“key”:{“_col0″:”0″,”_col1″:””,”_col2″:”2020-04-08″,”_col3″:”joYshebaoBeiJing”,”_col4″:”105″,”_col5″:”北京,”},”value”:null}

Caused by: org.apache.hadoop.hive.ql.Metadata.HiveException: java.lang.IllegalArgumentException: KeyValue size too laRge

03 该线上问题的原因

上述作业日志信息较为详细,具体为:Caused by: java.lang.IllegalArgumentException: KeyValue size too laRge at org.apache.hadoop.hbase.client.HTable.validatePut(HTable.java:1577);

该错误来自 HBase 客户端对待插入数据的校验,显示单条 KeyValue 的大小超出限制。KeyValue 是 HBase 存储结构的基本单位,通常对应大宽表中某行某列。KeyValue 内部包括 RowKey、CF(ColumnFamily)、CQ(ColumnQualifier)、Timestamp、Value 等字段,详细内容可参考官方文档,以下示例为示意截图:

记录一次 Hbase 线上问题的分析和解决

04 不同 HBase 版本相关的参数扩展知识

HBase 作为成熟的 NoSQL 数据库,存在多个版本:0.98;1.2.x(1.4.x 之前版本也较常见);2.1.x/2.4.x;3.0.0-alpha-1 等。针对“KeyValue size too laRge”问题,不同版本引入了不同的配置项:

在 1.4 及更高版本之前,只有客户端参数 hbase.client.keyvalue.Maxsize;在 1.4 及以后的版本,除了该客户端参数外,还增加了服务端参数 hbase.server.keyvalue.Maxsize。

通过对比不同版本的源码与官方文档,可以确认并证实这一点,相关讨论与截图见下列示例:

记录一次 Hbase 线上问题的分析和解决

记录一次 Hbase 线上问题的分析和解决

记录一次 Hbase 线上问题的分析和解决

在 JIRA 的描述中也有明确记录:

HBASE-18043:为了服务保护,应在服务端设置对单个单元格大小的硬性限制,客户端仍保留检查,但不能完全依赖客户端限制,以避免 RPC 拒绝导致的不可预知性。同时,客户端和服务端的默认配置应保持一致,变更服务端参数后需重启服务端,变更客户端参数则不一定需要重启。

因此,不同版本在遇到该问题时,主要可能出现两种情况:情况一是 KeyValue size too laRge;情况二是 Cell With size 25000046 exceeds limit of 10485760 bytes

错误原因简述:情况一是未配置客户端参数 hbase.client.keyvalue.Maxsize,且实际待插入的 KeyValue 大小超过默认上限;情况二是客户端已放宽了该参数,但未同步放宽服务端参数,导致实际数据大小介于两者之间而产生错误。

一次日志示例(情况二):Exception in thread “MAIN” org.apache.hadoop.hbase.DoNotRetryIOException: Cell with size 25000046 exceeds limit of 10485760 bytes at org.apache.hadoop.hbase.RegionServer.RSRPCServices.checkCellSizeLimit(RSRPCServices.java:944)

报错现场截图:

记录一次 Hbase 线上问题的分析和解决

05 解决思路与方案

在确认待插入的数据没有异常且确实需要提升 KeyValue 限制后,常用的解决方法包括:

方法一:修改配置文件 hbase-site.xml,增大客户端参数 hbase.client.keyvalue.Maxsize 的值;

方法二:若使用了 HBase JAVA API,改为通过 Configuration 对象修改默认配置,例如:Configuration conf = HBaseConfiguration.create(); conf.set(“hbase.client.keyvalue.Maxsize”, “20971520”);

方法三:若通过 Hive 进行操作,可以在客户端覆盖该参数,例如在 Hive SQL 中设置 set hbase.client.keyvalue.Maxsize=0; 说明:客户端参数与服务端参数的默认值通常保持一致;修改服务端参数后需要重启服务端,修改客户端参数则不一定需要。以下是 CDH 环境的配置示例截图:

记录一次 Hbase 线上问题的分析和解决

06 该问题的技术背景与原理要点

HBase 内部通过 KeyValue 结构存储表数据,单个 KeyValue 的大小包含 RowKey、CF、CQ、Timestamp、Value 等字段。在执行 PUT 时,系统会逐个检查每个列(cell)的大小,一旦超过 MaxKeyValueSize,就会抛出异常并拒绝写入。

与 KeyValue 大小相关的参数在版本演进中有所变化:在 1.4 及以前版本,只有客户端参数 hbase.client.keyvalue.Maxsize;在 1.4 及以后版本,除了客户端参数,还新增了服务端参数 hbase.server.keyvalue.Maxsize。之所以有限制,是因为 HBase 需要在基于 HDFS 的存储引擎之上提供实时读写能力,涉及内存缓存、异步刷写、以及与 WAL 日志相关的机制,因此需要对单个 KeyValue 的大小进行控制以确保稳定性与容错能力。一般来说,集群级别的默认配置应保持一致,且在变更时需要考虑重启影响与客户端差异性配置的允许范围。