2

我正在尝试使用 Google 的 Cloud Storage Connector for Hadoop 在 Hadoop 上运行 Oryx: https ://cloud.google.com/hadoop/google-cloud-storage-connector

我更喜欢将 Hadoop 2.4.1 与 Oryx 一起使用,因此我将 hadoop2_env.sh 设置用于我在 google 计算引擎上创建的 hadoop 集群,例如:

.bdutil -b <BUCKET_NAME> -n 2 --env_var_files hadoop2_env.sh \
--default_fs gs --prefix <PREFIX_NAME> deploy

当我尝试使用 hadoop 运行 oryx 时,我面临两个主要问题。

1) 尽管确认我的 hadoop conf 目录与 google 在计算引擎上安装的预期匹配,例如:

$ echo $HADOOP_CONF_DIR
/home/hadoop/hadoop-install/etc/hadoop

我仍然发现某些东西正在寻找 /conf 目录,例如:

Caused by: java.lang.IllegalStateException: Not a directory: /etc/hadoop/conf

我的理解是../etc/hadoop应该是/conf目录,eg: hadoop:配置文件

虽然我不需要进行任何更改,但这个问题只有在我将配置文件复制到新创建的目录时才能解决,例如:

sudo mkdir /etc/hadoop/conf
sudo cp /home/hadoop/hadoop-install/etc/hadoop/* /etc/hadoop/conf

那么这是为什么呢?这是使用 google hadoop 连接器的结果吗?

2)在“解决”上述问题之后,我发现(在我看来)与 hadoop 集群和 google 文件系统之间的通信有关的其他错误:

2014 年 10 月 1 日星期三 20:18:30 UTC 警告无法为您的平台加载 native-hadoop 库...在适用的情况下使用内置 java 类

2014 年 10 月 1 日星期三 20:18:30 UTC 信息 命名空间前缀:hdfs://BUCKET_NAME

2014 年 10 月 1 日星期三 20:18:30 UTC 在 com.cloudera.oryx.common.servcomp.StoreUtils.listGenerationsForInstance(StoreUtils.java:50) 在 com.cloudera.oryx.computation 执行 java.lang.ExceptionInInitializerError 时出现严重意外错误。 PeriodicRunner.run(PeriodicRunner.java:173) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304) at java.util .concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java: 1145) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 在 java.lang.Thread.run(Thread.java:745) 引起:java.lang.IllegalArgumentException: java.net.UnknownHostException: org.apache.hadoop.security.SecurityUtil.buildTokenService(SecurityUtil. java:373) 在 org.apache.hadoop.hdfs.NameNodeProxies.createNonHAProxy(NameNodeProxies.java:258) 在 org.apache.hadoop.hdfs.NameNodeProxies.createProxy(NameNodeProxies.java:153) 在 org.apache.hadoop.hdfs .DFSClient.(DFSClient.java:602) 在 org.apache.hadoop.hdfs.DFSClient.(DFSClient.java:547) 在 org.apache.hadoop.hdfs.DistributedFileSystem.initialize(DistributedFileSystem.java:139) 在 org. apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2591) 在 org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:89) 在 org.apache.hadoop.fs.FileSystem$Cache.getInternal (文件系统.java:2625) 在 org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2607) 在 org.apache.hadoop.fs.FileSystem.get(FileSystem.java:368) 在 com.cloudera.oryx.common .servcomp.Store.(Store.java:76) at com.cloudera.oryx.common.servcomp.Store.(Store.java:57) ... 还有 9 个

引起:java.net.UnknownHostException: BUCKET_NAME ... 22 更多

与我相关的是,当我将默认文件系统设置为 gs:// 时,命名空间前缀是 hdfs://

也许这会导致 UnkownHostException?

请注意,我已“确认”hadoop 集群已连接到 google 文件系统,例如:hadoop fs -ls 生成我的 google 云存储桶的内容以及 gs://BUCKET_NAME 目录的所有预期内容。但是,我不熟悉通过 hadoop 连接器对 hadoop 的 google 表现,以及我通常测试以查看 hadoop 集群是否正在运行的传统方式,即:jps 仅产生 6440 Jps,而不是列出所有节点。但是,我从 hadoop 集群的主节点(即 PREFIX_NAME-m)运行此命令,并且在使用 google 云存储连接器用于 hadoop 时,我不确定预期的输出。

那么,如何解决这些错误并让我的 oryx 作业(通过 hadoop)成功访问我的 gs://BUCKET_NAME 目录中的数据?

提前感谢您的见解或建议。

更新:感谢非常详细的回复。作为一种解决方法,我通过更改将 gs://“硬编码”到 oryx 中:

  prefix = "hdfs://" + host + ':' + port;
} else {
  prefix = "hdfs://" + host;

至:

  prefix = "gs://" + host + ':' + port;
} else {
  prefix = "gs://" + host;

我现在收到以下错误:

2014 年 10 月 14 日星期二 20:24:50 UTC 严重意外错误在 com.cloudera.oryx.common.servcomp.StoreUtils.listGenerationsForInstance(StoreUtils.java:50) 在 com.cloudera.oryx.computation 执行 java.lang.ExceptionInInitializerError。 PeriodicRunner.run(PeriodicRunner.java:173) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304) at java.util .concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java: 1145) 在 java.util.concurrent.ThreadPoolExecutor$Worker。在 java.lang.Thread.run(Thread.java:745) 处运行(ThreadPoolExecutor.java:615)

引起:java.lang.RuntimeException:java.lang.ClassNotFoundException:类 com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem 在 org.apache.hadoop.conf.Configuration.getClass 找不到 (Configuration.java:1905)在 org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2573) 在 org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2586) 在 org.apache.hadoop.fs.FileSystem.access $200(FileSystem.java:89) at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2625) at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2607)在 org.apache.hadoop.fs.FileSystem.get(FileSystem.java:368) 在 com.cloudera.oryx.common.servcomp.Store.(Store.java:76) 在 com.cloudera.oryx.common.servcomp。商店。(商店。java:57)

根据此处的说明:https ://cloud.google.com/hadoop/google-cloud-storage-connector#classpath我相信我已将连接器 jar 添加到 Hadoop 的类路径中;我补充说:

HADOOP_CLASSPATH=$HADOOP_CLASSPATH:'https://storage.googleapis.com/hadoop-lib/gcs/gcs-connector-1.2.9-hadoop2.jar 

到 /home/rich/hadoop-env-setup.sh。和 (echo $HADOOP_CLASSPATH) 产生:

/contrib/capacity-scheduler/.jar:/home/hadoop/hadoop-install/share/hadoop/common/lib/gcs-connector-1.2.9-hadoop2.jar:/contrib/capacity-scheduler/.jar:/ _ _主页/hadoop/hadoop-install/share/hadoop/common/lib/gcs-connector-1.2.9-hadoop2.jar

我需要在类路径中添加更多内容吗?

我还注意到(可能相关)即使使用导出命令,我仍然会收到 /etc/hadoop/conf 的错误。我一直在使用 sudo mkdir /etc/hadoop/conf 作为临时解决方法。我在这里提到这一点,以防它可能导致其他问题。

4

1 回答 1

1

似乎有几个问题;第一个是通常情况下,当事情在 下运行时hadoop jar,hadoop 会将各种系统环境变量和类路径等灌输到正在运行的程序中;在你的情况下,因为 Oryx 运行时没有使用hadoop jar,而是使用类似的东西:

java -Dconfig.file=oryx.conf -jar computation/target/oryx-computation-x.y.z.jar

然后$HADOOP_CONF_DIR实际上并没有进入环境,因此OryxConfiguration.java 中的 System.getenv无法获取它,并使用默认/etc/hadoop/conf值。只需使用export命令即可解决此问题,您可以通过查看它是否将其放入子shell来进行测试:

echo $HADOOP_CONF_DIR
bash -c 'echo $HADOOP_CONF_DIR'
export HADOOP_CONF_DIR
bash -c 'echo $HADOOP_CONF_DIR'
java -Dconfig.file=oryx.conf -jar computation/target/oryx-computation-x.y.z.jar

第二个也是更不幸的问题是 Oryx 似乎对“hdfs”进行了硬编码,而不是允许用户设置任何文件系统方案:

private Namespaces() {
  Config config = ConfigUtils.getDefaultConfig();
  boolean localData;
  if (config.hasPath("model.local")) {
    log.warn("model.local is deprecated; use model.local-data");
    localData = config.getBoolean("model.local");
  } else {
    localData = config.getBoolean("model.local-data");
  }
  if (localData) {
    prefix = "file:";
  } else {
    URI defaultURI = FileSystem.getDefaultUri(OryxConfiguration.get());
    String host = defaultURI.getHost();
    Preconditions.checkNotNull(host,
        "Hadoop FS has no host? Did you intent to set model.local-data=true?");
    int port = defaultURI.getPort();
    if (port > 0) {
      prefix = "hdfs://" + host + ':' + port;
    } else {
      prefix = "hdfs://" + host;
    }
  }
  log.info("Namespace prefix: {}", prefix);
}

这完全取决于 Oryx 是否打算在未来添加对其他文件系统方案的支持,但与此同时,您要么必须自己更改 Oryx 代码并重新编译,要么您可以尝试破解它(但有可能硬依赖 HDFS 失败的 Oryx)。

理论上,对 Oryx 的更改应该是:

    String scheme = defaultURI.getScheme();
    if (port > 0) {
      prefix = scheme + "://" + host + ':' + port;
    } else {
      prefix = scheme + "://" + host;
    }

但是,如果您确实走这条路,请记住GCS 的最终列表一致性语义,其中多阶段工作流不得依赖“列表”操作来立即查找前一阶段的所有输出;Oryx 可能有也可能没有这种依赖性。

在您的情况下,最可靠的解决方案是使用 部署--default_fs hdfs,其中 bdutil 仍将安装 gcs-connector 以便您可以运行hadoop distcp将数据从 GCS 临时移动到 HDFS,运行 Oryx,然后完成后,将其复制回地面站。

于 2014-10-02T01:42:14.737 回答