No FileSystem for scheme "s3"问题解决

2022-05-19 11:17:36 浏览数 (2)

一、背景

公司使用s3的路径去关联hive的分区,现在接入spark on k8s引入了3.0以上的hadoop版本,高版本的hadoop版本开始支持s3a配置。

二、配置

spark想要支持访问s3的数据,有两个条件

1、加入hadoop-aws和aws-sdk的jar包到spark/jar目录,hadoop3以上的aws-sdk jar是aws-jdk-java-bundle,注意两个jar包的版本一定要对上,不然大概率会报错,hadoop-aws的版本也尽量和spark带hadoop版本一致。例如hadoop-aws-3.3.1对应aws-java-sdk-bundle:1.11.901。不知道对应版本,可以把hadoop-aws依赖导入idea,然后maven工具那里可以看到。

2、添加配置

代码语言:javascript复制
spark.hadoop.fs.s3a.access.key *******
spark.hadoop.fs.s3a.secret.key *******
spark.hadoop.fs.s3a.impl org.apache.hadoop.fs.s3a.S3AFileSystem

三、问题

上诉配置,如果在spark中使用了s3的路径,会以下问题

上图是我试图去在spark上创建hive表指定路径为s3导致,如果是查询hive也会遇到一样的问题 No FileSystem for scheme "s3"

代码语言:javascript复制
CREATE TABLE `tmp`.`tmp_watch_base_user` (
  `uid` STRING COMMENT '用户id',
  `game_key` STRING COMMENT 'game_key',
  `host_id` STRING COMMENT 'host_id',
  `platform` STRING COMMENT 'platform',
  `day` BIGINT COMMENT 'day',
  `watch_time` INT COMMENT '时间',
  `first_watch_hour` STRING COMMENT 'first_watch_hour')
USING orc
LOCATION 's3://mybucket/hive/tmp.db/tmp_watch_base_user';

四、思考方向

找遍网上所有的帖子,都没说解决s3和s3a的兼容问题,考虑到如果有问题,需要回滚的原因,不能轻易修改元数据,自己想了两个方向

1、从hive-metadata模块获取元数据的时候,将拿到的location中的s3替换成s3a。

2、修改hadoop-common包下的Path,原因是所有访问文件系统的路径都会封装到Path中,Path调用getFileSystem方法去获取文件系统,可以在uri进入Path后,手动把s3替换成s3a。

五、最终解决方法

上诉两种方法改起源码来考虑的东西太多,试了一整天后没啥进展,怀着侥幸的心理,再去看一下hadoop的源码,看看有没有什么漏掉的配置,果不其然,在FileSystem的类下,看到加载文件系统的方法getFileSystemClass,通过加载java class的方式

代码语言:javascript复制
public static Class<? extends FileSystem> getFileSystemClass(String scheme,
      Configuration conf) throws IOException {
    if (!FILE_SYSTEMS_LOADED) {
      loadFileSystems();
    }
    LOGGER.debug("Looking for FS supporting {}", scheme);
    Class<? extends FileSystem> clazz = null;
    if (conf != null) {
      String property = "fs."   scheme   ".impl";
      LOGGER.debug("looking for configuration option {}", property);
      clazz = (Class<? extends FileSystem>) conf.getClass(
          property, null);
    } else {
      LOGGER.debug("No configuration: skipping check for fs.{}.impl", scheme);
    }
    if (clazz == null) {
      LOGGER.debug("Looking in service filesystems for implementation class");
      clazz = SERVICE_FILE_SYSTEMS.get(scheme);
    } else {
      LOGGER.debug("Filesystem {} defined in configuration option", scheme);
    }
    if (clazz == null) {
      throw new UnsupportedFileSystemException("No FileSystem for scheme "
            """   scheme   """);
    }
    LOGGER.debug("FS for {} is {}", scheme, clazz);
    return clazz;
  }

使用可以配置去加载指定的文件系统,也就是上面我们配置的 spark.hadoop.fs.s3a.impl=org.apache.hadoop.fs.s3a.S3AFileSystem

代码语言:javascript复制
String property = "fs."   scheme   ".impl";

想了想,scheme是从路径上获取,那s3路径的配置应该是spark.hadoop.fs.s3.impl,对应的文件系统应该是

org.apache.hadoop.fs.s3.S3FileSystem,但是很遗憾这个类在hadoop3后就删除了,后来又想s3a是s3的升级版,说不定s3a的文件系统可以适合s3,就使用下述配置,结果是可行的。

代码语言:javascript复制
spark.hadoop.fs.s3.impl=org.apache.hadoop.fs.s3a.S3AFileSystem

六、总结

问题不复杂,但是在做的过程中,找不到相关有用的帖子,导致心情浮躁,以为这个问题很不常见,其实如果静下心来从头看一下源码,或许这个问题2分钟就搞定了。

0 人点赞