前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >flink on yarn的一则jar冲突问题,你遇到过没?

flink on yarn的一则jar冲突问题,你遇到过没?

作者头像
山行AI
发布2021-08-18 10:49:07
1.5K0
发布2021-08-18 10:49:07
举报
文章被收录于专栏:山行AI山行AI

有人说,没遇到过jar包冲突问题都不好意思说自己用过hadoop。那么,你遇到过没?最近使用flink on yarn提交任务时遇到过一则jar冲突问题,整个分析过程还挺有意思的,记录一下。

背景

近期准备对实时计算平台进行升级,调研阶段使用yarn client手动向yarn集群上提交flink任务时出现了一个小插曲。提交任务时,一直提示失败,来yarn的web控制台发现日志有报错信息,错误如下:

代码语言:javascript
复制
Caused by: org.apache.flink.runtime.resourcemanager.exceptions.ResourceManagerException: Cannot initialize resource provider.
    at org.apache.flink.runtime.resourcemanager.active.ActiveResourceManager.initialize(ActiveResourceManager.java:124)
    at org.apache.flink.runtime.resourcemanager.ResourceManager.startResourceManagerServices(ResourceManager.java:245)
    at org.apache.flink.runtime.resourcemanager.ResourceManager.onStart(ResourceManager.java:229)
    ... 20 more
Caused by: org.apache.hadoop.yarn.exceptions.YarnRuntimeException: yarn.client.max-nodemanagers-proxies (0) can not be less than 1.
    at org.apache.hadoop.yarn.client.api.impl.ContainerManagementProtocolProxy.<init>(ContainerManagementProtocolProxy.java:74)
    at org.apache.hadoop.yarn.client.api.impl.NMClientImpl.serviceInit(NMClientImpl.java:136)
    at org.apache.hadoop.service.AbstractService.init(AbstractService.java:163)
    at org.apache.hadoop.yarn.client.api.async.impl.NMClientAsyncImpl.serviceInit(NMClientAsyncImpl.java:109)
    at org.apache.hadoop.service.AbstractService.init(AbstractService.java:163)
    at org.apache.flink.yarn.YarnResourceManagerDriver.initializeInternal(YarnResourceManagerDriver.java:186)
    at org.apache.flink.runtime.resourcemanager.active.AbstractResourceManagerDriver.initialize(AbstractResourceManagerDriver.java:81)
    at org.apache.flink.runtime.resourcemanager.active.ActiveResourceManager.initialize(ActiveResourceManager.java:122)
    ... 22 more

从报错信息中能清晰地看到,这是一个yarn参数的配置问题。要求yarn.client.max-nodemanagers-proxies的值不能小于1,而它的实际传入值为0,于是yarn Client在进行任务提交时初始化resource manager时抛出了异常。它的实际代码位置位于org.apache.hadoop.yarn.client.api.impl.ContainerManagementProtocolProxy中,查看了一下当前版本的ContainerManagementProtocolProxy中具体代码逻辑如下:

hadoop-yarn-client-2.4.1是flink-yarn的默认依赖,在这里会进行yarn.client.max-nodemanagers-proxies的配置检查,这个默值的值不能小于1,否则会抛出异常。如果没有手动配置过这个值,这里会使用500作为默认值。显然,我们没有对这个参数进行手动配置,那么为什么没有用500作为默认值呢?下面我们来分析一下。

分析

首先在实时计算平台使用yarn client进行任务提交时从来没有出现过这个异常,但是在这里使用yarn client手动提交时却出现了异常,这是什么原因呢?

首先想到的就是hadoop的版本依赖问题,从经验上来说这是最容易出问题的地方。

检查依赖版本

1.首先来查看实时计算平台上hadoop-yarn-client的依赖版本,查看后发现版本也是2.4.1,并无差异。2.由于两个地方都没有对yarn.client.max-nodemanagers-proxies进行手动配置,而上面从YarnConfiguration中获取yarn.client.max-nodemanagers-proxies的值时取到的不为空,导致默认填充值500没有生效,那么会不会是两个地方使用的YarnConfiguration中获取的值不同呢?于是添加日志打印输出(此处忽略这个过程),发现也并无差异。3.先是有点不太能理解了,转念一想,是不是使用了不同版本的YarnConfiguration,不同版本的有不同实现呢?查看一遍,果然如此。实时计算平台上使用的是2.4.1版本的YarnConfiguration,手动提交时使用的是2.7.4版本的YarnConfiguration。

具体原因分析

YarnConfiguration#getInt方法实际上继承自父类org.apache.hadoop.conf.Configuration#getInt方法,我们直接来看org.apache.hadoop.conf.Configuration#getInt方法的具体实现,代码如下:

代码语言:javascript
复制
  public int getInt(String name, int defaultValue) {
    String valueString = getTrimmed(name);
    if (valueString == null)
      return defaultValue;
    String hexString = getHexDigits(valueString);
    if (hexString != null) {
      return Integer.parseInt(hexString, 16);
    }
    return Integer.parseInt(valueString);
  }

这个方法的大致逻辑是先去配置上下文中获取指定的key对应的配置值,如果没有配置的话则返回默认值。简单一看,好像并无大问题。我们进入到getTrimmed方法来看:

代码语言:javascript
复制
  public String getTrimmed(String name) {
    String value = get(name);
    if (null == value) {
      return null;
    } else {
      return value.trim();
    }
  }

这个方法的注释简单翻译一下,大概是这样子的:该方法用于获取name属性对应的值,如果不存在该属性则为空。如果该key已弃用,它将返回取代已弃用的key所对应的那个key所对应的值。这个逻辑要进入到get(name)方法来看才比较清晰:

代码语言:javascript
复制
  public String get(String name) {
    String[] names = handleDeprecation(deprecationContext.get(), name);
    String result = null;
    for(String n : names) {
      result = substituteVars(getProps().getProperty(n));
    }
    return result;
  }

在handleDeprecation方法内部会先查找当前需要查找的key是不是在被废弃上下文列表中,如果不在列表中但直接返回原始key值;如果在废弃列表中,则返回代替废弃key的新key。

这也就是说,如果我们查看一下yarn.client.max-nodemanagers-proxies参数在2.4.1和2.7.4两个版本中的差异就能找到为啥都没有配置该参数的情况下,一个会为空进而使用默认值,另一个不为空而没有使用默认值的原因了。

版本差异分析

我们先来看一下org.apache.hadoop.conf.Configuration#deprecationContext属性值:

它默认初始化的是defaultDeprecations数组中的一些废弃参数与新的替代参数的映射,另外其他地方可以调用addDeprecations方法来添加新的映射值。

我们直接来看2.7.4版本的YarnConfiguration:

可以清楚地看到,它会向defaultDeprecations数组中添加一组新的映射值,即废弃掉yarn.client.max-nodemanagers-proxies,用yarn.client.max-cached-nodemanagers-proxies代替,而且对新参数的默认值也有设置:

也就是说在都没有配置yarn.client.max-nodemanagers-proxies时,使用2.7.4版本的YarnConfiguration来获取yarn.client.max-nodemanagers-proxies值会返回yarn.client.max-cached-nodemanagers-proxies的值0;而使用2.4.1版本的YarnConfiguration时返回为null会在2.4.1版本的ContainerManagementProtocolProxy中使用默认值500。

当然在2.7.4版本的ContainerManagementProtocolProxy中已经做了新老key值的逻辑替换:

总结

归其原因是因为手动提交时使用的hadoop依赖不一致,使用了2.4.1版本的hadoop-yarn-api(ContainerManagementProtocolProxy依赖)却使用了2.7.4版本的hadoop-common(YarnConfiguration在这个依赖包中)。2.7.4为较新的版本,其YarnConfiguration中将yarn.client.max-nodemanagers-proxies纳入了废弃参数,并会用yarn.client.max-cached-nodemanagers-proxies(0)代替,而在2.4.1版本的ContainerManagementProtocolProxy中去获取该参数时就会取到0,从而触发异常。

解决办法也很简单,全部用2.4.1版本的hadoop依赖或者全部用2.7.4版本的依赖。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开发架构二三事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 分析
    • 检查依赖版本
      • 具体原因分析
        • 版本差异分析
        • 总结
        相关产品与服务
        流计算 Oceanus
        流计算 Oceanus 是大数据产品生态体系的实时化分析利器,是基于 Apache Flink 构建的企业级实时大数据分析平台,具备一站开发、无缝连接、亚秒延时、低廉成本、安全稳定等特点。流计算 Oceanus 以实现企业数据价值最大化为目标,加速企业实时化数字化的建设进程。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档