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