hadoop常见问题

###1. 向HDFS写文件时报没有权限
错误信息类似如下:

1
2
3
4
5
6
7
8
9
10
11
12
Exception in thread "main" org.apache.hadoop.security.AccessControlException: Permission denied: user=Louz, access=WRITE, inode="/test":hduser:supergroup:drwxr-xr-x
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:234)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:214)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:158)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkPermission(FSNamesystem.java:5185)
......
Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException): Permission denied: user=Louz, access=WRITE, inode="/test":hduser:supergroup:drwxr-xr-x
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:234)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:214)
at org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.checkPermission(FSPermissionChecker.java:158)
......

原因:
这是由于写文件时是以客户端的用户名往hdfs里写的,如果客户端的用户在服务器上不存在或者没有对应目录的权限,所以会报以上的错

解决方法1:
在服务器端给对应的目录赋权,使用hdfs dfs -chmod命令,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[hduser@hadoop2 ~]$ hdfs dfs -ls -R /
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:39 /abc
drwxr-xr-x - hduser supergroup 0 2014-05-20 09:29 /pc-demo
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder1
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder2
[hduser@hadoop2 ~]$ hdfs dfs -chmod -R 777 /pc-demo
[hduser@hadoop2 ~]$ hdfs dfs -ls -R /
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:39 /abc
drwxrwxrwx - hduser supergroup 0 2014-05-20 09:29 /pc-demo
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder1
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder2

可以看到现在/pc-demo目录权限已经修改成所有人可读写

成功写入的文件权限类似

1
2
3
4
5
6
7
[hduser@hadoop2 ~]$ hdfs dfs -ls -R /
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:39 /abc
drwxrwxrwx - hduser supergroup 0 2014-05-20 09:34 /pc-demo
-rw-r--r-- 1 Louz supergroup 9 2014-05-20 09:34 /pc-demo/demo.txt
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder1
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder2

解决方法2:
在服务器端修改hdfs-site.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
<description></description>
</property>
<property>
<name>dfs.permissions</name>
<!-- 设置成false就不会检验客户端用户是否有hdfs的权限 -->
<value>false</value>
</property>
</configuration>

重启Hadoop服务,再执行程序,讲文件demo.txt上传至/test目录

1
2
3
4
5
6
7
8
[hduser@hadoop2 ~]$ hdfs dfs -ls -R /
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:39 /abc
drwxrwxrwx - hduser supergroup 0 2014-05-20 09:34 /pc-demo <- 该目录是通过chmod后,实现可上传文件,目录的权限为所有人可读写
-rw-r--r-- 1 Louz supergroup 9 2014-05-20 09:34 /pc-demo/demo.txt
drwxr-xr-x - hduser supergroup 0 2014-05-20 11:03 /test <- 该目录是通过修改hdfs-site.xml,实现可上传文件,目录权限为其他人只读
-rw-r--r-- 1 Louz supergroup 9 2014-05-20 11:03 /test/demo.txt
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder1
drwxr-xr-x - hduser supergroup 0 2014-05-19 16:38 /test/folder2

###2. windows运行客户端程序时报winutils not found
问题: 在windows运行MR测试程序时,报类似的错误:

1
2
3
4
5
2016-03-11 18:18:30,702 ERROR [main] util.Shell (Shell.java:getWinUtilsPath(374)) - Failed to locate the winutils binary in the hadoop binary path
java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.
at org.apache.hadoop.util.Shell.getQualifiedBinPath(Shell.java:356)
at org.apache.hadoop.util.Shell.getWinUtilsPath(Shell.java:371)
......

解决方法:
步骤一:首先要在环境变量里设置好HADOOP_HOME参数,值为hadoop解压包所在目录,例如我的是:D:\software\hadoop\hadoop-2.7.1

步骤二:需要把winutils.exe文件放到%HADOOP_HOME%\bin目录去,winutils.exe可以在 https://github.com/steveloughran/winutils 下载

步骤三:重启一下IDE


3. 在windows运行客户端的Job报UnsatisfiedLinkError错

问题: 报错信息如下:

1
2
3
4
5
java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
at org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Native Method)
at org.apache.hadoop.io.nativeio.NativeIO$Windows.access(NativeIO.java:609)
at org.apache.hadoop.fs.FileUtil.canRead(FileUtil.java:977)

解决方法:将编译后hadoop的bin目录中的hadoop.dll文件拷贝到%HADOOP_HOME%\bin即可


4. MapReduce程序的Classpath

一般运行MR程序的命令都是

1
hadoop jar user.jar MainClass .......

这时候程序的classpath分别有:

  1. hadoop框架本身的*.jar
  2. user.jar里的class
  3. user.jar里lib目录下的*.jar

要注意的是: 如果user.jar是放在hadoop环境的classpath中,那么user.jar依赖的jar包也必须放到hadoop环境的classpath中,不能放在user.jar里的lib目录中;但如果不把user.jar放到hadoop环境的classpath中,则可以将依赖包打到user.jar的lib目录中,原因如下:

  1. 如果user.jar放在hadoop classpath,那么执行hadoop jar user.jar MainClass ......
    的时候,user.jar中的class由hadoop的classloader(下面称为parent classloader)从hadoop classpath中的jar包load进来

  2. 而user.jar中的lib目录下的jar包是在org.apache.hadoop.util.RunJar的main方法中将user.jar解压到一个临时目录,再创建一个classloader(下面称为child classloader),将解压后的lib/*.jar加载进来。

  3. 如果user.jar放在hadoop的classpath中,user.jar本身的class由parent classloader加载,其依赖的类则是由child classloader加载,根据JVM的加载模型,parent classloader是不知道child classloader加载的类的,所有此时会报ClassNotFoundException的错误;

  4. 如果user.jar不放在hadoop的classpath中,user.jar本身的class以及依赖的lib/*.jar都是有child classloader加载,自然能正常运行。

5. 如何设置只有Mapper的程序

参考文档:http://unmeshasreeveni.blogspot.com/2014/05/map-only-jobs-in-hadoop.html
需要在客户端程序中设置

1
job.setNumReduceTasks(0);

这样就不会有reduce阶段,否则会默认使用Identity Reducer进行处理,白白多了shuffle阶段

6. 如何编译hadoop

官方文档
编译后可得出前面提到的winutils.exehadoop.dll等文件

1
2
3
4
5
6
7
8
9
10
11
12
Requirements:
* Windows System
* JDK 1.6+
* Maven 3.0 or later
* Findbugs 1.3.9 (if running findbugs)
* ProtocolBuffer 2.5.0
* CMake 2.6 or newer
* Windows SDK or Visual Studio 2010 Professional
* Unix command-line tools from GnuWin32 or Cygwin: sh, mkdir, rm, cp, tar, gzip
* zlib headers (if building native code bindings for zlib)
* Internet connection for first build (to fetch all Maven and Hadoop dependencies)
  1. 利用VirtualBoxVMWare安装windows,我采用的是VirtualBox + Windows7 32位
  2. 安装Windows SDK
    建议下载完整包进行安装,完整包地址

  3. 安装CMake
    我安装的是3.6.2版本

  4. 安装JDK
    我安装的是JDK8 update 101,加上JAVA_HOME环境变量(路径中不能有空格)

  5. 设置Platform环境变量
    根据目标平台设置该环境变量

    1
    2
    set Platform=x64 (when building on a 64-bit system)
    set Platform=Win32 (when building on a 32-bit system)
  6. 安装Maven
    我安装的是3.3.9,设置M2_HOME环境变量,并将%M2_HOME%\bin加到PATH环境变量中

  7. 解压Hadoop源代码
    我使用的是2.7.1版本

  8. 安装Cygwin
    选择http://mirrors.sohu.com/cygwin这个源,速度比较快。假设安装路径为C:\cygwin,将C:\cygwin\bin加入到PATH环境变量中,以便可以在windows命令行执行sh等命令

  9. 安装protobuf
    官方地址,我使用的是protoc-2.5.0-win32,解压后将目录加入到PATH变量中

  10. 执行构建
    Windos SDK的命令行执行以下命令:

    1
    2
    cd %HADOOP_HOME%
    mvn package -Pdist -Dmaven.javadoc.skip=true -DskipTests