SOCKSプロキシ経由でRedshift接続エラーにハマった話

2020.06.11

こんにちは。データアナリティクス事業本部のナガマサです。
オンライン入社して1ケ月が経ちました。出社ができる日が待ち遠しいです。

今回はSOCKSプロキシ経由で、ローカルからJDBCを介してRedshiftに接続しようとした際にハマった内容になります。

環境

  • Mac 10.15.5
  • Java 1.8.0_251
  • Ecilpse 2020-03 (4.15.0)
  • SOCKSプロキシ経由(認証不要)

事象

SOCKSプロキシ経由でローカルからRedshiftにJDBCを介して接続する際にエラーが発生しました。

Redshift純正のJDBCドライバー(JDBC 4.1)を使用しました。

エラー内容は下記のとおりです。

Caused by: com.amazon.support.exceptions.GeneralException: [Amazon](500150) Error setting/closing connection: Operation timed out.
	... 7 more
Caused by: java.net.ConnectException: Operation timed out
	at sun.nio.ch.Net.connect0(Native Method)
	at sun.nio.ch.Net.connect(Net.java:454)
	at sun.nio.ch.Net.connect(Net.java:446)
	at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:648)
	at sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:96)
	at com.amazon.redshift.client.PGClient.connect(Unknown Source)
	at com.amazon.redshift.client.PGClient.<init>(Unknown Source)
	at com.amazon.redshift.core.PGJDBCConnection.connect(Unknown Source)
	at com.amazon.jdbc.common.BaseConnectionFactory.doConnect(Unknown Source)
	at com.amazon.jdbc.common.AbstractDriver.connect(Unknown Source)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:208)

下記が問題なく設定できていることは確認しました。

  • Ecilpse上のプロキシ設定がされていること(Macのプロキシ設定が反映されていること)
  • 接続するRedshiftのVPCセキュリティグループに、SOCKSプロキシのIPアドレスがインバウンドルールで許可されていること

試したこと

そもそも環境の問題なのかプログラムの問題なのか切り分けするために、ローカルから単純に接続のみを試行するサンプルプログラムで確認してみました。
※今回は接続確認が目的のため、下記のサンプルプログラムをベースにして一部修正しています。

サンプルプログラム

Redshift純正のJDBCドライバーのバージョンを変更

JDBC 4.2 互換ドライバー、JDBC 4.0 互換ドライバーでも試してみました。

import java.sql.*;
import java.util.Properties;

public class ConnectToCluster {
    static final String RedshiftDbURL = "jdbc:redshift://XXXXXXXXXX.redshift.amazonaws.com:5439/XXXXXX";
    static final String MasterUsername = "********";
    static final String MasterUserPassword = "********";
    
    public static void main(String[] args) {
        Connection conn = null;
        try{

           Class.forName("com.amazon.redshift.jdbc42.Driver"); // JDBC 4.2 互換ドライバー
           //Class.forName("com.amazon.redshift.jdbc41.Driver"); JDBC 4.1 互換ドライバー
           //Class.forName("com.amazon.redshift.jdbc4.Driver"); JDBC 4.0 互換ドライバー
           
           System.out.println("Connecting to database...");
           Properties props = new Properties();
           props.setProperty("user", MasterUsername);
           props.setProperty("password", MasterUserPassword);
           props.setProperty("ssl", "true");
           props.setProperty("sslfactory", "com.amazon.redshift.ssl.NonValidatingFactory");
           
           conn = DriverManager.getConnection(RedshiftDbURL, props);	   
           System.out.println("Connection Class : " + conn.getClass().getName());
           conn.close();
        }catch(Exception ex){
           ex.printStackTrace();
        }finally{
           try{
              if(conn!=null)
                 conn.close();
           }catch(Exception ex){
              ex.printStackTrace();
           }
        }
        System.out.println("Finished connectivity test.");
     }
}

JDBC 4.2 互換ドライバー、JDBC 4.0 互換ドライバーでも同じエラーが出力されました。

Caused by: com.amazon.support.exceptions.GeneralException: [Amazon](500150) Error setting/closing connection: Operation timed out.
	... 7 more
Caused by: java.net.ConnectException: Operation timed out
	at sun.nio.ch.Net.connect0(Native Method)
	at sun.nio.ch.Net.connect(Net.java:454)
	at sun.nio.ch.Net.connect(Net.java:446)
	at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:648)
	at sun.nio.ch.SocketAdaptor.connect(SocketAdaptor.java:96)
	at com.amazon.redshift.client.PGClient.connect(Unknown Source)
	at com.amazon.redshift.client.PGClient.<init>(Unknown Source)
	at com.amazon.redshift.core.PGJDBCConnection.connect(Unknown Source)
	at com.amazon.jdbc.common.BaseConnectionFactory.doConnect(Unknown Source)
	at com.amazon.jdbc.common.AbstractDriver.connect(Unknown Source)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:208)

PostgreSQLのJDBCドライバーを使用

こちらの記事によると、Redshift純正のドライバーだと接続できないという情報があったので PostgreSQLのJDBCドライバーを試してみました。

まずはDBeaverをインストール後コネクションを作成します。この際にRedshiftを選ぶとSOCKSプロキシサーバ経由での接続に失敗します。そこでPostgreSQLでコネクションを作成します。

import java.sql.*;
import java.util.Properties;

public class ConnectToCluster {
    static final String PostgresqlDbURL = "jdbc:postgresql://XXXXXXXXXX.redshift.amazonaws.com:5439/XXXXXX";
    static final String MasterUsername = "********";
    static final String MasterUserPassword = "********";
    
    public static void main(String[] args) {
        Connection conn = null;
        try{
           
           Class.forName("org.postgresql.Driver");
           
           System.out.println("Connecting to database...");
           Properties props = new Properties();
           props.setProperty("user", MasterUsername);
           props.setProperty("password", MasterUserPassword);
           props.setProperty("ssl", "true");
           props.setProperty("sslfactory", "org.postgresql.ssl.NonValidatingFactory");
           
           conn = DriverManager.getConnection(PostgresqlDbURL, props);	   
           System.out.println("Connection Class : " + conn.getClass().getName());
           conn.close();
        }catch(Exception ex){
           ex.printStackTrace();
        }finally{
           try{
              if(conn!=null)
                 conn.close();
           }catch(Exception ex){
              ex.printStackTrace();
           }
        }
        System.out.println("Finished connectivity test.");
     }
}

接続できました!

Connection Class : org.postgresql.jdbc.PgConnection

SQL操作も問題ありませんでした!

まとめ

SOCKSプロキシ経由でなければ、Redshift純正のJDBCドライバーで問題なく接続できることは確認しています。今回はあくまでSOCKSプロキシ経由で接続する場合は、PostgreSQLのJDBCドライバーを使用することで接続エラーを回避できることがわかりました。

とはいえ、推奨はRedshift純正のJDBCドライバーでの接続なので、引き続き根本の原因調査は継続したいと思います。取り急ぎ備忘録として記載しておきます。

本件について知見がある方は、ご教授いただけると幸いです。

参考記事

リモート環境でのアプリケーション設定

Macで任意のアプリケーションをSOCKSプロキシ経由にしてみたかったので試してみた

Redshift と PostgreSQL に同時に JDBC 接続する