如代码所示使用Filesystem读文件目录,发现线上读取一个36万个文件的本地目录,任务卡住30分钟都没结束,冷汗下来了...
看线程栈位置在it.hasNext()位置,加日志看到一直有读取,大概每读1000个文件要8秒左右。改为listStatus然后自己实现递归读取,每1000个文件100多毫秒就能读完,看源码好像是listLocatedStatus和listStatus的区别,难道这个RemoteIterator迭代器成本很高吗
RemoteIterator<LocatedFileStatus> it = fs.listFiles(filePath, true);
while (it.hasNext()) {
fileList.add(it.next().getPath().toString().replace(replacedValue, ""));
}
谜底就在谜面上,程序逻辑本意是读一下fileStatus,记录status的文件路径,但断点发现实际还去扫描了文件内容!
从线程堆栈上看到LocatedFileStatus有一些额外的操作,通过shell来读取文件系统权限相关信息,而这个在fileStatus中是没有的:
public LocatedFileStatus(FileStatus stat, BlockLocation[] locations)
throws IOException {
this(stat.getLen(), stat.isDirectory(), stat.getReplication(),
stat.getBlockSize(), stat.getModificationTime(),
stat.getAccessTime(), stat.getPermission(), stat.getOwner(),
stat.getGroup(), null, stat.getPath(), locations);
if (stat.isSymlink()) {
setSymlink(stat.getSymlink());
}
}
继续往下看stat.getPermission():
一开始没注意这里应该看具体的实现,而不是这个抽象类
@Override
public FsPermission getPermission() {
if (!isPermissionLoaded()) {
loadPermissionInfo();
}
return super.getPermission();
}
上面可以发现loadPermissionInfo会去读文件,这个确实很伤!