0554 | 您所在的位置:网站首页 › hadoop有什么认证 › 0554 |
1 文档编写目的
Fayson在前面的文章《0553-6.1.0-如何使用Java代码同时访问安全和非安全CDH集群》,本篇文章介绍在同一Java进程中,通过多线程同时访问Kerberos认证集群和非认证集群时出现的一些异常及解决方法。 测试环境:CDH6.1.0 2 集群准备1.非认证集群,在该集群中根目录下创建了一个NONEKRBCDH目录用以标识 2.认证集群,在该集群中根目录下创建了一个KRBCDH目录用以标识 本次测试是将代码直接放在linux系统上运行,所以将两套集群的配置文件分别放在两个不同的目录下: 1.认证集群的配置信息包括krb5.conf和keytab文件放在/root/krbconf下 2.非认证集群的配置信息放在/root/conf下 1.初始化配置文件工具类 package com.cloudera.hdfs.utils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IOUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; public class HDFSUtils { public static Configuration initConfiguration(String confPath) { Configuration configuration = new Configuration(); System.out.println(confPath + File.separator + "core-site.xml"); configuration.addResource(new Path(confPath + File.separator +"core-site.xml")); configuration.addResource(new Path(confPath + File.separator +"hdfs-site.xml")); return configuration; } } 5 代码测试1.如下测试是在两个线程循环访问两个集群,每个线程连接时都执行,UserGroupInformation.setConfiguration操作 package com.cloudera.hdfs; import com.amazonaws.services.workdocs.model.User; import com.cloudera.hdfs.utils.HDFSUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.UserGroupInformation; import java.io.File; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //初始化认证集群配置文件 Configuration configuration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "krbconf"); configuration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问认证集群 new Thread(() -> { try { while (true) { //配置kerberos认证的配置文件 System.setProperty("java.security.krb5.conf", File.separator + "root" + File.separator+ "krbconf" + File.separator + "krb5.conf"); //进行身份认证 UserGroupInformation.setConfiguration(configuration); UserGroupInformation.loginUserFromKeytab("[email protected]", File.separator + "root"+ File.separator + "krbconf" + File.separator + "hive.keytab"); System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(configuration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("KRB:" + file.getPath()); } } } catch (Exception e) { e.printStackTrace(); } }).start(); //初始化非认证配置文件 Configuration noAuthconfiguration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "conf"); noAuthconfiguration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问非认证集群 new Thread(() -> { try { while (true) { System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); UserGroupInformation.setConfiguration(noAuthconfiguration); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(noAuthconfiguration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("NONEKRB:" + file.getPath()); } } } catch (Exception e) { e.printStackTrace(); } }).start(); } }问题: 在访问认证集群的线程认证结束之后准备访问集群,这时访问非认证集群的线程将UserGroupInformation中的认证方式改成SIMPLE之后,导致访问认证集群的线程报错:认证方式不对 2.在上一步的基础上,将线程中认证访问集群的代码加锁 package com.cloudera.hdfs; import com.amazonaws.services.workdocs.model.User; import com.cloudera.hdfs.utils.HDFSUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.UserGroupInformation; import java.io.File; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //初始化认证集群配置文件 Configuration configuration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "krbconf"); configuration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问认证集群 new Thread(() -> { try { while (true) { synchronized ("A") { //配置kerberos认证的配置文件 System.setProperty("java.security.krb5.conf", File.separator + "root" + File.separator+ "krbconf" + File.separator + "krb5.conf"); //进行身份认证 UserGroupInformation.setConfiguration(configuration); UserGroupInformation.loginUserFromKeytab("[email protected]", File.separator + "root"+ File.separator + "krbconf" + File.separator + "hive.keytab"); System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(configuration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("KRB:" + file.getPath()); } } } } catch (Exception e) { e.printStackTrace(); } }).start(); //初始化非认证配置文件 Configuration noAuthconfiguration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "conf"); noAuthconfiguration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问非认证集群 new Thread(() -> { try { while (true) { synchronized ("A") { System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); UserGroupInformation.setConfiguration(noAuthconfiguration); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(noAuthconfiguration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("NONEKRB:" + file.getPath()); } } } } catch (Exception e) { e.printStackTrace(); } }).start(); } }问题: 此时虽然不再报错了,但是我们从结果中看出,两个线程访问的是同一个集群 原因在于没有重置UserGroupInformation 3.在上一步的基础上,访问非认证集群之前增加重置UserGroupInformation操作 package com.cloudera.hdfs; import com.amazonaws.services.workdocs.model.User; import com.cloudera.hdfs.utils.HDFSUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.UserGroupInformation; import java.io.File; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //初始化认证集群配置文件 Configuration configuration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "krbconf"); configuration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问认证集群 new Thread(() -> { try { while (true) { synchronized ("A") { //配置kerberos认证的配置文件 System.setProperty("java.security.krb5.conf", File.separator + "root" + File.separator+ "krbconf" + File.separator + "krb5.conf"); //进行身份认证 UserGroupInformation.setConfiguration(configuration); UserGroupInformation.loginUserFromKeytab("[email protected]", File.separator + "root"+ File.separator + "krbconf" + File.separator + "hive.keytab"); System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(configuration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("KRB:" + file.getPath()); } } } } catch (Exception e) { e.printStackTrace(); } }).start(); //初始化非认证配置文件 Configuration noAuthconfiguration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "conf"); noAuthconfiguration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问非认证集群 new Thread(() -> { try { while (true) { synchronized ("A") { //重置认证信息 UserGroupInformation.reset(); System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); UserGroupInformation.setConfiguration(noAuthconfiguration); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(noAuthconfiguration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("NONEKRB:" + file.getPath()); } } } } catch (Exception e) { e.printStackTrace(); } }).start(); } }从结果来看,测试成功: 4.进一步测试增加重置UserGroupInformation但是不加锁的情况 package com.cloudera.hdfs; import com.amazonaws.services.workdocs.model.User; import com.cloudera.hdfs.utils.HDFSUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.UserGroupInformation; import java.io.File; import java.io.IOException; public class Test { public static void main(String[] args) throws IOException { //初始化认证集群配置文件 Configuration configuration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "krbconf"); configuration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问认证集群 new Thread(() -> { try { while (true) { //synchronized ("A") { //配置kerberos认证的配置文件 System.setProperty("java.security.krb5.conf", File.separator + "root" + File.separator+ "krbconf" + File.separator + "krb5.conf"); //进行身份认证 UserGroupInformation.setConfiguration(configuration); UserGroupInformation.loginUserFromKeytab("[email protected]", File.separator + "root"+ File.separator + "krbconf" + File.separator + "hive.keytab"); System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(configuration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("KRB:" + file.getPath()); } //} } } catch (Exception e) { e.printStackTrace(); } }).start(); //初始化非认证配置文件 Configuration noAuthconfiguration = HDFSUtils.initConfiguration(File.separator + "root" + File.separator + "conf"); noAuthconfiguration.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem"); //该线程循环访问非认证集群 new Thread(() -> { try { while (true) { //synchronized ("A") { //重置认证信息 UserGroupInformation.reset(); System.out.println("当前用户是:" + UserGroupInformation.getCurrentUser()); UserGroupInformation.setConfiguration(noAuthconfiguration); //列出根目录下所有文件 FileSystem fileSystem = FileSystem.get(noAuthconfiguration); FileStatus[] files = fileSystem.listStatus(new Path("hdfs://nameservice1/")); for (FileStatus file : files) { System.out.println("NONEKRB:" + file.getPath()); } //} } } catch (Exception e) { e.printStackTrace(); } }).start(); } }问题: 在访问认证集群的线程认证结束之后准备访问集群时,会出现这时正好被访问非认证集群的线程把认证信息清除的情况,无法找到用户,导致报错。 1.因为java进程的kerberos身份认证信息存放在UserGroupInformation的静态字段中,因此该进程的内存中仅能存取一份身份信息,这也导致一个线程修改该身份信息之后会直接影响另一个线程。 2.如果要在不同的线程中访问认证集群和非认证集群,只能通过加锁和重置身份信息的方式,但这会显著影响程序执行效率。 |
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |