2

我在 3 个虚拟机中运行 cloudera 集群,并尝试通过 map reduce 作业执行 hbase 批量加载。但我总是得到错误:

error: Class org.apache.hadoop.hbase.mapreduce.HFileOutputFormat not found

所以,似乎地图进程没有找到类。所以我尝试了这个:

1) 将 hbase.jar 添加到每个节点上的 HADOOP_CLASSPATH

2) 将 TableMapReduceUtil.addDependencyJars(job) / TableMapReduceUtil.addDependencyJars(myConf, HFileOutputFormat.class) 添加到我的源代码

没有任何效果。我完全不知道为什么找不到该类,因为 jar/class 在类路径中绝对可用。

如果我查看 job.xml,我会看到以下条目:

name=tmpjars    value=file:/C:/Users/Thomas/.m2/repository/org/apache/zookeeper/zookeeper/3.4.5-cdh4.3.0/zookeeper-3.4.5-cdh4.3.0.jar,file:/C:/Users/Thomas/.m2/repository/org/apache/hbase/hbase/0.94.6-cdh4.3.0/hbase-0.94.6-cdh4.3.0.jar,file:/C:/Users/Thomas/.m2/repository/org/apache/hadoop/hadoop-core/2.0.0-mr1-cdh4.3.0/hadoop-core-2.0.0-mr1-cdh4.3.0.jar,file:/C:/Users/Thomas/.m2/repository/com/google/guava/guava/11.0.2/guava-11.0.2.jar,file:/C:/Users/Thomas/.m2/repository/com/google/protobuf/protobuf-java/2.4.0a/protobuf-java-2.4.0a.jar

这对我来说似乎有点奇怪,这些是我在 Windows 系统上的本地 jar。也许这应该是hdfs jars?如果是,我该如何更改“tmpjars”的值?

这是我尝试执行的java代码:

        configuration = new Configuration(false);
        configuration.set("mapred.job.tracker", "192.168.2.41:8021");
        configuration.set("fs.defaultFS", "hdfs://192.168.2.41:8020/");
        configuration.set("hbase.zookeeper.quorum", "192.168.2.41");
        configuration.set("hbase.zookeeper.property.clientPort", "2181");

        Job job = new Job(configuration, "HBase Bulk Import for "
                + tablename);
        job.setJarByClass(HBaseKVMapper.class);

        job.setMapperClass(HBaseKVMapper.class);
        job.setMapOutputKeyClass(ImmutableBytesWritable.class);
        job.setMapOutputValueClass(KeyValue.class);
        job.setOutputFormatClass(HFileOutputFormat.class);
        job.setPartitionerClass(TotalOrderPartitioner.class);
        job.setInputFormatClass(TextInputFormat.class);
        HFileOutputFormat.configureIncrementalLoad(job, hTable);

        FileInputFormat.addInputPath(job, new Path("myfile1"));
        FileOutputFormat.setOutputPath(job, new Path("myfile2"));

        job.waitForCompletion(true);

        LoadIncrementalHFiles loader = new LoadIncrementalHFiles(
                configuration);
        loader.doBulkLoad(new Path("myFile3"), hTable);

编辑:

我尝试了更多,它完全奇怪。我将以下行添加到 java 代码中:

job.setJarByClass(HFileOutputFormat.class);

执行此操作后,错误消失了,但出现了另一个找不到类的异常:

java.lang.RuntimeException: java.lang.ClassNotFoundException: Class mypackage.bulkLoad.HBaseKVMapper not found

HBaseKVMapper 是我想要执行的自定义 Mapper 类。因此,我尝试使用“job.setJarByClass(HBaseKVMapper.class)”添加它,但它不起作用,因为它只有一个类文件,没有 jar。所以我生成了一个包含 HBaseKVMapper.class 的 Jarfile。之后,我再次执行它,现在又得到了 HFileOutputFormat.class not found 异常。

稍微调试了一下,发现setJarByClass Methode只是把本地的jar文件拷贝到HDFS上的.staging/job_#number/job.jar中。因此,此 setJarByClass() 方法仅适用于一个 jar 文件,因为它在使用另一个 jar 再次执行 setJarByClass() 后覆盖了 job.jar。

在搜索 eroor 时,我在工作分期目录中看到了以下结构:

工作分期目录

在 libjars 目录中,我看到了相关的 jar 文件

libjars 目录

因此,hbase jar 位于 libjars 目录中,但 jobtracker 不使用它来执行作业。为什么?

4

2 回答 2

1

我会尝试使用 Cloudera Manager(免费版),因为它会为您解决这些问题。否则请注意以下事项:

您自己的类和 HBase 类 HFileOutputFormat 都需要在本地和远程的类路径上可用。

提交作业

意味着当您的驱动程序运行时在本地获取正确的类路径:

$ env HADOOP_CLASSPATH=$(hbase classpath) hadoop jar path/to/jar class....

在服务器上

在你的 hadoop-env.sh

export HADOOP_CLASSPATH=$(hbase claspath)

或使用

TableMapReduceUtil.addDependencyJars
于 2013-08-18T22:30:55.577 回答
0

我找到了一个对我有用的“被黑”解决方案,但我对此并不满意,因为它实际上并不实用。

我的“被黑”解决方案:

  1. 创建一个包含所有必要类文件的大 Jar,我将其命名为“big.jar”并将其添加到本地(eclipse)类路径中
  2. 添加行: job.setJarByClass(MyMapperClass.class) ... MyMapperClass 必须在 big.jar

当我执行此操作时,将为每个作业将 big.jar 复制到文件系统。没有错误了。问题是,jar 大小为 80mb,每次都必须复制。

如果有人知道更好的方法,如果他能告诉我怎么做,我会很高兴。

编辑:

现在我尝试使用 Apache Pig 执行作业并遇到完全相同的问题。在这种情况下,我的 hacked soultion 不起作用,因为 pig 会自动创建工作。这是猪的错误:

java.lang.ClassNotFoundException: Class org.apache.hadoop.hbase.mapreduce.TableSplit not found
于 2013-08-18T15:04:57.213 回答