[アップデート] Aurora Serverless の Data API が東京リージョンでもサポートされました

Aurora Serverless の Data API 機能がサポートされましたので早速つかってみました!東京リージョンでも使えますので、是非、お試しあれ!
2019.06.01

昨年の re:Invent 前に発表された Aurora Serverless の Data API がついにサポートされたようです!そして、東京リージョンでも使えます!さっそく使ってみたのでレポートします。

Data API って何?

これまで Lambda と RDBMS 系のサービス(RDS/Aurora)は接続方法や、最大接続数の問題に直面しやすいことから相性が悪い(いわるゆアンチパターン)と言われてきました。Data API は Aurora Serverless の エンドポイントとして機能するので、従来のように Lambda は Aurora Serverless に直接接続する必要はなく、Data API エンドポイントに接続する形となり、最大接続数の問題を回避することができます。

また、Aurora Serverless が配置されている VPC へのアクセスも Data API エンドポイントを介して行われるため、起動が遅いといわれる VPC Lambda を使わずともアクセスが可能となります。このあたりの詳細は以下、大栗の記事を参照ください。

Amazon Aurora ServerlessでHTTPSエンドポイントができ本当にサーバーレスアーキテクチャで利用可能になる!

それでは、さっそく試していきましょう。

Aurora Serverless の Data API を有効化

Aurora Serverless の作成時には Data API を指定することが出来ないようですので、まずは Aurora Serverless をそのまま作成してください。(Data API が使用できるのは執筆時点で MySQL 5.6 互換のみです)作成できたら「変更」メニューの「ネットワーク&セキュリティ」に Data API がありますのでチェックして有効化します。

(まだ Beta の文字が残っているのが気になりますが、おいおい消えるのでしょうか。。)

クエリエディタ

Data API を有効にすると、AWS コンソールからクエリが実行できるクエリエディタが使用できるようになります。こちらも、既に大栗の記事があるので参照ください。

Amazon Aurora ServerlessでManagement Consoleからクエリが実行可能になりました

接続情報はシークレットマネージャに

Data API では認証情報をシークレットマネージャーで渡しますので、シークレットマネージャに Aurora Serverless のパスワード情報を登録しておきます。

必要な権限

Data API の実行に必要な権限は下記のとおりですので、不足している場合はポリシー追加しておきます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SecretsManagerDbCredentialsAccess",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:PutResourcePolicy",
                "secretsmanager:PutSecretValue",
                "secretsmanager:DeleteSecret",
                "secretsmanager:DescribeSecret",
                "secretsmanager:TagResource"
            ],
            "Resource": "arn:aws:secretsmanager:*:*:secret:rds-db-credentials/*"
        },
        {
            "Sid": "RDSDataServiceAccess",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:CreateSecret",
                "secretsmanager:ListSecrets",
                "secretsmanager:GetRandomPassword",
                "tag:GetResources",
                "rds-data:BatchExecuteStatement",
                "rds-data:BeginTransaction",
                "rds-data:CommitTransaction",
                "rds-data:ExecuteStatement",
                "rds-data:RollbackTransaction"
            ],
            "Resource": "*"
        }
    ]
} 

Data API でのクエリ実行

今回は AWS CLI で試しています。手もとの AWS CLI が古かったので、update することで実行できるようになりました。実行環境は下記のとおりです。

$ aws --version
aws-cli/1.16.169 Python/2.7.10 Darwin/18.2.0 botocore/1.12.159

execute-statement コマンド

それでは DB と テーブルを作成し、データを挿入します。通常のクエリ実行には execute-statement コマンドを使います。認証情報は --secret-arn でシークレットマネージャの ARN を指定します。クラスタは --resource-arn で Aurora Serverless の ARN を指定します。出力は JSON で返ってきます。

また、Data APIへのすべての呼び出しは同期的です。デフォルトでは、1分で呼び出しはタイムアウトし処理が終了しますが、--continue-after-timeout パラメーターを使用してタイムアウトした後も SQL ステートメントの実行を続けることができます。DDL ステートメントの場合は、タイムアウトによってデータ構造が破損する可能性もあるので、--continue-after-timeout を使用してステートメントを実行し続けることを推奨されています。

# データベースの作成
$ aws rds-data execute-statement \
   --resource-arn "arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:aurora-sl" \
   --secret-arn "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxxxx:secret:aurora-sl-password-0wKK8u" \
   --sql "create database mydb"
{
    "numberOfRecordsUpdated": 1,
    "generatedFields": []
}

# テーブルの作成
$ aws rds-data execute-statement \ #以降の --resource-arn、--secret-arn は省略しています
   --database "mydb" \
   --sql "create table sample_table (ID int, TYPE varchar(20), TIMESTAMP);"
{
    "numberOfRecordsUpdated": 0,
    "generatedFields": []
}

# レコードの挿入
$ aws rds-data execute-statement \
   --database "mydb" \
   --sql "insert into sample_table (ID, TYPE, TIMESTAMP) values (1, 'TEST', now());"
{
    "numberOfRecordsUpdated": 1,
    "generatedFields": []
}

# テーブルの参照
$ aws rds-data execute-statement \
   --database "mydb" \
   --sql "select * from sample_table"
{
    "records": [
        [
            {
                "longValue": 1
            },
            {
                "stringValue": "TEST"
            },
            {
                "stringValue": "2019-06-01 04:15:10.0"
            }
        ]
    ],
    "numberOfRecordsUpdated": 0
}

大栗の記事では execute-sql コマンドを使用していますが、execute-statement に変わったようです。オプション名なども変わっているので、Beta で試されていた環境は置き換えていくのが良いかと思います。

execute-sql execute-statement
--aws-secret-store-arn --secret-arn
--db-cluster-or-instance-arn --resource-arn
--sql-statements --sql

--include-result-metadata

--include-result-metadata オプションを付与すると、メタデータも拾うことができます。

$ aws rds-data execute-statement \ #--resource-arn、--secret-arn は省略しています
   --database "mydb" \
   --sql "select * from sample_table" --include-result-metadata
{
    "records": [
        [
            {
                "longValue": 1
            },
            {
                "stringValue": "TEST"
            },
            {
                "stringValue": "2019-06-01 04:15:10.0"
            }
        ]
    ],
    "columnMetadata": [
        {
            "isAutoIncrement": false,
            "name": "ID",
            "nullable": 1,
            "tableName": "sample_table",
            "isCurrency": false,
            "precision": 11,
            "arrayBaseColumnType": 0,
            "label": "ID",
            "typeName": "INT",
            "scale": 0,
            "isCaseSensitive": false,
            "isSigned": true,
            "schemaName": "",
            "type": 4
        },
        {
            "isAutoIncrement": false,
            "name": "TYPE",
            "nullable": 1,
            "tableName": "sample_table",
            "isCurrency": false,
            "precision": 20,
            "arrayBaseColumnType": 0,
            "label": "TYPE",
            "typeName": "VARCHAR",
            "scale": 0,
            "isCaseSensitive": false,
            "isSigned": false,
            "schemaName": "",
            "type": 12
        },
        {
            "isAutoIncrement": false,
            "name": "TIMESTAMP",
            "nullable": 1,
            "tableName": "sample_table",
            "isCurrency": false,
            "precision": 19,
            "arrayBaseColumnType": 0,
            "label": "TIMESTAMP",
            "typeName": "DATETIME",
            "scale": 0,
            "isCaseSensitive": false,
            "isSigned": false,
            "schemaName": "",
            "type": 93
        }
    ],
    "numberOfRecordsUpdated": 0
}

バッチ操作の追加

Beta 版ではなかった機能として、Named Parameters を使ったバッチ操作が可能となりました。100レコードの追加を1つずつクエリするなんて考えたくないですね。本当に追加されて良かったと思います。

batch-execute-statement コマンド

バッチ操作には batch-execute-statement を指定し、--parameter-sets オプションで引数を渡します。レスポンスサイズの制限は 1 MB または1,000レコードです。1 MBを超えるレスポンスデータまたは、1,000を超えるレコードを返すと、呼び出しは終了します。

$ aws rds-data batch-execute-statement \ #--resource-arn、--secret-arn は省略しています
   --database "mydb2" \
   --sql "insert into sample_table values (:id, :type)" \
   --parameter-sets \
   "[[{\"name\": \"id\", \"value\": {\"longValue\": 1}},{\"name\": \"type\", \"value\": {\"stringValue\": \"BATCH1\"}}], \
   [{\"name\": \"id\", \"value\": {\"longValue\": 2}},{\"name\": \"type\", \"value\": {\"stringValue\": \"BATCH2\"}}], \
   [{\"name\": \"id\", \"value\": {\"longValue\": 3}},{\"name\": \"type\", \"value\": {\"stringValue\": \"BATCH3\"}}]]"
{
    "updateResults": [
        {
            "generatedFields": []
        },
        {
            "generatedFields": []
        },
        {
            "generatedFields": []
        }
    ]
}

トランザクションサポート

これも Beta 版ではなかった機能ですが、トランザクションがサポートされるようになりました。ただし、トランザクションには時間の制限がありますので注意点としておさせておきましょう。

  • トランザクションは最大24時間実行できます。24時間を経過すると、トランザクションは終了し自動的にロールバックされます。
  • トランザクション ID の呼び出しが 3分以上ない場合、トランザクションは終了し自動的にロールバックされます。

begin-transaction コマンド

begin-transaction コマンドでトランザクションの開始を宣言します。戻り値のトランザクション ID を後続の execute-statementbatch-execute-statement--transaction-id オプションに指定することで、トランザクションとして処理されます。

また、begin-transaction 宣言後でも、--transaction-id の指定がない処理は自動的にコミットされます。

# トランザクションの開始を宣言
$ aws rds-data begin-transaction \ #--resource-arn、--secret-arn は省略しています
   --database "mydb"
{
    "transactionId": "AWl2l9O07LsBrq9GXL・・・・・vmvyJfuI="
}

# トランザクション ID を指定することで、トランザクション処理になります
$ aws rds-data execute-statement \ #--resource-arn、--secret-arn は省略しています
   --transaction-id "AWl2l9O07LsBrq9GXL・・・・・vmvyJfuI=" \
   --database "mydb" \
   --sql "insert into sample_table (ID, TYPE, TIMESTAMP) values (2, 'AAA', now());"
{
    "numberOfRecordsUpdated": 1,
    "generatedFields": []
}

rollback-transaction コマンド

rollback-transaction コマンドを使用し、--transaction-id を指定してロールバックできます。

# 先ほどの execute-statement をロールバックします
$ aws rds-data rollback-transaction \ #--resource-arn、--secret-arn は省略しています
   --transaction-id "AWl2l9O07LsBrq9GXL・・・・・vmvyJfuI="
{
    "transactionStatus": "Rollback Complete"
}

# ロールバックされたのでレコードは増えていません
$ aws rds-data execute-statement \ #--resource-arn、--secret-arn は省略しています
   --database "mydb" \
   --sql "select * from sample_table"
{
    "records": [
        [
            {
                "longValue": 1
            },
            {
                "stringValue": "TEST"
            },
            {
                "stringValue": "2019-06-01 04:15:10.0"
            }
        ]
    ],
    "numberOfRecordsUpdated": 0
}

先述のとおり、ロールバックされるのは --transaction-id を指定した処理のみです。--transaction-id が指定されていない場合は自動コミットされる点をお忘れなく。

commit-transaction コマンド

commit-transaction コマンドと、--transaction-id を指定してトランザクションをコミットします。

# 新たに発行したトランザクション ID でレコード追加
$ aws rds-data execute-statement \ #--resource-arn、--secret-arn は省略しています
   --transaction-id "AWl2l9O07Ls・・・・・TBYQnK6Yzxs=" \
   --database "mydb" \
   --sql "insert into sample_table (ID, TYPE, TIMESTAMP) values (2, 'COMMIT', now());"
{
    "numberOfRecordsUpdated": 1,
    "generatedFields": []
}

# トランザクションをコミット
$ aws rds-data commit-transaction \ #--resource-arn、--secret-arn は省略しています
   --transaction-id "AWl2l9O07Ls・・・・・TBYQnK6Yzxs="
{
    "transactionStatus": "Transaction Committed"
}

# コミットしたので、レコードが追加されています
$ aws rds-data execute-statement \ #--resource-arn、--secret-arn は省略しています
   --database "mydb" \
   --sql "select * from sample_table"
{
    "records": [
        [
            {
                "longValue": 1
            },
            {
                "stringValue": "TEST"
            },
            {
                "stringValue": "2019-06-01 04:15:10.0"
            }
        ],
        [
            {
                "longValue": 2
            },
            {
                "stringValue": "COMMIT"
            },
            {
                "stringValue": "2019-06-01 04:41:47.0"
            }
        ]
    ],
    "numberOfRecordsUpdated": 0
}

トランザクション ID を呼び出さす3分以上放置してみたところ、トランザクション ID が見つからず、自動的にロールバックされていました。

$ aws rds-data commit-transaction \ #--resource-arn、--secret-arn は省略しています
   --transaction-id "AWl2l9O07LsBC・・・・・ATRuFFacZXeIQ="

An error occurred (BadRequestException) when calling the CommitTransaction operation: \
Transaction AWl2l9O07LsBC・・・・・ATRuFFacZXeIQ= is not found

Lambda で実行してみたが・・・

ここまで AWS CLI で動作を確認してきましたが、Data API が活きるのは Lambda からの実行ですよね。ということで、以下の環境で試してみました。

  • 東京リージョン
  • Python 3.7
  • IAM ロールに AmazonRDSDataFullAccess ポリシーを追加

lambda_function.py

import boto3 

def lambda_handler(event, context):
 
    rdsData = boto3.client('rds-data')
 
    cluster_arn = 'arn:aws:rds:ap-northeast-1:xxxxxxxx:cluster:aurora-sl'
    secret_arn = 'arn:aws:secretsmanager:ap-northeast-1:xxxxxxxx:secret:aurora-sl-password-0wKK8u'
  
    response1 = rdsData.execute_statement(
                resourceArn = cluster_arn, 
                secretArn = secret_arn, 
                database = 'mydb', 
                sql = 'select * from sample_table')
 
    print (response1['records'])

しかしながら、標準のままでは SDK がまだ古いのか rds-data に対応していないようで、実行できませんでした(涙) バージニアでも同様に試してみましたがダメでした。python 3.7 以外は試してないので、どなたか試してくださいませ。

さいごに

Lambda での動作確認がおわってないので、片手落ちの検証記事になってしまった感は否めませんが。。AWS CLI を使っていても Data API エンドポイントのおかげで Aurora Serverless へのアクセスが非常に簡単であることは間違いないです。また、バッチ操作やトランザクションにも対応するようになっていますので、Beta 版の検証だけでおわっている方は、是非、もう一度試してみてはいかがでしょうか!

以上!大阪オフィスの丸毛(@marumo1981)でした!