创建Hadoop FileSystem报`Provider org.apache.hadoop.fs.azure.NativeAzureFileSystem not a sub...

栏目: 编程工具 · 发布时间: 5年前

内容简介:为了验证一个线上问题,写了一个简单的Spark任务,在提交节点上听过报如下错误:错误的代码是这一段:

为了验证一个线上问题,写了一个简单的Spark任务,在提交节点上听过 spark-submit 命令提交任务,总是跑不起来。

报如下错误:

18/12/26 16:37:24 ERROR study.Application: error
java.util.ServiceConfigurationError: org.apache.hadoop.fs.FileSystem: Provider org.apache.hadoop.fs.azure.NativeAzureFileSystem not a subtype
        at java.util.ServiceLoader.fail(ServiceLoader.java:239)
        at java.util.ServiceLoader.access$300(ServiceLoader.java:185)
        at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:376)
        at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
        at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
        at org.apache.hadoop.fs.FileSystem.loadFileSystems(FileSystem.java:2400)
        at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2411)
        at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2428)
        at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:88)
        at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2467)
        at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2449)
        at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:367)
        at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:166)
        at com.vivo.internet.ai.platform.study.FeatureOnlineService.syncByModelMeta(FeatureOnlineService.java:105)
        at com.vivo.internet.ai.platform.study.FeatureOnlineService.syncByModelName(FeatureOnlineService.java:80)
        at com.vivo.internet.ai.platform.study.Application.run(Application.java:34)
        at com.vivo.internet.ai.platform.study.Application.main(Application.java:18)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:744)
        at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:187)
        at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:212)
        at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:126)
        at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)

错误的代码是这一段:

...
// 避免打jar包时SPI文件出现问题
Configuration cfg = new Configuration();
cfg.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");

String hiveSuccessPath = null;
try {
    // 一个特征集就是一张hive表,需要先检查特征数据是否写OK
    FileSystem fileSystem = FileSystem.get(URI.create("/hive/warehouse/dm_ads_db.db"), cfg);
    for (String featureSetPath : featureSetPathToKeys.keySet()) {
        // hdfs://footstone/hive/warehouse/dm_ads_db.db/feature_app_cn_base/dt=20180913/_SUCCESS
        hiveSuccessPath = featureSetPath + "/dt=" + dateForFeature + "/_SUCCESS";
        boolean success = fileSystem.exists(new Path(hiveSuccessPath));
        if (!success) {
            LOGGER.warn("hdfs file not exist:{}", hiveSuccessPath);
            throw new IllegalArgumentException("feature data is not ready:" + featureSetPath);
        }
    }
} catch (RuntimeException e) {
    throw e;
} catch (IOException e) {
    throw new RuntimeException("check path error:" + hiveSuccessPath, e);
}
...

就是这一句 FileSystem fileSystem = FileSystem.get(URI.create("/hive/warehouse/dm_ads_db.db"), cfg);

改成:

FileSystem fileSystem = FileSystem.get(URI.create("hdfs://footstone/hive/warehouse/dm_ads_db.db"), cfg);

或者

FileSystem fileSystem = FileSystem.get(cfg);

还是报一样的错误。

谷歌都没有任何结论。只能跟着源码看下去了。

Hadoop对文件系统进行了抽象,HDFS只是其中的一个实现。Java抽象类 org.apache.hadoop.fs.FileSystem 定义了Hadoop中一个文件系统的客户端接口,并且该抽象类允许自定义实现对应的文件系统,运行时通过 Java 的SPI机制加载相应的实现类。下面是常见的几个具体实现:

文件系统 URI schema Java实现(都在org.apache.hadoop包中) 描述
Local file fs.LocalFileSystem 使用客户端校验和的本地磁盘文件系统。使用RawLocalFileSystem表示无校验和的本地磁盘文件系统。
HDFS hdfs hdfs.DistributedFileSystem Hadoop的分布式文件系统。将HDFS设计成与MapReduce结合使用,可以实现高性能。
WebHDFS webhdfs Hdfs.web.WebHdfsFileSystem 基于HTTP的文件系统,提供对HDFS的认证读/写访问。
HAR har Hdfs.web.WebHdfsFileSystem WebHDFS的HTTPS版本
Secure WebHDFS swebhdfs fs.HarFileSystem 一个构建在其他文件系统之上用于文件存档的文件系统。Hadoop存档文件系统通常用于将HDFS中的多个文件打包成一个存档文件,以减少namenode内存的使用。使用hadoop的achive命令来创建HAR文件。
View viewfs viewfs.ViewFileSystem 针对其他Hadoop文件系统的客户端挂载表。通常用于为联邦namenode创建挂载点。
FTP ftp fs.ftp.FTPFileSystem 由FTP服务器支持的文件系统
S3 S3a fs.s3a.S3AFileSystem 由Amazon S3 支持的文件系统。替代老版本的s3n(S3)原生
Azure wasb fs.azure.NativeAzureFileSystem 由Microsoft Azure 支持的文件系统
Swift swift fs.swift.snative.SwiftNativeFileSystem 由OpenStack Swift 支持的文件系统

SPI通过 java.util.ServiceLoader 类加载 META-INF/services/ 目录下的ServiceProvider。于是解压打包的jar包(是一个大的uberjar),发现里面确实有 META-INF/services/org.apache.hadoop.fs.FileSystem 文件,打开一看,里面写了好几个实现类:

org.apache.hadoop.fs.LocalFileSystem
 org.apache.hadoop.fs.viewfs.ViewFileSystem
 org.apache.hadoop.fs.s3.S3FileSystem
 org.apache.hadoop.fs.s3native.NativeS3FileSystem
 org.apache.hadoop.fs.ftp.FTPFileSystem
 org.apache.hadoop.fs.HarFileSystem

但是呢,就没有 NativeAzureFileSystem 的声明,类路径也没有这个依赖。

而且报错的代码也很奇怪:

private static void loadFileSystems() {
  synchronized (FileSystem.class) {
    if (!FILE_SYSTEMS_LOADED) {
      ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class);
      for (FileSystem fs : serviceLoader) {
        SERVICE_FILE_SYSTEMS.put(fs.getScheme(), fs.getClass());
      }
      FILE_SYSTEMS_LOADED = true;
    }
  }
}
private S nextService() {
    if (!hasNextService())
        throw new NoSuchElementException();
    String cn = nextName;
    nextName = null;
    Class<?> c = null;
    try {
        c = Class.forName(cn, false, loader);
    } catch (ClassNotFoundException x) {
        fail(service,
             "Provider " + cn + " not found");
    }
    if (!service.isAssignableFrom(c)) {
        fail(service,
             "Provider " + cn  + " not a subtype");
    }
    try {
        S p = service.cast(c.newInstance());
        providers.put(cn, p);
        return p;
    } catch (Throwable x) {
        fail(service,
             "Provider " + cn + " could not be instantiated",
             x);
    }
    throw new Error();          // This cannot happen
}

出错的这一段:

if (!service.isAssignableFrom(c)) {
      fail(service,
           "Provider " + cn  + " not a subtype");
}

service是 org.apache.hadoop.fs.FileSystem , cn是 org.apache.hadoop.fs.azure.NativeAzureFileSystemorg.apache.hadoop.fs.azure.NativeAzureFileSystem extends org.apache.hadoop.fs.FileSystem ,所以正常来说 isAssignableFrom 这个判断应该是pass才对的。

综合判断:

1、打出来的uberjar包 META-INF/services/org.apache.hadoop.fs.FileSystem 没有 org.apache.hadoop.fs.azure.NativeAzureFileSystem 的注册,也没有 org.apache.hadoop.fs.azure.NativeAzureFileSystem 的class文件,但是forName却成功了 => Spark运行时有这个SPI注册和依赖包。 2、isAssignableFrom应该成功却失败了 => NativeAzureFileSystem是由不同的classLoader加载的。

分析那么多,怎么解决呢?对比可以正常跑的uberjar包,发现人家压根就没有 META-INF/services/org.apache.hadoop.fs.FileSystem 这个文件,继续跟踪下去,发现人家压根就没有打包spark的依赖。也就是说确实 META-INF/services/org.apache.hadoop.fs.FileSystem 就是spark-core带进去的。而且集群运行时的spark-core引进来的依赖中 META-INF/services/org.apache.hadoop.fs.FileSystem 比hadoop官方注册的FileSystem Provider要多(我们线上用的是CDH版本)。 最后把spark的依赖改成provider就可以跑通了。

<dependency>
  <groupId>org.apache.spark</groupId>
  <artifactId>spark-core_${scala.version}</artifactId>
  <version>${spark.version}</version>
  <scope>provided</scope>
</dependency>

时间关系,我没有找一下 arthas 查看一下类加载信息。留给感兴趣的同学。


以上所述就是小编给大家介绍的《创建Hadoop FileSystem报`Provider org.apache.hadoop.fs.azure.NativeAzureFileSystem not a sub...》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

ME2.0

ME2.0

丹·斯柯伯尔 / 2011-11 / 36.00元

《Me2.0个人品牌崛起E时代》,本书介绍在信息技术飞速发展的今天,如何使用网络来营建个人形象,建立关系网,谋求理想的工作,完成商务交易。成功学与今天的网络通讯相结合,smart 原则与SWOT分析,视频网站、博客、社交网站、搜索引擎如何使用才能让你以直线方式走向成功等内容。一起来看看 《ME2.0》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具