使用globStatus和Google Cloud Storage存储桶作为输入时无法运行Spark作业

时间:2014-10-19 12:50:17

标签: hadoop google-cloud-storage apache-spark google-hadoop

我正在使用Spark 1.1。 我有一个Spark工作,只在一个存储桶(即以......开头的文件夹)中寻找某种模式的文件夹,并且只应处理那些。我通过以下方式实现这一目标:

FileSystem fs = FileSystem.get(new Configuration(true));
FileStatus[] statusArr = fs.globStatus(new Path(inputPath));
List<FileStatus> statusList = Arrays.asList(statusArr);

List<String> pathsStr = convertFileStatusToPath(statusList);

JavaRDD<String> paths = sc.parallelize(pathsStr);

但是,在Google云端存储路径上运行此作业时:gs:// rsync-1 / 2014_07_31 *(使用最新的Google云存储连接器1.2.9),我收到以下错误:

4/10/13 10:28:38 INFO slf4j.Slf4jLogger: Slf4jLogger started    
14/10/13 10:28:38 INFO util.Utils: Successfully started service 'Driver' on port 60379.    
14/10/13 10:28:38 INFO worker.WorkerWatcher: Connecting to worker akka.tcp://sparkWorker@hadoop-w-9.c.taboola-qa-01.internal:45212/user/Worker    
Exception in thread "main" java.lang.reflect.InvocationTargetException    
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)    
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)    
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    
    at java.lang.reflect.Method.invoke(Method.java:606)    
    at org.apache.spark.deploy.worker.DriverWrapper$.main(DriverWrapper.scala:40)    
    at org.apache.spark.deploy.worker.DriverWrapper.main(DriverWrapper.scala)    
Caused by: java.lang.IllegalArgumentException: Wrong bucket: rsync-1, in path: gs://rsync-1/2014_07_31*, expected bucket: hadoop-config    
    at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem.checkPath(GoogleHadoopFileSystem.java:100)    
    at org.apache.hadoop.fs.FileSystem.makeQualified(FileSystem.java:294)    
    at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase.makeQualified(GoogleHadoopFileSystemBase.java:457)    
    at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem.getGcsPath(GoogleHadoopFileSystem.java:163)    
    at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase.globStatus(GoogleHadoopFileSystemBase.java:1052)    
    at com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase.globStatus(GoogleHadoopFileSystemBase.java:1027)    
    at com.doit.customer.dataconverter.Phase0.main(Phase0.java:578)    
... 6 more

当我在本地文件夹上运行此作业时,一切正常。

hadoop-config是我用于在Google Compute Engine上部署Spark群集的一个存储桶(使用bdutil 0.35.2工具)

1 个答案:

答案 0 :(得分:4)

简答

而不是使用:

    FileSystem fs = FileSystem.get(new Configuration(true));
    FileStatus[] statusArr = fs.globStatus(new Path(inputPath));
    List<FileStatus> statusList = Arrays.asList(statusArr);

你需要做

    Path inputPathObj = new Path(inputPath);
    FileSystem fs = FileSystem.get(inputPathObj.toUri(), new Configuration(true));
    FileStatus[] statusArr = fs.globStatus(inputPathObj);
    List<FileStatus> statusList = Arrays.asList(statusArr);

因为在Hadoop中,FileSystem实例是基于URI的schemeauthority组件共享的(并且在更高级的设置中可能是用户组信息),并且这些实例在方案之间不可互换和当局。

长答案

这与 [方案]中hostname的{​​{1}}和path组件之间的区别有关:// [权限] / [路径] ,这在HDFS用例中可能更明显,但也适用于GCS。基本上,org.apache.hadoop.fs.FileSystem中有几个URI方法,其中最适用的方法是:

get

public static FileSystem get(Configuration conf)

前者实际上只是用后者调用后者:

public static FileSystem get(URI uri, Configuration conf)

其中 return get(getDefaultUri(conf), conf); getDefaultUri(conf)fs.default.name定义。第二个考虑因素是具有不同fs.defaultFShosthname组件的FileSystems被认为是本质上不同的文件系统;在HDFS案例中,这是有道理的,如:

authority

在可能完全不同的文件系统实例上的每个点,在不同的集群上,允许在两个单独的HDFS实例上使用相同的路径名来引用单独的存储名称空间。虽然在机器的“主机名”方面不太透明,但GCS中的 FileSystem.get("hdfs://foo-cluster-namenode/", conf); FileSystem.get("hdfs://bar-cluster-namenode/", conf); 确实扮演了GCE URI的bucket组件的角色 - 在Hadoop中,这意味着authority确实返回当FileSystem.get相同但不同存储桶的不同实例时,相同的缓存Java FileSystem对象。正如您无法创建HDFS实例并将其指向其他权限一样:

bucket

当您致电 // Can't mix authorities! FileSystem.get("hdfs://foo/", conf).listStatus(new Path("hdfs://bar/")); 时,您实际上有一个指向FileSystem.get(conf)的缓存实例,然后使用它来尝试列出gs://hadoop-config/

相反,当您知道要操作的路径时,应该是您获取FileSystem实例的时间:

gs://rsync-1