【问题标题】:Oracle Database JDBC driver cannot read wallet file from SparkOracle 数据库 JDBC 驱动程序无法从 Spark 读取钱包文件
【发布时间】:2019-01-24 20:30:28
【问题描述】:

目标

我正在尝试从运行在 Yarn 上的 Spark 应用程序写入 Oracle 的 ADWC(基本上是 oracle 数据库)。连接到此数据库的唯一方法是使用 Oracle Wallet 文件,该文件基本上是一个 Java 密钥库。

问题

当 JDBC 驱动程序尝试从 HDFS 读取钱包时,就会出现问题。如果我包含 hdfs:// 前缀,则 JDBC 驱动程序中的解析器会引发错误,如果我不包含,则它无法找到该文件。

以前的尝试

  1. 包括连接字符串中的目录(前缀和非)jdbc:oracle:thin:@luigi_low?TNS_ADMIN=/user/spark/wallet_LUIGI
  2. 将目录包含为spark.driver.extraJavaOptions-Doracle.net.tns_admin-Doracle.net.wallet_location

所有代码都在GitHub上,具体的错误信息在这里https://github.com/sblack4/kafka-scala-jdbc/blob/master/ERROR.md

我在这里有一个相同连接的工作示例https://github.com/sblack4/scala-jdbc-adwc

帮助我 StackOverflow。你是我唯一的希望

如果您需要更多说明,请不要犹豫:)

更新(SparkFiles 尝试)

代码位于同一存储库的单独分支上,https://github.com/sblack4/kafka-scala-jdbc/tree/sparkfiles

此错误消息让我感到困惑,因为我的 JDBC 库似乎已停止尝试读取钱包文件。可能和之前的问题无关

Exception in thread "main" java.sql.SQLRecoverableException: IO Error: Invalid connection string format, a valid format is: "host:port:sid" 

我已通过 Ambari 从我的类路径中删除了其他 JDBC 库,因为此错误可能与 spark 获取旧版本的 JDBC 库有关

【问题讨论】:

  • 简而言之:JDBC驱动程序内部的代码没有HDFS的概念,它需要一个普通本地文件系统中的普通文件(或者可能是InputStream?)那么,为什么不使用 Spark 将钱包下载到本地(临时)文件(或者在 HDFS 上打开一个流?) 并将其传递给驱动程序??
  • @thatjeffsmith 是的,连接在本地完美运行
  • @SamsonScharfrichter 我会尝试InputStream 的想法,但我不确定如何在本地下载驱动程序。如果我可以在连接字符串中将该驱动程序本地路径传递给 JDBC,这听起来相当简单
  • 您是否在 Spark 驱动程序中打开 JDBC 连接 执行程序(即并行读取/写入 DataFrame 中的 Oracle 数据)以及多个“独立”会话,或者仅在驱动程序中(使用自定义代码运行 Spark JDBC 接口不支持的命令)?因为您可以告诉驱动程序将文件分发给其执行程序,但是本地路径会不同,JDBC URL 也会不同...

标签: oracle apache-spark hdfs hadoop-yarn ojdbc


【解决方案1】:

这里有一些代码可以帮助诊断问题所在。 它检查并配置连接所需的一切。

  • JDBC 驱动版本
  • 已安装 JCE
  • 类路径依赖项

配置

  • tns_admin
  • ssl 设置
  • 信任/密钥存储

这是 sqldev/sqlcl 中的精简版

import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Properties;

import javax.crypto.Cipher;

import oracle.jdbc.OracleConnection;

public class JDBCTest {

  public static void fail(String msg){
    System.err.println(String.join("", Collections.nCopies(20, "*")));
    System.err.println(msg);
    System.err.println(String.join("", Collections.nCopies(20, "*")));
    System.exit(1);
  }
  public static void main(String[] args) throws SQLException {
    System.out.println("JDBC Driver Version:" + oracle.jdbc.OracleDriver.getDriverVersion());

    // Check JDBC Driver Version
    if (!oracle.jdbc.OracleDriver.getDriverVersion().startsWith("18.")) {
      fail(" DRIVER TOOO OLD!!!");
    }

    // Check JCE Installed
    int maxKeySize = 0;
    try {
      maxKeySize = Cipher.getMaxAllowedKeyLength("AES");
    } catch (NoSuchAlgorithmException e) {
    }
    if (maxKeySize < 129 ) {
      fail(" JCE Policy not unlimited!!!");      
    }

    // Check Classpath

    String cp = System.getProperty("java.class.path");

    String[] cpFiles = {"ojdbc8.jar","oraclepki.jar","osdt_cert.jar","osdt_core.jar"};

    for (String file:cpFiles){
      if ( cp.indexOf(file) == -1 ){
        fail("CLASSPATH Missing:" + file);

      }
    }
    // Wallet unziped location
    String unzippedWalletLocation = "/Users/klrice/workspace/12.2JDBC/wallet";



    String conString = "jdbc:oracle:thin:@sqldev_medium";


    Properties props = new Properties();
    props.setProperty("oracle.net.wallet_location",unzippedWalletLocation);

    props.setProperty(OracleConnection.CONNECTION_PROPERTY_THIN_NET_CONNECT_TIMEOUT, "2000");

    // unzipped includes a tnsnames.ora
    props.setProperty("oracle.net.tns_admin",unzippedWalletLocation);
    props.setProperty("javax.net.ssl.trustStore","truststore.jks");
    props.setProperty("javax.net.ssl.trustStorePassword","<password>");
    props.setProperty("javax.net.ssl.keyStore","keystore.jks");
    props.setProperty("javax.net.ssl.keyStorePassword","<password>");
    props.setProperty("oracle.net.ssl_server_dn_match","true");    
    props.setProperty("oracle.net.ssl_version","1.2");


    props.setProperty("user", "ADMIN");
    props.setProperty("password", "<password>");

    try { 
      // now Connect 
      Connection conn = DriverManager.getConnection(conString,props);
    } catch (Exception e){
      e.printStackTrace();
      fail(e.getLocalizedMessage());
    }

    System.out.println("SUCCESS!!");


  }

}

【讨论】:

    【解决方案2】:

    你在使用18.3 JDBC drivers吗?将 TNS_ADMIN 作为连接 URL 的一部分传递需要 18.3 JDBC 驱动程序。此外,您是否尝试在公司网络内进行连接。在这种情况下,您需要在连接 URL 中传递 HTTPS_PROXY 和 HTTPS_PROXY_PORT。让我们知道。乐于帮助解决问题。

    【讨论】:

      猜你喜欢
      • 2017-07-21
      • 2021-02-04
      • 2011-06-04
      • 2017-10-16
      • 2021-03-23
      • 1970-01-01
      • 2016-02-07
      • 2014-03-30
      • 1970-01-01
      相关资源
      最近更新 更多