Flink生产问题排障-HBase NotServingRegionException

一、背景与问题

在实时计算场景中,Flink 常通过 HBase Connector 与 HBase 进行数据交互,用于维表关联、结果写入等业务场景。HBase 作为分布式列存储数据库,其数据按 Region 划分并分布在不同 RegionServer 上,HBase 的 region 是数据分布和负载均衡的基本单元,随着数据写入或运维操作,region 会分裂、合并或迁移。为了提升元数据访问效率,HBase 客户端会缓存 meta 表的路由信息(即 MetaCache),避免每次请求都查询 meta 表。

去年我们完成了Flink版本的升级(1.14->1.16)与任务迁移,在迁移初期,我们收到用户反馈有部分Flink任务总是在凌晨2-4点间失败,重新拉起又恢复正常,异常时间很有规律。

二、问题排查

1.排查失败的任务日志发现,任务失败停止前,TM日志均报错org.apache.hadoop.hbase.NotServingRegionException,同时伴随 Unable to load exception received from server的异常跟随日志(截图不清晰,看看大概轮廓)。

2.查看任务失败时间段的运行指标监控,除了重启次数、lag延迟等引发的结果现象,其他无明显异常。

3.与用户沟通Flink任务的处理逻辑与使用场景,了解到这些任务都使用了到了 HBase 维表,且这些HBase表每天凌晨2-4点会通过跑批任务进行全量刷新(overwrite 逻辑),即删除前一天的 表region 并生成新的 表region。通过日志发现,任务失败的时间点与每天定时跑批、清理旧 表Region 的时间点高度吻合。

4.详细排查Flink容错重试的几次NotServingRegionException日志发现,在HBase表数据每天跑批全量更新后,FLink任务重试几次仍然不断地去请求HBase表的旧RegionId,而没有刷新cache重新查询meta表元数据。基于上述排查现象,此问题初步判断是 HBase 客户端的 Meta 缓存未及时更新,导致访问了已失效的 Region,直至Flink任务重试失败停止。

三、问题分析

1.HBase客户端MetaCache机制分析:HBase 客户端在建立 Connection时会缓存 meta 表中的 region 信息,存储在 MetaCache中,这个缓存默认不会主动过期,只有当客户端收到某些特定异常(如 NotServingRegionException)时,才会触发缓存刷新并重试请求。

2.HBase客户端异常处理分析:当服务端返回 NotServingRegionException时,客户端本应触发缓存刷新逻辑,但日志显示并未执行,而是直接抛出了 DoNotRetryIOException。进一步检查客户端对服务端返回异常的处理逻辑。在 ConnectionImplementation中,有一个方法用于将服务端抛出的远程异常转换为本地异常,如下图: 服务端返回的异常类型名称为 org.apache.hadoop.hbase.NotServingRegionException。客户端尝试用 Class.forName加载这个类,如果失败则捕获 ClassNotFoundException,最终包装成 DoNotRetryIOException抛出。DoNotRetryIOException是一个不可重试异常,客户端收到后会直接失败,不会刷新 MetaCache。

3.ClassNotFoundException分析:在 Flink 任务中使用的是 Flink 官方提供的 HBase Connector,该 Connector 为了避免与 Hadoop/HBase 客户端产生依赖冲突,对 HBase 客户端进行了 relocation(包重定向)。原本的 org.apache.hadoop.hbase包被 shade 成了 org.apache.flink.hbase.shaded.org.apache.hadoop.hbase。因此,当客户端尝试加载原始类名 org.apache.hadoop.hbase.NotServingRegionException时,自然找不到,抛出 ClassNotFoundException。任务日志中确实打印了 "Unable to load exception received from server" ,刚好印证了这一推断。

四、解决方案

问题的核心是客户端在运行时无法加载到服务端返回的异常类,最简单的办法就是让 Flink 任务的 classpath 中包含原始的 HBase 客户端类,我们正是采用这种办法,添加后经过数据测试验证,客户端能够成功加载原始异常类,进入正常的重试逻辑,MetaCache 得以刷新,任务恢复稳定。

另外,为避免包冲突的潜在隐患,提升整体Flink任务的健壮性,我们同时制定了以下长期优化方案:

1.缓存主动刷新:在 Flink 任务中,定期调用 HBase 客户端的 clearMetaCache()方法,主动清空缓存,强制从 Meta 表拉取最新 Region 信息。

2.HBase批量卸数优化:将全量卸数调整为增量卸数,避免阻塞HBase表数据请求服务。

3.HBase-connector源码二开:优化完善客户端异常处理逻辑、优化shade配置等,完成定制化优化。

五、总结

在 Flink 与外部系统(如 Kafka、HDFS、Redis)交互的场景中,都可能遇到因依赖冲突、缓存失效或异常处理不当导致的问题,我们要从现象入手,结合日志监控和组件技术原理,必要时配合源码分析,层层递进定位到根因,才能知其然知其所以然,达到自主掌控。

相关推荐
2501_942389556 小时前
为支撑持续攀升的AI资本开支
人工智能·oracle·hbase·database·storm
abcy0712131 天前
spark核心组件
flink·spark
翔云1234563 天前
Kafka + Flink实时时流处理场景
flink·kafka
abcy0712134 天前
flink state实例
大数据·算法·flink
Flink_China4 天前
抖音集团基于Paimon的流式数据湖应用实践
大数据·flink
abcy0712134 天前
flink 对齐与非对齐,窗口,状态state原理详解
大数据·flink
大大大大晴天️4 天前
Flink DataStream API 进阶使用与避坑指南
大数据·flink
abcy0712135 天前
flink Task Slots and Resources详解
flink
大大大大晴天6 天前
Flink DataStream API多流操作与实践
flink
2601_960906727 天前
网络防御等最先进AI模型领域
人工智能·json·hbase·flume·storm