无法使用 java 连接到 AWS EMR 上的配置单元

Not able to connect to hive on AWS EMR using java

我已经用 Hive 设置了 AWS EMR 集群。我想使用 java 从我的本地机器连接到 hive thrift 服务器。我尝试了以下代码-

Class.forName("com.amazon.hive.jdbc3.HS2Driver");
con = DriverManager.getConnection("jdbc:hive2://ec2XXXX.compute-1.amazonaws.com:10000/default","hadoop", "");

http://docs.aws.amazon.com/ElasticMapReduce/latest/DeveloperGuide/HiveJDBCDriver.html.As 在开发者指南中提到,将与 hive jdbc 驱动程序相关的 jar 添加到 class 路径。 但是我在尝试建立连接时遇到异常。 我能够使用上面的代码(使用不同的 jdbc 驱动程序)连接到简单 hadoop 集群上的配置单元服务器。 如果我遗漏了什么,有人可以建议吗? 是否可以使用配置单元从本地计算机连接到 AWS EMR 上的配置单元服务器 jdbc?

(来自评论的合并答案)

Hive 运行 在端口 10000 上,但仅在本地,您必须创建到 emr 的 ssh 隧道。

以下来自documentation for hive 0.13.1

创建隧道

ssh -o ServerAliveInterval=10 -i path-to-key-file -N -L 10000:localhost:10000 hadoop@master-public-dns-name 

连接到 JDBC

 jdbc:hive2://localhost:10000/default

您可以使用库 JSch 中的代码

public static void portForwardForHive() {
    try {
        if(session != null && session.isConnected()) {
            return;
        }

        JSch jsch = new JSch();
        jsch.addIdentity(PATH_TO_SSH_KEY_PEM);
        String host = REMOTE_HOST;
        session = jsch.getSession(USER, host, 22);

        // username and password will be given via UserInfo interface.
        UserInfo ui = new MyUserInfo();
        session.setUserInfo(ui);

        session.connect();
        int assingedPort = session.setPortForwardingL(LPORT, RHOST, RPORT);
        System.out.println("Port forwarding done for the post : " + assingedPort);
    } catch (Exception e) {
        System.out.println(e);
    }
}

不确定您是否已经解决了这个问题,但它是 EMR 中的一个错误,这让我很头疼。

对于像您正在做的直接 jdbc 连接,您必须在阴影 uber-jar 中包含 jdbc 驱动程序。对于 jdbc 从数据帧内访问,您无法访问 uber-jar 中的 jar(另一个不相关的错误),但您必须在命令行中指定它(S3 是保存它们的方便位置):

--文件 s3://mybucketJAR/postgresql-9.4-1201.jdbc4.jar

但是,即使在这之后,如果您专门尝试访问配置单元,您将 运行 陷入另一个问题。 Amazon 构建了自己的 jdbc 驱动程序,与普通的 Hive 驱动程序(com.amazon.hive.jdbc41.HS2Driver)具有不同的 class 层次结构,但是 EMR 集群包含标准的 Hive jdbc 标准路径中的驱动程序 (org.apache.hive.jdbc.HiveDriver)。

这会自动注册为能够处理 jdbc:hive 和 jdbc:hive2 url,因此当您尝试连接到配置单元 URL 时,它会首先找到这个并使用它——即使你专门注册了亚马逊的。不幸的是,这个与亚马逊的 Hive EMR 版本不兼容。

有两种可能的解决方案:

1:找到有问题的驱动程序并注销它: Scala 示例:

val jdbcDrv = Collections.list(DriverManager.getDrivers)

for(i <- 0 until jdbcDrv.size) {
  val drv = jdbcDrv.get(i)
  val drvName = drv.getClass.getName

  if(drvName == "org.apache.hive.jdbc.HiveDriver") {
    log.info(s"Deregistering JDBC Driver: ${drvName}")
    DriverManager.deregisterDriver(drv)
  }
}

或者 2:正如我后来发现的,您可以在尝试连接时将驱动程序指定为连接属性的一部分:

Scala 示例:

val hiveCredentials = new java.util.Properties
hiveCredentials.setProperty("user", hiveDBUser)
hiveCredentials.setProperty("password", hiveDBPassword)
hiveCredentials.setProperty("driver", "com.amazon.hive.jdbc41.HS2Driver")

val conn = DriverManager.getConnection(hiveDBURL, hiveCredentials)

这是一个更 "correct" 的版本,因为它应该覆盖任何预注册的处理程序,即使它们具有完全不同的 class 层次结构。