默认情况下,部署在 MapReduce 集群中的 MapReduce jobs 没有权限访问$HBASE_CONF_DIR
路径下的 HBase 配置 或者 HBase classes.
通过以下方式可以为 MapReduce jobs 配置权限.
增加 hbase-site.xml 到 $HADOOP_HOME/conf
然后将 HBase jars 添加到 $HADOOP_HOME/lib 目录下
最后需要将这些变更拷贝到 Hadoop 集群中所有服务上.
或者
编辑 $HADOOP_HOME/conf/hadoop-env.sh 将 HBase 依赖添加到
HADOOP_CLASSPATH
.
以上配置均不推荐,因为它会让 Hadoop 安装 HBase 的依赖,并且需要重启 Hadoop 集群才能使用 HBase 中的数据.
推荐的方式是 HBase 使用HADOOP_CLASSPATH
or -libjars
添加其依赖的 jar 包.
从 HBase 0.90.x
,HBase 添加依赖 jar 包到任务自身配置中. 依赖项只需要在本地CLASSPATH
可用,然后被打包部署到 MapReduce 集群的 fat job jar 中.一种取巧的方式是传递全量的 HBase classpath(即 hbase,独立的 jars 还有配置)到 mapreduce job 运行器中令 hbase 工具从全量的 classpath 挑选依赖最终配置到 MapReduce job 的配置中(可以查看源码实现TableMapReduceUtil#addDependencyJars(org.apache.hadoop.mapreduce.Job)
).
下面的例子是在表usertable
上运行的 HBase 的 MapReduce 任务: 表行数统计任务RowCounter.设置在 MapReduce 上下文运行需要的 hbase jars 以及配置文件如 hbase-site.xml 到 HADOOP_CLASSPATH
. 一定要确保使用了与你的系统相对应的 HBase Jar.替换以下命令中的 VERSION 字段为本地 HBASE 版本. 反引号(`)使 shell 执行子命令,将hbase classpath
的输出设置为HADOOP_CLASSPATH
. 这个例子需要在 Bash-compatible 执行.
$ HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase classpath` \
${HADOOP_HOME}/bin/hadoop jar ${HBASE_HOME}/lib/hbase-mapreduce-VERSION.jar \
org.apache.hadoop.hbase.mapreduce.RowCounter usertable
以上命令将启动一个运行在本地配置指定的 hbase 集群的 mapreduce 作业,用来统计表行数.这个集群也是 Hadoop 配置指定的.
hbase-mapreduce.jar
核心是一个驱动,罗列了 HBASE 装载的一些基础的 MapReduce 任务.例如,假设你安装的是2.0.0-SNAPSHOT
版本:
$ HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase classpath` \
${HADOOP_HOME}/bin/hadoop jar ${HBASE_HOME}/lib/hbase-mapreduce-2.0.0-SNAPSHOT.jar
An example program must be given as the first argument.
Valid program names are:
CellCounter: Count cells in HBase table.
WALPlayer: Replay WAL files.
completebulkload: Complete a bulk data load.
copytable: Export a table from local cluster to peer cluster.
export: Write table data to HDFS.
exportsnapshot: Export the specific snapshot to a given FileSystem.
import: Import data written by Export.
importtsv: Import data in TSV format.
rowcounter: Count rows in HBase table.
verifyrep: Compare the data from tables in two different clusters. WARNING: It doesn't work for incrementColumnValues'd cells since the timestamp is changed after being appended to the log.
您可以使用上面列出的 MapReduce 任务的简写采用以下命令重新执行表行数统计任务(同样,假设安装的 HBASE 是2.0.0-SNAPSHOT
版本):
$ HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase classpath` \
${HADOOP_HOME}/bin/hadoop jar ${HBASE_HOME}/lib/hbase-mapreduce-2.0.0-SNAPSHOT.jar \
rowcounter usertable
您可能发现了hbase mapredcp
工具的输出; 它列出了在 hbase 运行基础 mapreduce 作业所需的最小 jar 文件集合(不包括配置,如果希望 MapReduce 作业能准确找到目标集群,则可能需要添加些配置)。 一旦你开始做任何实质性的事情,你还需要添加额外依赖,这些依赖需在运行hbase mapredcp
时通过传递系统属性-Dtmpjars
来指定。
对于那些没有打包依赖的 jobs 或者直接调用TableMapReduceUtil#addDependencyJars
,则下面的命令格式就非常必要了:
$ HADOOP_CLASSPATH=`${HBASE_HOME}/bin/hbase mapredcp`:${HBASE_HOME}/conf hadoop jar MyApp.jar MyJobMainClass -libjars $(${HBASE_HOME}/bin/hbase mapredcp | tr ':' ',') ...
如果您是在 HBase 的构建地址而不是安装地址执行以上示例,您会遇到如下错误:
java.lang.RuntimeException: java.lang.ClassNotFoundException: org.apache.hadoop.hbase.mapreduce.RowCounter$RowCounterMapper
如果出现了以上问题,请参照以下命令修改,它从构建环境的 target/ 目录下使用 HBASE jars
$ HADOOP_CLASSPATH=${HBASE_BUILD_HOME}/hbase-mapreduce/target/hbase-mapreduce-VERSION-SNAPSHOT.jar:`${HBASE_BUILD_HOME}/bin/hbase classpath` ${HADOOP_HOME}/bin/hadoop jar ${HBASE_BUILD_HOME}/hbase-mapreduce/target/hbase-mapreduce-VERSION-SNAPSHOT.jar rowcounter usertable
Notice to MapReduce users of HBase between 0.96.1 and 0.98.4 一些 HBase MapReduce 任务启动失败,会出现以下类似的异常:
Exception in thread "main" java.lang.IllegalAccessError: class com.google.protobuf.ZeroCopyLiteralByteString cannot access its superclass com.google.protobuf.LiteralByteString at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:792) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java:71) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at org.apache.hadoop.hbase.protobuf.ProtobufUtil.toScan(ProtobufUtil.java:818) at org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.convertScanToString(TableMapReduceUtil.java:433) at org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:186) at org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:147) at org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:270) at org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil.initTableMapperJob(TableMapReduceUtil.java:100) ...
这是HBASE-9867无意间增加了一个类加载器依赖引入的优化.
这个影响使用
-libjars
和 'fat jar '的任务,他们将运行时依赖放在在lib
路径下.
为了满足新类加载器需要,hbase-protocol.jar
必须包含在 Hadoop 的 环境变量下.可通过HBase, MapReduce, and the CLASSPATH查阅解决 一些 classpath 错误的推荐解决方法.
The following is included for historical purposes.
在 Hadoop 的 lib 目录里通过系统连接或者直接拷贝方式引入
hbase-protocol.jar
,可以系统范围内解决 classpath 问题.这也可以在每个作业启动的基础上实现,方法是在作业提交时将其(
hbase-protocol.jar
)包含在HADOOP_CLASSPATH
环境变量中。启动时打包其依赖项,以下所有三个作业启动命令都满足此要求
$ HADOOP_CLASSPATH=/path/to/hbase-protocol.jar:/path/to/hbase/conf hadoop jar MyJob.jar MyJobMainClass $ HADOOP_CLASSPATH=$(hbase mapredcp):/path/to/hbase/conf hadoop jar MyJob.jar MyJobMainClass $ HADOOP_CLASSPATH=$(hbase classpath) hadoop jar MyJob.jar MyJobMainClass
下面的命令对于那些不打包自己依赖的 Jar 文件很有必要:
$ HADOOP_CLASSPATH=$(hbase mapredcp):/etc/hbase/conf hadoop jar MyApp.jar MyJobMainClass -libjars $(hbase mapredcp | tr ':' ',') ...
可以查阅 HBASE-10304进行更深入的讨论.