hadoop.fs.FileSystem.get导致OOM的原因和解决方案

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

问题描述

在调用HDFS获取文件系统的get接口时指定用户可能会导致OOM问题示例代码如下

FileSystem fileSystem = FileSystem.get(uri, conf, "hadoopuser");

问题溯源

该方法源码
在这里插入图片描述
在有缓存的情况下将从Cache中取一路取下去最后会从map中根据key取内容
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
但如果指定了user此处根据key只能取到空值
原因
如下图所示Cache的map的Key中包括了UserGroupInformation ugi上述拿值时候会以此类型作为Key在这里插入图片描述回到指定用户名时最初调用的get方法源码如下

  public static FileSystem get(final URI uri, final Configuration conf,
        final String user) throws IOException, InterruptedException {
    String ticketCachePath =
      conf.get(CommonConfigurationKeys.KERBEROS_TICKET_CACHE_PATH);
    //进入getBestUGI查看一下源码
    UserGroupInformation ugi =
        UserGroupInformation.getBestUGI(ticketCachePath, user);
    return ugi.doAs(new PrivilegedExceptionAction<FileSystem>() {
      @Override
      public FileSystem run() throws IOException {
        return get(uri, conf);
      }
    });
  }

getBestUGI查看源码

  public static UserGroupInformation getBestUGI(
      String ticketCachePath, String user) throws IOException {
    if (ticketCachePath != null) {
      return getUGIFromTicketCache(ticketCachePath, user);
    } else if (user == null) {
      return getCurrentUser();
    } else {
    //注意这一句查看一下源码
      return createRemoteUser(user);
    }    
  }

createRemoteUser源码

@InterfaceAudience.Public
  @InterfaceStability.Evolving
  public static UserGroupInformation createRemoteUser(String user, AuthMethod authMethod) {
    if (user == null || user.isEmpty()) {
      throw new IllegalArgumentException("Null user");
    }
    //此处subject一直是新的
    Subject subject = new Subject();
    subject.getPrincipals().add(new User(user));
    UserGroupInformation result = new UserGroupInformation(subject);
    result.setAuthenticationMethod(authMethod);
    return result;
  }

可以看出在指定了用户名的情况下一直会新建subject那么如何判断两个key是否相等呢查看一下Cache重写的hashCode方法

 public int hashCode() {
        return (scheme + authority).hashCode() + ugi.hashCode() + (int)unique;
      }

可以看出在判断两个Key值是否一致时会判断ugi的hashCode是否一致其中ugi.hashCode代码如下又能够看出判断ugi的hashCode是否一致会去判断subject的hashCode是否一致而上面说过的调用createRemoteUser每次都会新建一个subject这也就导致了这两个Key值永远是不同的用这个Key值取也一定是取不到值的

public int hashCode() {
    return System.identityHashCode(subject);
  }

在取不到值的情况下getInternal中的下列语句就会一直被执行到

 map.put(key, fs);

最终导致OOM

解决方法

自己定义一个map缓存,调用FileSystem.newInstance,不使用FileSystem的cache

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Hadoop