HDFS客户端的权限错误:Permission denied | IT人生录

标签: | 发表时间:2018-04-18 20:48 | 作者:
出处:http://www.huqiwen.com

搭建了一个Hadoop的环境,Hadoop集群环境部署在几个Linux服务器上,现在想使用windows上的Java客户端来操作集群中的HDFS文件,但是在客户端运行时出现了如下的认证错误,被折磨了几天,问题终得以解决。以此文记录问题的解决过程。

(如果想看最终解决问题的方法拉到最后,如果想看我的问题解决思路请从上向下看)

问题描述

上传文件的代码:

  1.     private static void uploadToHdfs() throws FileNotFoundException,IOException {
  2.         //我的文件地址
  3.         String localSrc = "E:\\快盘\\技术文档\\hadoop\\HDFS初步研究.pdf";
  4.         //存放在云端的目的地址
  5.         String dest = "hdfs://192.168.2.156:9000/user/HDFS初步研究.pdf";
  6.         InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
  7.         //得到配置对象
  8.         Configuration conf = new Configuration();
  9. //        conf.set("fs.default.name","hdfs://192.168.2.156:9000");
  10.         //文件系统
  11.         FileSystem fs = FileSystem.get(URI.create(dest), conf);
  12.         //输出流
  13.         OutputStream out = fs.create(new Path(dest), new Progressable() {
  14.             @Override
  15.             public void progress() {
  16.                 System.out.println("上传完一个设定缓存区大小容量的文件!");
  17.             }
  18.         });
  19.         //连接两个流,形成通道,使输入流向输出流传输数据
  20.         IOUtils.copyBytes(in, out, 4096, true);
  21.     }

错误的详细描述如下:

org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied: user=Administrator, access=WRITE, inode="hadoop": hadoop:supergroup:rwxr-xr-x

其实这个错误的原因很容易看出来,用户Administator在hadoop上执行写操作时被权限系统拒绝.

解决问题的过程

看到这个错误的,第一步就是将这个错误直接入放到百度google里面进行搜索。找到了N多篇文章,但是主要的思路就如此篇文章所写的两个解决办法: http://www.cnblogs.com/acmy/archive/2011/10/28/2227901.html

1、在hdfs的配置文件中,将dfs.permissions修改为False

2、执行这样的操作 hadoop fs -chmod 777 /user/hadoop

对于上面的第一个方法,我试了行不通,不知道是自己设置错误还是其他原因,对我此法不可行,第二个方法可行。第二个方法是让我们来修改HDFS中相应文件夹的权限,后面的/user/hadoop这个路径为HDFS中的文件路径,这样修改之后就让我们的administrator有在HDFS的相应目录下有写文件的权限(所有的用户都是写权限)。

虽然上面的第二步可以解决问题了,上传之后的文件所有者为Administrator,但是总感觉这样的方法不够优雅,而且这样修改权限会有一定的安全问题,总之就是看着不爽,就在想有没有其他的办法?

问题分析

开始仔细的观察了这个错误的详细信息,看到user=Administrator, access=WRITE。这里的user其实是我当前系统(运行客户端的计算机的操作系统)的用户名,实际期望这里的user=hadoop(hadoop是我的HADOOP上面的用户名),但是它取的是当前的系统的用户名,很明显,如果我将当前系统的用户名改为hadoop,这个肯定也是可以行得通的,但是如果后期将开发的代码部署到服务器上之后,就不能方便的修改用户,此方法明显也不够方便。

现在就想着Configuration这个是一个配置类,有没有一个参数是可以在某个地方设置以哪个用户运行呢?搜索了半天,无果。没有找到相关的配置参数。

最终只有继续分析代码, FileSystem fs = FileSystem.get(URI.create(dest), conf);代码是在此处开始对HDFS进行调用,所以就想着将HADOOP的源码下下来,debug整个调用过程,这个user=Administator是在什么时间赋予的值。理解了调用过程,还怕找不到解决问题的办法么?

跟踪代码进入 FileSystem.get-->CACHE.get()-->Key key = new Key(uri, conf);到这里的时候发现key值里面已经有Administrator了,所以关键肯定是在new key的过程。继续跟踪UserGroupInformation.getCurrentUser()-->getLoginUser()-->login.login()到这一步的时候发现用户名已经确定了,但是这个方法是Java的核心源码,是一个通用的安全认证,但对这一块不熟悉,但是debug时看到subject里面有NTUserPrincipal:Administator,所以就想着搜索一下这个东西是啥,结果就找到了下面这一篇关键的文章:

http://www.udpwork.com/item/7047.html

在此篇文章里面作者分析了hadoop的整个登录过程,对于我有用的是其中的这一段:

2.login.login();
这个会调用HadoopLoginModule的login()和commit()方法。
HadoopLoginModule的login()方法是一个空函数,只打印了一行调试日志 LOG.debug("hadoop login");
commit()方法负责把Principal添加到Subject中。
此时一个首要问题是username是什么?
在使用了kerberos的情况下,从javax.security.auth.kerberos.KerberosPrincipal的实例获取username。
在未使用kerberos的情况下,优先读取HADOOP_USER_NAME这个系统环境变量,如果不为空,那么拿它作username。否则,读取HADOOP_USER_NAME这个java环境变量。否则,从com.sun.security.auth.NTUserPrincipal或者com.sun.security.auth.UnixPrincipal的实例获取username。
如果以上尝试都失败,那么抛出异常LoginException("Can’t find user name")。
最终拿username构造org.apache.hadoop.security.User的实例添加到Subject中。

看完这一段,我明白了执行login.login的时候调用了hadoop里面的HadoopLoginModule方法,而关键是在commit方法里面,在这里优先读取HADOOP_USER_NAME系统环境变量,然后是java环境变量,如果再没有就从NTUserPrincipal等里面取。关键代码为:

  1. if (!isSecurityEnabled() && (user == null)) {
  2.   String envUser = System.getenv(HADOOP_USER_NAME);
  3.   if (envUser == null) {
  4.     envUser = System.getProperty(HADOOP_USER_NAME);
  5.   }
  6.   user = envUser == null ? null : new User(envUser);
  7. }

OK,看到这里我的需求也就解决了,只要在系统的环境变量里面添加HADOOP_USER_NAME=hadoop(HDFS上的有权限的用户,具体看自己的情况),或者在当前JDK的变量参数里面添加HADOOP_USER_NAME这个Java变量即可。我的情况添加系统环境变量更方法。

如果是在Eclipse里面运行,修改完环境变量后,记得重启一下eclipse,不然可能不会生效。

解决办法

最终,总结下来解决办法大概有三种:

1、在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看自己的情况,以后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,不然可能不生效)

2、将当前系统的帐号修改为hadoop

3、使用HDFS的命令行接口修改相应目录的权限,hadoop fs -chmod 777 /user,后面的/user是要上传文件的路径,不同的情况可能不一样,比如要上传的文件路径为hdfs://namenode/user/xxx.doc,则这样的修改可以,如果要上传的文件路径为hdfs://namenode/java/xxx.doc,则要修改的为hadoop fs -chmod 777 /java或者hadoop fs -chmod 777 /,java的那个需要先在HDFS里面建立Java目录,后面的这个是为根目录调整权限。

我喜欢第一个方法。

相关 [hdfs 客户端 错误] 推荐:

HDFS客户端的权限错误:Permission denied | IT人生录

- -
搭建了一个Hadoop的环境,Hadoop集群环境部署在几个Linux服务器上,现在想使用windows上的Java客户端来操作集群中的HDFS文件,但是在客户端运行时出现了如下的认证错误,被折磨了几天,问题终得以解决. (如果想看最终解决问题的方法拉到最后,如果想看我的问题解决思路请从上向下看).

HDFS Federation客户端(viewfs)配置攻略

- - 董的博客
Dong | 新浪微博: 西成懂 | 可以转载, 但必须以超链接形式标明文章原始出处和作者信息及 版权声明. 网址: http://dongxicheng.org/hadoop-hdfs/hdfs-federation-viewfs/. 本博客的文章集合: http://dongxicheng.org/recommend/.

HDFS-压缩

- - Java - 编程语言 - ITeye博客
文件压缩带来了两大益处1)减少存贮空间2)加速网络(磁盘)传输. 基于大数据的传输,都需要经过压缩处理. 压缩格式 工具 算法 文件扩展名 可分块. Java代码 复制代码 收藏代码. 24.        // io.compression.codecs 定义列表中的一个 . Native gzip 库减少解压缩时间在50%,压缩时间在10%(同java实现的压缩算法).

HDFS架构

- - 数据库 - ITeye博客
       在阅读了GFS的论文之后,对GFS的框架有了基本的了解,进一步学习自然是对HDFS的解析,不得不说,之前对GFS的一些了解,对理解HDFS还是很有帮助的,毕竟后者是建立在前者之上的分布式文件系统,二者在框架上可以找到很多的共同点,建议初次接触HFDS的技术人员可以先把GFS的那篇论文啃个两三遍,毕竟磨刀不砍柴工.

Hadoop剖析之HDFS

- - CSDN博客数据库推荐文章
Hadoop的分布式文件系统(HDFS)是Hadoop的很重要的一部分,本文先简单介绍HDFS的几个特点,然后再分析背后的原理,即怎样实现这种特点的. 这是HDFS最核心的特性了,把大量数据部署在便宜的硬件上,即使其中某些磁盘出现故障,HDFS也能很快恢复丢失的数据. 这个的意思是HDFS适合一次写入,多次读取的程序,文件写入后,就不需要修改了.

Hoop:Hadoop HDFS的RESTFul封装

- Vent - NoSQLFan
Hoop是对Hadoop HDFS Proxy 的改良重写,为Hadoop HDFS提供了HTTP(S)的访问接口. 通过标准的HTTP协议访问你的HDFS系统. 在运行不同版本的HDFS之间进行数据交换(这克服了一些RPC方式因版本不同而产生的兼容性问题). 将对HDFS的操作置于防火墙的保护下.

[转]HDFS用户指南

- - 小鸥的博客
本文档可以作为使用Hadoop分布式文件系统用户的起点,无论是将HDFS应用在一个Hadoop集群中还是作为一个单独的分布式文件系统使用. HDFS被设计成可以马上在许多环境中工作起来,那么一些HDFS的运行知识肯定能大大地帮助你对一个集群做配置改进和诊断. HDFS是Hadoop应用的主要分布式存储.

HDFS 读文件分析

- - 经验沉淀 知识结晶
UNIX Domain Socket是在socket架构上发展起来的用于同一台主机的进程间通讯(IPC),它不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和 应答等,只是将应用层数据从一个进程拷贝到另一个进程. UNIX Domain Socket有SOCK_DGRAM或SOCK_STREAM两种工作模式,类似于UDP和TCP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱.

Hadoop之HDFS子框架

- - CSDN博客云计算推荐文章
由图片可以看到HDFS主要包含这样几个功能组件. Namenode:存储文档的元数据信息,还有整个文件系统的目录结构. DataNode:存储文档块信息,并且文档块之间是有冗余备份的. 这里面提到了文档块的概念,同本地文件系统一样,HDFS也是按块存储的,只不过块的大小设置的相对大一些,默认为64M.

hdfs-ha热备原理

- - 开源软件 - ITeye博客
下面的总结来自于: http://dongxicheng.org/hadoop-hdfs/hdfs-ha-federation-deploy/ .            Hadoop 2.0中的HDFS增加了两个重大特性,HA和Federaion. HA即为High Availability,用于解决NameNode单点故障问题,该特性通过热备的方式为主NameNode提供一个备用者,一旦主NameNode出现故障,可以迅速切换至备NameNode,从而实现不间断对外提供服务.