HDP3.1.4 Hive+LLAP环境含GROUP BY的查询报TezTask返回code2异常
异常根因定位
java.lang.NoClassDefFoundError: Could not initialize class org.apache.tez.runtime.library.api.TezRuntimeConfiguration 不是类路径缺失jar导致的报错,本质是TezRuntimeConfiguration类的静态初始化块执行时抛出了异常,类加载器首次初始化失败后,会将该类标记为不可用状态,后续所有依赖该类的任务调用时,都只会抛出NoClassDefFoundError,不会展示真实的初始化异常堆栈。
两类查询的运行差异刚好对应报错触发逻辑:
- 不带GROUP BY的全表
select count(*) from balance;查询,Tez生成的DAG仅需在Map端完成行计数聚合,不需要触发Shuffle环节的OrderedPartitionedKVOutput组件加载,也就不会触发TezRuntimeConfiguration类的初始化流程,因此可正常运行 - 带GROUP BY的
select count(*),jobdate from balance group by jobdate;查询,需要按jobdate字段做分区Shuffle,Map任务启动时会初始化OrderedPartitionedKVOutput组件,直接触发TezRuntimeConfiguration类的静态块执行,一旦初始化失败,所有走到Shuffle环节的Map任务都会批量失败,和报错中9个失败任务、3万多被Kill任务的特征完全匹配。
结合现有配置,静态初始化失败的核心触发点为Tez运行时内存参数超出类初始化的校验阈值:
- 当前LLAP集群共4个节点,单LLAP daemon分配YARN容器内存35840MB,总堆内存32768MB,配置单daemon启动8个executor,单executor可分配堆内存为32768/8=4096MB
- 手动配置的
tez.runtime.io.sort.mb=1638、tez.runtime.unordered.output.buffer.size-mb=409,两个堆内缓冲区总和达2047MB,占单executor堆内存的50%。Tez 0.9.1(HDP3.1.4自带版本)的TezRuntimeConfiguration类静态块内置校验逻辑:两个缓冲区的总大小不能超过JVM可用堆的40%,否则会直接抛出参数不合法异常,导致类初始化失败。
排查与修复方案
- 提取真实初始化异常:登录运行LLAP daemon的节点,查看日志路径
/var/log/hive/llap/下对应容器的日志,搜索首次出现的ExceptionInInitializerError堆栈,可直接看到参数校验失败的具体报错信息。 - 调整Tez运行时内存参数匹配校验规则:
- 将
tez.runtime.io.sort.mb从1638调整为1228MB(约为单executor堆内存的30%) - 将
tez.runtime.unordered.output.buffer.size-mb从409调整为102MB(约为单executor堆内存的2.5%) - 两项参数总和控制在单executor堆内存的40%以内,预留足够内存给任务序列化、KV输出、框架本身的开销,满足类初始化的校验阈值要求
- 将
- 排查Tez jar包版本一致性:检查所有NodeManager节点的Tez lib路径下,是否存在版本不一致的tez-runtime-api、tez-runtime-impl jar包,HDP3.1.4默认的Tez版本为0.9.1.3.1.4.0-314,所有节点的jar包版本必须完全一致,多版本并存会导致类加载顺序异常,触发类初始化失败。
- 重启所有LLAP daemon节点:类加载器一旦将TezRuntimeConfiguration标记为初始化失败状态,仅修改配置不重启服务的话,类加载器不会重新执行静态块初始化逻辑,故障会持续存在。重启完成后执行测试查询,即可验证修复效果。
内容的提问来源于stack exchange,提问作者Arash Amani
相关产品推荐
相关产品推荐

