【问题标题】:hadoop distcp via java resulting in NoClassDefFoundError: Could not initialize class com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemhadoop distcp via java导致NoClassDefFoundError:无法初始化类com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem
【发布时间】:2021-12-31 14:14:05
【问题描述】:

我正在尝试使用 Hadoop Java 库在我的 hadoop 集群上运行 distcp 命令,以将内容从 HDFS 移动到 Google Cloud Bucket。我收到错误NoClassDefFoundError: Could not initialize class com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem

下面是我的java代码:

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.tools.DistCp;
import org.apache.hadoop.tools.DistCpOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class HadoopHelper {

    private static Logger logger = LoggerFactory.getLogger(HadoopHelper.class);

    private static final String FS_DEFAULT_FS = "fs.defaultFS";

    private final Configuration conf;

    public HadoopHelper(String hadoopUrl) {
        conf = new Configuration();
        conf.set(FS_DEFAULT_FS, "hdfs://" + hadoopUrl);
    }

    public void distCP(JsonArray files, String target) {

        try {
            List<Path> srcPaths = new ArrayList<>();

            for (JsonElement file : files) {
                String srcPath = file.getAsString();
                srcPaths.add(new Path(srcPath));
            }

            DistCpOptions options = new DistCpOptions.Builder(
                    srcPaths,
                    new Path("gs://" + target)
            ).build();

            logger.info("Using distcp to copy {} to gs://{}", files, target);

            this.conf.set("fs.gs.impl", "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem");
            this.conf.set("fs.gs.auth.service.account.email", "my-svc-account@my-gcp-project.iam.gserviceaccount.com");
            this.conf.set("fs.gs.auth.service.account.keyfile", "config/my-svc-account-keyfile.p12");
            this.conf.set("fs.gs.project.id", "my-gcp-project");


            DistCp distCp = new DistCp(this.conf, options);
            Job job = distCp.execute();

            job.waitForCompletion(true);

            logger.info("Distcp operation success. Exiting");
        } catch (Exception e) {
            logger.error("Error while trying to execute distcp", e);
            logger.error("Distcp operation failed. Exiting");
            throw new IllegalArgumentException("Distcp failed");
        }
    }

    public void createDirectory() throws IOException {
        FileSystem fileSystem = FileSystem.get(this.conf);
        fileSystem.mkdirs(new Path("/user/newfolder"));
        logger.info("Done");
    }
}

我在pom.xml 中添加了以下依赖项:

    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>3.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-distcp</artifactId>
        <version>3.3.1</version>
    </dependency>
    <dependency>
        <groupId>com.google.cloud.bigdataoss</groupId>
        <artifactId>gcs-connector</artifactId>
        <version>hadoop3-2.2.4</version>
    </dependency>
    <dependency>
        <groupId>com.google.cloud.bigdataoss</groupId>
        <artifactId>util</artifactId>
        <version>2.2.4</version>
    </dependency>

如果我像这样在集群本身上运行 distcp 命令:hadoop distcp /user gs://my_bucket_name/

distcp 操作成功,内容被复制到云桶中。

【问题讨论】:

    标签: java hadoop hdfs


    【解决方案1】:

    您是否将 jar 添加到 hadoop 的类路径中?

    将连接器 jar 添加到 Hadoop 的类路径 将连接器 jar 放在 HADOOP_COMMON_LIB_JARS_DIR 目录中应该足以让 Hadoop 加载该 jar。或者,为了确保 jar 已加载,您可以将 HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/to/gcs-connector.jar> 添加到 Hadoop 配置目录中的 hadoop-env.sh。

    这需要在这行代码之前对 DisctCp conf(in your code this.conf) 进行:

    this.conf.set("HADOOP_CLASSPATH","$HADOOP_CLASSPATH:/tmp/gcs-connector-latest-hadoop2.jar")
    DistCp distCp = new DistCp(this.conf, options);
    

    如果有帮助的话,有一个troubleshooting section

    【讨论】:

    • 我添加了 hadoop 库作为 pom 依赖项。这够了吗?
    • 我认为这还不够。但是您可以轻松地对此进行测试。
    • 是的,当我运行在我的类路径中包含 hadoop 库的应用程序时,我得到了上述错误。所以我认为这还不够。我还应该在我的类路径中添加什么?
    • 我很困惑,您是否按照我的回答或您的 jar 的类路径中所述将其添加到您的 hadoop 类路径中? (pom.xml) 我建议应该将它添加到 hadoop 类路径中。
    • 我已将它添加到我的应用程序的 pom.xml 以及集群的类路径中,如果这是您的意思?如果我在集群上运行hadoop distcp /user gs://my_bucket_name/,distcp 操作就可以了。
    猜你喜欢
    • 1970-01-01
    • 2013-10-27
    • 2014-12-05
    • 2019-11-28
    • 2019-08-22
    • 2017-02-28
    • 2016-09-03
    • 2017-06-29
    • 1970-01-01
    相关资源
    最近更新 更多