专栏首页Hadoop实操0554-6.1.0-同一java进程中同时访问认证和非认证集群的问题(续)

0554-6.1.0-同一java进程中同时访问认证和非认证集群的问题(续)

作者:李继武

1

文档编写目的

Fayson在前面的文章《0553-6.1.0-如何使用Java代码同时访问安全和非安全CDH集群》,本篇文章介绍在同一Java进程中,通过多线程同时访问Kerberos认证集群和非认证集群时出现的一些异常及解决方法。

  • 测试环境:CDH6.1.0

2

集群准备

1.非认证集群,在该集群中根目录下创建了一个NONEKRBCDH目录用以标识

2.认证集群,在该集群中根目录下创建了一个KRBCDH目录用以标识

3

环境准备

本次测试是将代码直接放在linux系统上运行,所以将两套集群的配置文件分别放在两个不同的目录下:

1.认证集群的配置信息包括krb5.conf和keytab文件放在/root/krbconf下

2.非认证集群的配置信息放在/root/conf下

4

工具类

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("hive@MACRO.COM", 
                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("hive@MACRO.COM", 
                    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("hive@MACRO.COM", 
                    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("hive@MACRO.COM", 
                    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();
    }
}

问题:

在访问认证集群的线程认证结束之后准备访问集群时,会出现这时正好被访问非认证集群的线程把认证信息清除的情况,无法找到用户,导致报错。

6

总结

1.因为java进程的kerberos身份认证信息存放在UserGroupInformation的静态字段中,因此该进程的内存中仅能存取一份身份信息,这也导致一个线程修改该身份信息之后会直接影响另一个线程。

2.如果要在不同的线程中访问认证集群和非认证集群,只能通过加锁和重置身份信息的方式,但这会显著影响程序执行效率。

提示:代码块部分可以左右滑动查看噢

为天地立心,为生民立命,为往圣继绝学,为万世开太平。 温馨提示:如果使用电脑查看图片不清晰,可以使用手机打开文章单击文中的图片放大查看高清原图。

推荐关注Hadoop实操,第一时间,分享更多Hadoop干货,欢迎转发和分享。

原创文章,欢迎转载,转载请注明:转载自微信公众号Hadoop实操

本文分享自微信公众号 - Hadoop实操(gh_c4c535955d0f),作者:Fayson

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Cloudera产品支持生命周期策略

    本文主要介绍Cloudera企业版产品支持的生命周期,包括CDH每个版本终止支持的预计日期。了解该策略主要是方便大家在规划搭建/升级CDH集群时的版本选择,不代...

    Fayson
  • 如何开发HBase Endpoint类型的Coprocessor以及部署使用

    Fayson
  • 0524-6.1-如何使用Cloudera Manager启用HDFS的HA

    在HDFS集群中NameNode存在单点故障(SPOF),对于只有一个NameNode的集群,如果NameNode机器出现意外,将导致整个集群无法使用。为了解决...

    Fayson
  • 导致python中import错误的原因是什么

    Python程序可以调用一组基本的函数(即内建函数),比如print()、input()和len()等函数。Python本身也内置一组模块(即标准库)。每个模块...

    砸漏
  • PEP8编码规范,及开发中的一些惯例和建

    规范的代码给人的第一感觉是【美观】,美的东西总是更加的吸引人,也愿意观看。不规范的代码风格总是令人感到难受,检查会很困难。所以美观带来的是代码的【可读性】强,...

    py3study
  • 响铃:“高烧不退”的人工智能,谁更具话语权?

    如今,AI已是大家最喜闻乐见的话题。无论是巨头还是创业者,都纷纷推出了相关产品,比如三星在11月21日发布了Bixby中文版,又比如灵伴即时在11月22日发布的...

    曾响铃
  • 中国哪个省市AI最吸金?2018 AI产业投融资报告揭晓

    【新智元导读】投中研究院最新发布《2018 AI产业投融资研究报告》,对2018年中美科技巨头AI产业战略投资布局、AI在各行业的发展现状等进行了全面分析。

    新智元
  • Test Code Highlight

    BORBER
  • MySQL show语句

    JavaEdge
  • 怕不怕?第一批AI已经开始干这种事了

    导读:我们曾在《那个陪你聊微信、发自拍的妹子,可能不是人》中提到过跟你自动聊微信的机器人,在本文中我们会给你看更多类似案例。

    华章科技

扫码关注云+社区

领取腾讯云代金券