提交 Google Dataproc Hadoop 作业时未找到 Hadoop Streaming jar?

Hadoop Streaming jar not found when submitting Google Dataproc Hadoop Job?

尝试以编程方式提交 Hadoop MapReduce 作业时(从使用 dataproc 库的 Java 应用程序),作业立即失败。当通过 UI 提交完全相同的作业时,它工作正常。

我已尝试通过 SSH 连接到 Dataproc 集群以确认文件存在、检查权限并更改 jar 引用。还没有任何效果。

我遇到的错误:

Exception in thread "main" java.lang.ClassNotFoundException: file:///usr/lib/hadoop-mapreduce/hadoop-streaming-2.8.4.jar
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.google.cloud.hadoop.services.agent.job.shim.HadoopRunClassShim.main(HadoopRunClassShim.java:18)
Job output is complete

当我在控制台中克隆失败的作业并查看 REST 等价物时,这是我看到的:

POST /v1/projects/project-id/regions/us-east1/jobs:submit/
{
  "projectId": "project-id",
  "job": {
    "reference": {
      "projectId": "project-id",
      "jobId": "jobDoesNotWork"
    },
    "placement": {
      "clusterName": "cluster-name",
      "clusterUuid": "uuid"
    },
    "submittedBy": "service-account@project.iam.gserviceaccount.com",
    "jobUuid": "uuid",
    "hadoopJob": {
      "args": [
        "-Dmapred.reduce.tasks=20",
        "-Dmapred.output.compress=true",
        "-Dmapred.compress.map.output=true",
        "-Dstream.map.output.field.separator=,",
        "-Dmapred.textoutputformat.separator=,",
        "-Dmapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec",
        "-Dmapreduce.input.fileinputformat.split.minsize=268435456",
        "-Dmapreduce.input.fileinputformat.split.maxsize=268435456",
        "-mapper",
        "/bin/cat",
        "-reducer",
        "/bin/cat",
        "-inputformat",
        "org.apache.hadoop.mapred.lib.CombineTextInputFormat",
        "-outputformat",
        "org.apache.hadoop.mapred.TextOutputFormat",
        "-input",
        "gs://input/path/",
        "-output",
        "gs://output/path/"
      ],
      "mainJarFileUri": "file:///usr/lib/hadoop-mapreduce/hadoop-streaming-2.8.4.jar"
    }
  }
}

当我通过控制台提交作业时,它起作用了。该工作的 REST 等价物:

POST /v1/projects/project-id/regions/us-east1/jobs:submit/
{
  "projectId": "project-id",
  "job": {
    "reference": {
      "projectId": "project-id,
      "jobId": "jobDoesWork"
    },
    "placement": {
      "clusterName": "cluster-name,
      "clusterUuid": ""
    },
    "submittedBy": "user_email_account@email.com",
    "jobUuid": "uuid",
    "hadoopJob": {
      "args": [
        "-Dmapred.reduce.tasks=20",
        "-Dmapred.output.compress=true",
        "-Dmapred.compress.map.output=true",
        "-Dstream.map.output.field.separator=,",
        "-Dmapred.textoutputformat.separator=,",
        "-Dmapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec",
        "-Dmapreduce.input.fileinputformat.split.minsize=268435456",
        "-Dmapreduce.input.fileinputformat.split.maxsize=268435456",
        "-mapper",
        "/bin/cat",
        "-reducer",
        "/bin/cat",
        "-inputformat",
        "org.apache.hadoop.mapred.lib.CombineTextInputFormat",
        "-outputformat",
        "org.apache.hadoop.mapred.TextOutputFormat",
        "-input",
        "gs://input/path/",
        "-output",
        "gs://output/path/"
      ],
      "mainJarFileUri": "file:///usr/lib/hadoop-mapreduce/hadoop-streaming-2.8.4.jar"
    }
  }
}

我通过 ssh 进入了盒子并确认该文件实际上存在。我能真正看到的唯一区别是“submittedBy”。一个有效,一个无效。我猜这是一个权限问题,但我似乎无法分辨在每种情况下权限是从哪里提取的。在这两种情况下,Dataproc 集群都是使用相同的服务帐号创建的。

在集群上查看该 jar 的权限我看到:

-rw-r--r-- 1 root root  133856 Nov 27 20:17 hadoop-streaming-2.8.4.jar
lrwxrwxrwx 1 root root      26 Nov 27 20:17 hadoop-streaming.jar -> hadoop-streaming-2.8.4.jar

我尝试将 mainJarFileUri 从明确指向版本控制的 jar 更改为 link(因为它具有打开权限),但并不真正期望它能工作。但事实并非如此。

有没有更多 Dataproc 经验的人知道这里发生了什么,我该如何解决它?

代码中一个容易犯的常见错误是调用 setMainClass when you intended to call setMainJarFileUri,反之亦然。您收到的 java.lang.ClassNotFoundException 表明 Dataproc 正在尝试将该 jarfile 字符串作为类名而不是 jarfile 提交,因此 Dataproc 认为您设置了 main_class。您可能需要仔细检查您的代码,看看这是否是您遇到的错误。

在 GUI 中使用 "clone job" 隐藏此问题的原因是 GUI 试图通过提供单个文本框来设置 main_classmain_jar_file_uri 来更加用户友好, 并通过查看文件扩展名来推断它是否是一个 jarfile。因此,如果您在 main_class 字段中提交带有 jarfile URI 的作业但失败了,那么您单击 clone 并提交新作业,GUI 将尝试变得聪明并识别新作业实际上指定了一个 jarfile 名称,因此将在 JSON 请求中正确设置 main_jar_file_uri 字段而不是 main_class.