我开发了一个在Hadoop Edge Node(Cloudera CDH 5.9.1)上运行的Java程序。它“永远”运行,因为它是一个回复请求的(微)服务。它接收来自其他地方运行的webapp的请求,并使用Impala JDBC驱动程序从Impala中提取数据并发回数据。
它在大约10个小时内运行良好,然后它变得无法获得Impala JDBC连接。你会发现堆栈跟踪和这个问题的结尾。简而言之,它会抛出javax.security.auth.login.LoginException: Unable to obtain Principal Name for authentication
。
我的理解是Impala JDBC驱动程序变为能够对Kerberos进行身份验证,因为Kerberos票证已过期。因此,为了确保启动程序的用户具有Kerberos票证,我在创建JDBC连接之前添加了一段代码。我读了那两个Stackoverflow线程:
他们非常清楚地解释了问题和解决方案。这是我尝试实现它(我不明白为什么它为Impala失败):
public class KerberosRelogger {
private final static Logger logger = LogManager.getLogger();
public static String userName;
public static String user;
public static String keytab;
public static Configuration conf;
private static UserGroupInformation ugi;
static {
try {
init();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void init() throws IOException {
userName = System.getProperty("user.name");
user = userName + "@MY_REALM";
keytab = System.getProperty("user.home") + "/" + userName + ".keytab";
conf = new Configuration();
conf.addResource(new Path("file:///etc/hadoop/conf/core-site.xml"));
conf.addResource(new Path("file:///etc/hadoop/conf/hdfs-site.xml"));
UserGroupInformation.setConfiguration(conf);
ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(user, keytab);
logger.debug("userName : {}", userName);
logger.debug("user : {}", user);
logger.debug("keytab : {}", keytab);
}
public static void testHadoopConnexion() throws IOException {
ugi.checkTGTAndReloginFromKeytab();
FileSystem fs = FileSystem.get(conf);
FileStatus[] statuses = fs.listStatus(new Path("/"));
List<String> dirNames = new ArrayList<>();
for (FileStatus status : statuses) {
dirNames.add(status.getPath().getName());
}
logger.debug("HDFS root dirs : " + dirNames);
}
private static Connection createImpalaConnection() throws IOException {
ugi.checkTGTAndReloginFromKeytab();
String IMPALAD_HOST = "my_node";
String jdbcUrl = "jdbc:impala://" + IMPALAD_HOST + ":21050;AuthMech=1;KrbRealm=MY_REALM;KrbHostFQDN=" + IMPALAD_HOST + ";KrbServiceName=impala;SSL=1";
Properties props = new Properties();
props.put("user", userName);
props.put("password", "");
try {
Connection connection = DriverManager.getConnection(jdbcUrl, props);
return connection;
} catch (SQLException e) {
throw new RuntimeException("Fail to create JDBC connection", e);
}
}
private static void testImpalaConnection() throws IOException, SQLException {
int n = 0;
try (Connection cnx = createImpalaConnection()) {
String sql = "show databases";
try (PreparedStatement ps = cnx.prepareStatement(sql)) {
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
n++;
}
}
}
}
logger.debug("{} Impala databases", n);
}
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
logger.debug("Test Hadoop connection");
testHadoopConnexion();
logger.debug("Hadoop connection - SUCCESS");
} catch (Exception e) {
logger.error("Hadoop connection - FAIL", e);
}
System.out.println();
try {
logger.debug("Test Impala connection");
testImpalaConnection();
logger.debug("Impala connection - SUCCESS");
} catch (Exception e) {
logger.error("Impala connection - FAIL", e);
}
}
}, 1, 10, TimeUnit.SECONDS);
}
}
如果故障单过期或者我使用命令行执行“kdestroy”,Hadoop HDFS列表仍然有效,但Impala JDBC驱动程序无法建立连接。
为什么Impala无法进行身份验证,而Hadoop API调用有效?它是Hadoop API的工作原理,它意味着程序化的重新编写工作,并且有一个“新鲜”的票据。我对吗 ?为什么Impala失败了呢?
异常堆栈跟踪
Caused by: java.sql.SQLException: [Simba][ImpalaJDBCDriver](500168) Error creating login context using ticket cache: Unable to obtain Principal Name for authentication .
at com.cloudera.hivecommon.api.HiveServer2ClientFactory.createTransport(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.hivecommon.api.HiveServer2ClientFactory.createClient(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.hivecommon.core.HiveJDBCCommonConnection.establishConnection(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.impala.core.ImpalaJDBCConnection.establishConnection(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.core.LoginTimeoutConnection.connect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.common.BaseConnectionFactory.doConnect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.common.AbstractDriver.connect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at java.sql.DriverManager.getConnection(DriverManager.java:664) ~[?:1.8.0_92]
at java.sql.DriverManager.getConnection(DriverManager.java:208) ~[?:1.8.0_92]
...
Caused by: com.cloudera.support.exceptions.GeneralException: [Simba][ImpalaJDBCDriver](500168) Error creating login context using ticket cache: Unable to obtain Principal Name for authentication .
at com.cloudera.hivecommon.api.HiveServer2ClientFactory.createTransport(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.hivecommon.api.HiveServer2ClientFactory.createClient(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.hivecommon.core.HiveJDBCCommonConnection.establishConnection(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.impala.core.ImpalaJDBCConnection.establishConnection(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.core.LoginTimeoutConnection.connect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.common.BaseConnectionFactory.doConnect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.common.AbstractDriver.connect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at java.sql.DriverManager.getConnection(DriverManager.java:664) ~[?:1.8.0_92]
at java.sql.DriverManager.getConnection(DriverManager.java:208) ~[?:1.8.0_92]
...
Caused by: javax.security.auth.login.LoginException: Unable to obtain Principal Name for authentication
at com.sun.security.auth.module.Krb5LoginModule.promptForName(Krb5LoginModule.java:841) ~[?:1.8.0_92]
at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:704) ~[?:1.8.0_92]
at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:617) ~[?:1.8.0_92]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_92]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_92]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_92]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_92]
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) ~[?:1.8.0_92]
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195) ~[?:1.8.0_92]
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682) ~[?:1.8.0_92]
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680) ~[?:1.8.0_92]
at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_92]
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) ~[?:1.8.0_92]
at javax.security.auth.login.LoginContext.login(LoginContext.java:587) ~[?:1.8.0_92]
at com.cloudera.jdbc.kerberos.Kerberos.getSubjectViaTicketCache(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.hivecommon.api.HiveServer2ClientFactory.createTransport(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.hivecommon.api.HiveServer2ClientFactory.createClient(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.hivecommon.core.HiveJDBCCommonConnection.establishConnection(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.impala.core.ImpalaJDBCConnection.establishConnection(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.core.LoginTimeoutConnection.connect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.common.BaseConnectionFactory.doConnect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at com.cloudera.jdbc.common.AbstractDriver.connect(Unknown Source) ~[ImpalaJDBC41.jar:ImpalaJDBC_2.5.41.1061]
at java.sql.DriverManager.getConnection(DriverManager.java:664) ~[?:1.8.0_92]
at java.sql.DriverManager.getConnection(DriverManager.java:208) ~[?:1.8.0_92]
...