Athena Federationを使ってみた


概要

  • Amazon Athena の Query Federation に関する Github リポジトリに GA の文字があったので使ってみた。
  • Athena の裏に Lambda があっていろいろやってくれるのだが、ブラックボックス感が強く、動かすためにはいろんな知識が必要。
  • セットアップは少し大変だけど、使い勝手は良い。

Amazon Athena Federated Query とは

https://docs.aws.amazon.com/athena/latest/ug/connect-to-a-data-source.html
の日本語要約です。

  • 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) と繋いでみる

https://docs.aws.amazon.com/athena/latest/ug/connect-to-a-data-source-lambda.html
基本この画面に従う。悩んだ・困ったところだけメモ。

何はともあれクエリを投げてみよう

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 にアクセスしている理由を調べる。