💬
Athena Federationを使ってみた
概要
- Amazon Athena の Query Federation に関する Github リポジトリに GA の文字があったので使ってみた。
- Athena の裏に Lambda があっていろいろやってくれるのだが、ブラックボックス感が強く、動かすためにはいろんな知識が必要。
- セットアップは少し大変だけど、使い勝手は良い。
Amazon Athena Federated Query とは
の日本語要約です。
- S3 以外に保存されているデータに対してクエリを投げたり、各種パイプラインを組める。
- RDB や non-RDB、オブジェクト、カスタムデータソースに対してクエリできるようになります。
- AWS Lambda で
data source connector
を使います。data source connector
は対象データソースと Athena を接続するコードです。 - 以下のデータソースのための
data source connector
は事前に用意してあります。- Amazon CloudWatch Logs
- Amazon DynamoDB
- Amazon DocumentDB
- Amazon RDS
- JDBC 互換 DB(e.g. MySQL, PostgreSQL)
- Athena Query Federation SDK を使うことで独自の
custom connector
を作れます。 -
data source connector
は AWS Serverless Application Repository からデプロイできます。
RDS(MySQL) と繋いでみる
基本この画面に従う。悩んだ・困ったところだけメモ。
- RDS へ接続するときも MySQL を選択する。
- Athena で Data Source を作ったあと Lambda に環境変数を追加する必要がある。
- https://github.com/awslabs/aws-athena-query-federation/tree/master/athena-jdbc#multiplexing-handler-parameters に従う。
- {CATALOG_NAME}_connection_string という KEY
-
mysql://jdbc:mysql://foo.us-east-1.rds.amazonaws.com:3306/first_db?user=admin&password=XXXXXXXXXXXX
みたいな VALUE
何はともあれクエリを投げてみよう
Athena の画面からテーブル名一覧に MySQL のテーブル名が表示されたのでセットアップ完了かと思い、適当に SELECT 文を投げてみた。
Athena 上のエラー表示はこんな感じ。
GENERIC_USER_ERROR: Encountered an exception[com.amazonaws.SdkClientException] from your LambdaFunction[arn:aws:lambda:us-east-1:{ACCOUNT_ID}:function:jdbc_connection] executed in context[retrieving meta-data] with message[Unable to execute HTTP request: Connect to s3.amazonaws.com:443 [s3.amazonaws.com/{IP}] failed: connect timed out]
Lambda から S3 に接続できない的な話なので Lambda のログをみる。
Unable to execute HTTP request: Connect to s3.amazonaws.com:443 [s3.amazonaws.com/{IP}] failed: connect timed out: com.amazonaws.SdkClientException
com.amazonaws.SdkClientException: Unable to execute HTTP request: Connect to s3.amazonaws.com:443 [s3.amazonaws.com/{IP}] failed: connect timed out
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleRetryableException(AmazonHttpClient.java:1207)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1153)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:802)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:704)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5062)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5008)
at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5002)
at com.amazonaws.services.s3.AmazonS3Client.listBuckets(AmazonS3Client.java:996)
at com.amazonaws.services.s3.AmazonS3Client.listBuckets(AmazonS3Client.java:1002)
at com.amazonaws.athena.connector.lambda.domain.spill.SpillLocationVerifier.updateBucketState(SpillLocationVerifier.java:88)
at com.amazonaws.athena.connector.lambda.domain.spill.SpillLocationVerifier.checkBucketAuthZ(SpillLocationVerifier.java:74)
at com.amazonaws.athena.connector.lambda.handlers.MetadataHandler.doHandleRequest(MetadataHandler.java:265)
at com.amazonaws.athena.connector.lambda.handlers.CompositeHandler.handleRequest(CompositeHandler.java:132)
at com.amazonaws.athena.connector.lambda.handlers.CompositeHandler.handleRequest(CompositeHandler.java:100)
Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to s3.amazonaws.com:443 [s3.amazonaws.com/{IP}] failed: connect timed out
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.amazonaws.http.conn.ClientConnectionManagerFactory$Handler.invoke(ClientConnectionManagerFactory.java:76)
at com.amazonaws.http.conn.$Proxy19.connect(Unknown Source)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at com.amazonaws.http.apache.client.impl.SdkHttpClient.execute(SdkHttpClient.java:72)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1330)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1145)
... 17 more
Caused by: java.net.SocketTimeoutException: connect timed out
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:368)
at com.amazonaws.http.conn.ssl.SdkTLSSocketFactory.connectSocket(SdkTLSSocketFactory.java:142)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
... 33 more
Lambda が自動で生成されるので、詳しいことはよく分からないけど、多分 VPC Lambda が S3 にアクセスできない問題っぽい。
VPC エンドポイントの設定して、再度クエリ実行
またエラー。
Serverless Application の Deploy 時に設定したバケットがないっぽい。
You do NOT own the spill bucket with the name: {Bucket name}: java.lang.RuntimeException
java.lang.RuntimeException: You do NOT own the spill bucket with the name: FirstAthenaJdbcConnector
at com.amazonaws.athena.connector.lambda.domain.spill.SpillLocationVerifier.passOrFail(SpillLocationVerifier.java:115)
at com.amazonaws.athena.connector.lambda.domain.spill.SpillLocationVerifier.checkBucketAuthZ(SpillLocationVerifier.java:77)
at com.amazonaws.athena.connector.lambda.handlers.MetadataHandler.doHandleRequest(MetadataHandler.java:265)
at com.amazonaws.athena.connector.lambda.handlers.CompositeHandler.handleRequest(CompositeHandler.java:132)
at com.amazonaws.athena.connector.lambda.handlers.CompositeHandler.handleRequest(CompositeHandler.java:100)
バケットを作ってクエリを再実行
成功した!MySQL の中身データが表示された!
不明点・今後の調査課題
- Athena の画面に表示されたテーブル名のプルダウンを開いたら
partition_name(varchar)
とpartition_name(varchar)(Partitioned)
という見知らぬカラムが追加されていた。何かを調べる。 - Lambda が S3 にアクセスしている理由を調べる。
Discussion