通过 Dataproc 的 Spark 作业的 Hadoop 安全性 GroupMappingServiceProvider 异常 API
Hadoop security GroupMappingServiceProvider exception for Spark job via Dataproc API
我正在尝试 运行 在 google dataproc 集群上执行 Spark 作业,但出现以下错误:
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: class org.apache.hadoop.security.JniBasedUnixGroupsMapping not org.apache.hadoop.security.GroupMappingServiceProvider
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2330)
at org.apache.hadoop.security.Groups.<init>(Groups.java:108)
at org.apache.hadoop.security.Groups.<init>(Groups.java:102)
at org.apache.hadoop.security.Groups.getUserToGroupsMappingService(Groups.java:450)
at org.apache.hadoop.security.UserGroupInformation.initialize(UserGroupInformation.java:310)
at org.apache.hadoop.security.UserGroupInformation.ensureInitialized(UserGroupInformation.java:277)
at org.apache.hadoop.security.UserGroupInformation.loginUserFromSubject(UserGroupInformation.java:833)
at org.apache.hadoop.security.UserGroupInformation.getLoginUser(UserGroupInformation.java:803)
at org.apache.hadoop.security.UserGroupInformation.getCurrentUser(UserGroupInformation.java:676)
at org.apache.spark.util.Utils$$anonfun$getCurrentUserName.apply(Utils.scala:2430)
at org.apache.spark.util.Utils$$anonfun$getCurrentUserName.apply(Utils.scala:2430)
at scala.Option.getOrElse(Option.scala:121)
at org.apache.spark.util.Utils$.getCurrentUserName(Utils.scala:2430)
at org.apache.spark.SparkContext.<init>(SparkContext.scala:295)
at org.apache.spark.api.java.JavaSparkContext.<init>(JavaSparkContext.scala:58)
at com.my.package.spark.SparkModule.provideJavaSparkContext(SparkModule.java:59)
at com.my.package.spark.SparkModule$$ModuleAdapter$ProvideJavaSparkContextProvidesAdapter.get(SparkModule$$ModuleAdapter.java:140)
at com.my.package.spark.SparkModule$$ModuleAdapter$ProvideJavaSparkContextProvidesAdapter.get(SparkModule$$ModuleAdapter.java:101)
at dagger.internal.Linker$SingletonBinding.get(Linker.java:364)
at spark.Main$$InjectAdapter.get(Main$$InjectAdapter.java:65)
at spark.Main$$InjectAdapter.get(Main$$InjectAdapter.java:23)
at dagger.ObjectGraph$DaggerObjectGraph.get(ObjectGraph.java:272)
at spark.Main.main(Main.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:755)
at org.apache.spark.deploy.SparkSubmit$.doRunMain(SparkSubmit.scala:180)
at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:205)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:119)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.RuntimeException: class org.apache.hadoop.security.JniBasedUnixGroupsMapping not org.apache.hadoop.security.GroupMappingServiceProvider
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2324)
... 31 more
Dataproc 版本:1.1.51 和 1.2.15
工作配置:
地区:全球
集群 my-cluster
工作类型:Spark
Jar 文件:gs://bucket/jars/spark-job.jar
主要 class 或 jar:spark.Main
参数:
属性:
spark.driver.extraClassPath: /path/to/google-api-client-1.20.0.jar
spark.driver.userClassPathFirst: 真
我没问题运行在命令行上这样设置:
spark-submit --conf "spark.driver.extraClassPath=/path/to/google-api-client-1.20.0.jar" --conf "spark.driver.userClassPathFirst=true" --class spark.Main /path/to/spark-job.jar
但是 UI/API 不允许您同时传递 class 名称和 jar,所以它看起来像这样:
spark-submit --conf spark.driver.extraClassPath=/path/to/google-api-client-1.20.0.jar --conf spark.driver.userClassPathFirst=true --class spark.Main --jars /tmp/1f4d5289-37af-4311-9ccc-5eee34acaf62/spark-job.jar /usr/lib/hadoop/hadoop-common.jar
我不知道是不是提供 extraClassPath 有问题,还是 spark-job.jar 和 hadoop-common.jar 有某种冲突。
我 认为 这是由 userClassPathFirst 和 /usr/lib/hadoop/hadoop-common.jar 的组合引起的,jar 是 Dataproc 指定用于 spark-submit 的 jar。在某些情况下,将使用来自用户 class 加载器的 GroupMappingServiceProvider 实例,而在其他情况下,将使用来自系统 class 加载器的实例。由于从一个 class 加载程序加载的 class 不等于从另一个 class 加载程序加载的相同 class,您最终会遇到此异常。
而不是 userClassPathFirst,使用像 maven shade 这样的东西来重新定位冲突的 classes 是否有意义?
如果您不想关闭 spark.driver.userClassPathFirst=true
,您可以检查 "org.apache.spark" %% "spark-core" % SPARK_VERSION
依赖项是否存在以及范围是否已正确定义。
当 spark-core
jar 在类路径中时,不会抛出异常。
对于遇到此问题的任何人(即使您没有使用 Spark)
此处引发此异常Configuration.java#L2585
Configuration.java
异常的含义
Hadoop 告诉你,第二个 class 是 而不是 另一个 class 的 subclass
或 subinterface
。
这就是 Class.isAssignableFrom(OtherClass)
在上图中 2584
行所做的事情
The java.lang.Class.isAssignableFrom()
determines if the class or
interface represented by this Class object is either the same as,
or is a superclass or superinterface of, the class or
interface represented by the specified Class parameter.
但我们知道
org.apache.hadoop.security.GroupMappingServiceProvider
是超class的
org.apache.hadoop.security.JniBasedUnixGroupsMapping
那怎么会这样呢?
为什么会这样
发生这种情况的原因有多种
- 您的
classpath
上有两个版本的 hadoop-client
库
- 您已将 Hadoop 与一个库捆绑在一起,但它的版本或发行版与另一个捆绑的 Hadoop 库不同。
- 您的 class 路径指向多个 Hadoop 安装或 Hadoop 客户端,而它们应该只有一个
hadoop-client
jar
- 您使用了错误的 Hadoop 包 - 例如,您的目标是 Cloudera 环境并且您使用的是开源版本的 Hadoop 库
解决方案
- 使所有 Hadoop 库版本符合同一版本
- 创建一个元包,并在所有插件、客户端、包中仅依赖于这个元包 jar。
- 切换到使用客户端库的正确发行版本 - 示例:
- Cloudera 阴影
hadoop-client-api
- Cloudera 阴影
hadoop-client-runtime
- 通过
hadoop-client-api
和 hadoop-client-runtime
使用阴影版本的 Hadoop 客户端库
我正在尝试 运行 在 google dataproc 集群上执行 Spark 作业,但出现以下错误:
Exception in thread "main" java.lang.RuntimeException: java.lang.RuntimeException: class org.apache.hadoop.security.JniBasedUnixGroupsMapping not org.apache.hadoop.security.GroupMappingServiceProvider
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2330)
at org.apache.hadoop.security.Groups.<init>(Groups.java:108)
at org.apache.hadoop.security.Groups.<init>(Groups.java:102)
at org.apache.hadoop.security.Groups.getUserToGroupsMappingService(Groups.java:450)
at org.apache.hadoop.security.UserGroupInformation.initialize(UserGroupInformation.java:310)
at org.apache.hadoop.security.UserGroupInformation.ensureInitialized(UserGroupInformation.java:277)
at org.apache.hadoop.security.UserGroupInformation.loginUserFromSubject(UserGroupInformation.java:833)
at org.apache.hadoop.security.UserGroupInformation.getLoginUser(UserGroupInformation.java:803)
at org.apache.hadoop.security.UserGroupInformation.getCurrentUser(UserGroupInformation.java:676)
at org.apache.spark.util.Utils$$anonfun$getCurrentUserName.apply(Utils.scala:2430)
at org.apache.spark.util.Utils$$anonfun$getCurrentUserName.apply(Utils.scala:2430)
at scala.Option.getOrElse(Option.scala:121)
at org.apache.spark.util.Utils$.getCurrentUserName(Utils.scala:2430)
at org.apache.spark.SparkContext.<init>(SparkContext.scala:295)
at org.apache.spark.api.java.JavaSparkContext.<init>(JavaSparkContext.scala:58)
at com.my.package.spark.SparkModule.provideJavaSparkContext(SparkModule.java:59)
at com.my.package.spark.SparkModule$$ModuleAdapter$ProvideJavaSparkContextProvidesAdapter.get(SparkModule$$ModuleAdapter.java:140)
at com.my.package.spark.SparkModule$$ModuleAdapter$ProvideJavaSparkContextProvidesAdapter.get(SparkModule$$ModuleAdapter.java:101)
at dagger.internal.Linker$SingletonBinding.get(Linker.java:364)
at spark.Main$$InjectAdapter.get(Main$$InjectAdapter.java:65)
at spark.Main$$InjectAdapter.get(Main$$InjectAdapter.java:23)
at dagger.ObjectGraph$DaggerObjectGraph.get(ObjectGraph.java:272)
at spark.Main.main(Main.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:755)
at org.apache.spark.deploy.SparkSubmit$.doRunMain(SparkSubmit.scala:180)
at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:205)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:119)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.RuntimeException: class org.apache.hadoop.security.JniBasedUnixGroupsMapping not org.apache.hadoop.security.GroupMappingServiceProvider
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2324)
... 31 more
Dataproc 版本:1.1.51 和 1.2.15
工作配置:
地区:全球
集群 my-cluster
工作类型:Spark
Jar 文件:gs://bucket/jars/spark-job.jar
主要 class 或 jar:spark.Main
参数:
属性:
spark.driver.extraClassPath: /path/to/google-api-client-1.20.0.jar
spark.driver.userClassPathFirst: 真
我没问题运行在命令行上这样设置:
spark-submit --conf "spark.driver.extraClassPath=/path/to/google-api-client-1.20.0.jar" --conf "spark.driver.userClassPathFirst=true" --class spark.Main /path/to/spark-job.jar
但是 UI/API 不允许您同时传递 class 名称和 jar,所以它看起来像这样:
spark-submit --conf spark.driver.extraClassPath=/path/to/google-api-client-1.20.0.jar --conf spark.driver.userClassPathFirst=true --class spark.Main --jars /tmp/1f4d5289-37af-4311-9ccc-5eee34acaf62/spark-job.jar /usr/lib/hadoop/hadoop-common.jar
我不知道是不是提供 extraClassPath 有问题,还是 spark-job.jar 和 hadoop-common.jar 有某种冲突。
我 认为 这是由 userClassPathFirst 和 /usr/lib/hadoop/hadoop-common.jar 的组合引起的,jar 是 Dataproc 指定用于 spark-submit 的 jar。在某些情况下,将使用来自用户 class 加载器的 GroupMappingServiceProvider 实例,而在其他情况下,将使用来自系统 class 加载器的实例。由于从一个 class 加载程序加载的 class 不等于从另一个 class 加载程序加载的相同 class,您最终会遇到此异常。
而不是 userClassPathFirst,使用像 maven shade 这样的东西来重新定位冲突的 classes 是否有意义?
如果您不想关闭 spark.driver.userClassPathFirst=true
,您可以检查 "org.apache.spark" %% "spark-core" % SPARK_VERSION
依赖项是否存在以及范围是否已正确定义。
当 spark-core
jar 在类路径中时,不会抛出异常。
对于遇到此问题的任何人(即使您没有使用 Spark)
此处引发此异常Configuration.java#L2585
Configuration.java
异常的含义
Hadoop 告诉你,第二个 class 是 而不是 另一个 class 的 subclass
或 subinterface
。
这就是 Class.isAssignableFrom(OtherClass)
在上图中 2584
行所做的事情
The
java.lang.Class.isAssignableFrom()
determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.
但我们知道
org.apache.hadoop.security.GroupMappingServiceProvider
是超class的
org.apache.hadoop.security.JniBasedUnixGroupsMapping
那怎么会这样呢?
为什么会这样
发生这种情况的原因有多种
- 您的
classpath
上有两个版本的 - 您已将 Hadoop 与一个库捆绑在一起,但它的版本或发行版与另一个捆绑的 Hadoop 库不同。
- 您的 class 路径指向多个 Hadoop 安装或 Hadoop 客户端,而它们应该只有一个
hadoop-client
jar - 您使用了错误的 Hadoop 包 - 例如,您的目标是 Cloudera 环境并且您使用的是开源版本的 Hadoop 库
hadoop-client
库
解决方案
- 使所有 Hadoop 库版本符合同一版本
- 创建一个元包,并在所有插件、客户端、包中仅依赖于这个元包 jar。
- 切换到使用客户端库的正确发行版本 - 示例:
- Cloudera 阴影
hadoop-client-api
- Cloudera 阴影
hadoop-client-runtime
- Cloudera 阴影
- 通过
hadoop-client-api
和hadoop-client-runtime
使用阴影版本的 Hadoop 客户端库