之前在为客户做数据湖产品调试Spark程序的时候,遇到过一个报错:
ERROR spark.SparkContext: Error initializing SparkContext.
org.apache.hadoop.security.AccessControlException: Permission denied:user=datalake, access=WRITE, inode="/user":hdfs:supergroup:drwxr-xr-x
at
org.apache.hadoop.hdfs.server.namenode.FSPermissionChecker.check(FSPermissionChecker.java:400)
一、原因分析
从日志中大致可以看出,是因为Spark在启动阶段初始化SparkContext时遇到了write权限问题,其中当前用户为datalake,要执行write操作的目录是HDFS的/user目录。想要figure out这个问题,首先需要了解HDFS的/user目录是干嘛用的。
1.1 HDFS的home目录
注意,Hadoop 的 home 目录和 HDFS 的 home目录是两回事:
- Hadoop 的 home 目录:Hadoop的安装目录,通常会配置在环境变量PATH中;
- HDFS 的 home 目录:是指每个访问HDFS的用户目录,定义在:/user/{user_id},比如上面的/user/datalake。
比如,在列出我的mac上HDFS的所有{user_id}:
datalake$ hdfs dfs -ls /user
Found 1 items
drwxr-xr-x - ycaha supergroup 0 2019-08-05 13:05 /user/hive
很显然,HDFS中的home目录只有/user/hive,其中hive为user_id。从权限描述可以看出,/user/hive是个目录(首字母如果是d表示目录,如果是-表示文件),owner为ycaha,所属用户组为supergroup,ycaha、supergroup、以及其他用户对/user/hive的权限分别为:可读可写可执行、可读不可写可执行、可读不可写可执行(rwxr-xr-x,每三个字符一组表示用户或者用户组的权限)。关于linux用户权限可以参考:https://www.cnblogs.com/garfieldcgf/p/8323489.html
1.2 创建新的user_id
比如以datalake用户去执行Spark程序,Spark在启动阶段初始化SparkContext时需要访问工作目录/user/datalake,此时必须保证两个条件都成立:
-
- HDFS存在目录/user/datalake;
-
- datalake用户对于目录/user/datalake具有write权限;
可以通过如下命令来创建新的user_id:
# 首先使用具有write权限的用户,比如上面的ycaha
# 然后创建新user_id目录
hdfs dfs -mkdir /user/datalake
可以看到新的user_id:
drwxr-xr-x - ycaha supergroup 0 2019-10-17 20:53 /user/datalake
drwxr-xr-x - ycaha supergroup 0 2019-08-05 13:05 /user/hive
但是datalake用户的权限是-xr,即不具备write权限,因此接下来需要修改用户权限或者目录权限,比如下面修改目录/user/datalake的权限为775(datalake具有可读可写可执行权限):
hdfs dfs -chmod 775 /user/datalake
得到:
ycaha$ hdfs dfs -ls /user/
Found 2 items
drwxrwxr-x - ycaha supergroup 0 2019-10-17 20:53 /user/datalake
drwxr-xr-x - ycaha supergroup 0 2019-08-05 13:05 /user/hive
二、解决方案
2.1 方案1
直接像1.2中一样,创建一个新的user_id(即datalake)并赋予用户write权限即可。
2.2 方案2:修改默认的spark.yarn.stagingDir配置
spark.yarn.stagingDir是Spark的一个配置项,用于指定Spark在提交应用程序时使用的暂存目录,该配置项配置在spark-defaults.conf中,其默认值是当前用户在文件系统中的主目录,比如/user/datalake。
因此可以通过修改spark.yarn.stagingDir的值,将其指向一个“提交Spark job用户”具有write权限的目录即可,比如/usr/sparkjob/tmp/。
也可以在提交Spark job的时候,显式地指定配置项spark.yarn.stagingDir的值,比如:
--conf spark.yarn.stagingDir=hdfs:///
注意:hdfs:///不可省略。
如有错误之处,敬请指正!
参考:
https://www.cloudera.com/documentation/enterprise/latest/PDF/cloudera-spark.pdf
https://stackoverflow.com/questions/42723604/how-to-set-spark-job-staging-location
https://www.jianshu.com/p/e7838e9e5c44