[新機能]Amazon Auroraで高速にクローンを作成できます

Amazon RDS

大栗です。

Amazon Auroraでデータベースのクローンを作成できる機能がリリースされました!

データベース・クローン

データベースのクローンはre:Invent 2016でアナウンスされていたのですが、既存のAuroraクラスタを素早くコスト効率よく複製する機能です。データベースのクローンではCopy-on-Writeプロトコルを使用しており、ソースデータベースかクローンデータベースで書き換えが発生した時にデータがコピーされます。

Copy-on-Writeプロトコル

Copy-on-WriteはOSのメモリ管理などでよく使用されますが、データの複製を行う時に実際にはコピーせずに同じデータを共有して複製時から変更がある時にオリジナルのデータをコピーします。Wikipediaによると『原本またはコピーのどちらかを書き換えようとしたときに、それを検出し、その時点ではじめて新たな空き領域を探して割り当て、コピーを実行する』と述べています。

つまりソースデータベースかクローンデータベースに何らかの変更が発生した時にストレージ側で実際にコピーを行うということです。

制限事項

データベースのクローンでは、以下の制限があります。

  • リージョン間でクローンデータベースを作成することはできません。クローンデータベースは、ソースデータベースと同じリージョンに作成する必要があります。
  • 同じソースデータベースの他のクローンから作成されたクローンを含めて、最大15個のクローンを現在持つことができます。それ以降のクローンはソースデータベースの完全コピーになります。
  • クロスアカウントのデータベースクローンは現在サポートされていません。
  • 異なるVPCにクローンを提供できますが、VPCのサブネットが同じAZにマッピングされている場合に限ります。

試してみた

事前準備

事前にAuroraクラスタを作成して、データを JdbcRunnerTiny TPC-Cを使用してTPC-C用のデータをwarehouseを10としてデータ投入しています。約1GBのデータが保存されます。

java JR scripts/tpcc_load.js -nAgents 8 -param0 10

約1GBのデータが保存されます。

mysql> select table_schema, sum(data_length+index_length) /1024 /1024 as MB from information_schema.tables  group by table_schema order by sum(data_length+index_length) desc;
+--------------------+---------------+
| table_schema       | MB            |
+--------------------+---------------+
| tpcc               | 1048.70312500 |
| mysql              |    7.24774456 |
| information_schema |    0.01074219 |
| performance_schema |    0.00000000 |
+--------------------+---------------+
4 rows in set (0.14 sec)

CloudWatch上でも約1GBのデータが確認できます。

CloudWatch_Management_Console_と_untitled_と_1__ec2-user_ip-172-31-6-253___jdbcrunner_jdbcrunner-1_2__ssh__と_深夜残業明けの勤務免除と休業手当

Management Consoleでクローンを行う

クローン元のDBインスタンスを選択して、[インスタンスの操作]-[クローンの作成]をクリックします。

RDS_·_AWS_Console

以下の用に「インスタンスの仕様」、「設定」、「ネットワーク & セキュリティ」、「データベースの設定」、「メンテナンス」を指定してクローンの作成をクリックします。VPCを選択できるので別のVPCにクローンを作成することもできます。

RDS_·_AWS_Console

クラスタが作成されます。

RDS_·_AWS_Console

DBインスタンスも作成されます。

RDS_·_AWS_Console

Auroraにログインしてみます。

$ mysql -u awsuser -p -h clone01-cluster.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 113
Server version: 5.6.10 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

約1GBのデータが保存されています。

mysql> select table_schema, sum(data_length+index_length) /1024 /1024 as MB from information_schema.tables  group by table_schema order by sum(data_length+index_length) desc;
+--------------------+---------------+
| table_schema       | MB            |
+--------------------+---------------+
| tpcc               | 1048.70312500 |
| mysql              |    7.24774456 |
| information_schema |    0.01074219 |
| performance_schema |    0.00000000 |
+--------------------+---------------+
4 rows in set (0.14 sec)

しかし、CloudWatchでAuroraクラスタのVolumeBytesUsedを確認すると100MB程度になっています。クローン作成中のデータに600MB程度のポイントがありますが、一時的なものになっています。

CloudWatch_Management_Console_と_EC2_Management_Console

AWS CLIでクローンを行う

今度はCLIでクローンを作成します。restore-db-cluster-to-point-in-timeコマンドを使用するのですが、--restore-typecopy-on-writeを指定することでデータベースクローンができます。

$ aws rds restore-db-cluster-to-point-in-time \
>     --db-cluster-identifier clone03 \
>     --restore-type copy-on-write \
>     --source-db-cluster-identifier source-cluster \
>     --use-latest-restorable-time \
>     --db-subnet-group-name default \
>     --vpc-security-group-ids sg-xxxxxxxx
{
    "DBCluster": {
        "MasterUsername": "awsuser",
        "ReaderEndpoint": "clone03.cluster-ro-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com",
        "ReadReplicaIdentifiers": [],
        "CloneGroupId": "12345678-1234-1234-1234-123456789012",
        "VpcSecurityGroups": [
            {
                "Status": "active",
                "VpcSecurityGroupId": "sg-xxxxxxxx"
            }
        ],
        "HostedZoneId": "12345678901234",
        "Status": "creating",
        "MultiAZ": false,
        "PreferredBackupWindow": "20:00-20:30",
        "DBSubnetGroup": "default",
        "AllocatedStorage": 1,
        "BackupRetentionPeriod": 1,
        "PreferredMaintenanceWindow": "fri:18:13-fri:18:43",
        "Engine": "aurora",
        "Endpoint": "clone03.cluster-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com",
        "AssociatedRoles": [],
        "IAMDatabaseAuthenticationEnabled": false,
        "ClusterCreateTime": "2017-06-13T02:24:09.236Z",
        "EngineVersion": "5.6.10a",
        "DBClusterIdentifier": "clone03",
        "DbClusterResourceId": "cluster-ABCDEFGHIJKLMNOPQRSTUVWXYZ",
        "DBClusterMembers": [],
        "DBClusterArn": "arn:aws:rds:ap-northeast-1:123456789012:cluster:clone03",
        "StorageEncrypted": false,
        "DatabaseName": "mydb",
        "DBClusterParameterGroup": "aurora-test-001",
        "AvailabilityZones": [
            "ap-northeast-1a",
            "ap-northeast-1c"
        ],
        "Port": 3306
    }
}

Auroraクラスタが作成されます。DBインスタンスは作成されないので、別途作成する必要があります。

クローンの動きを確認する

データに変更があった時に実際のコピーを行うので、その時のデータ量の変化について確認してみます。

データ挿入した時の挙動

各テーブルに1行ずつデータを挿入しました。すると79,413,248バイトから79,446,016バイトと32KBのデータ量が増加しました。

CloudWatch_Management_Console

別のクラスタで以下のような小さいテーブルに対して1件挿入した場合に増えるデータサイズを確認してみます。

mysql> desc new_orders ;
+---------+---------+------+-----+---------+-------+
| Field   | Type    | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| no_o_id | int(11) | NO   | PRI | 0       |       |
| no_d_id | int(11) | NO   | PRI | 0       |       |
| no_w_id | int(11) | NO   | PRI | 0       |       |
+---------+---------+------+-----+---------+-------+
3 rows in set (0.00 sec)

79,413,248バイトから79,429,632バイトと16KBのデータ量が増加しました。ここで増える16KBがCopy-on-Writeを行う単位のページのサイズと考えられると思われます。

CloudWatch_Management_Console_と_投稿の編集_‹_Developers_IO_—_WordPress

テーブルをTRUNCATEした時の挙動

全テーブルをTRUNCATEします。外部キー制約のチェックを無視するためforeign_key_checksを0にして実行しました。

mysql> set foreign_key_checks = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> truncate table customer  ;
Query OK, 0 rows affected (0.03 sec)

mysql> truncate table district  ;
Query OK, 0 rows affected (0.03 sec)

mysql> truncate table history   ;
Query OK, 0 rows affected (0.02 sec)

mysql> truncate table item      ;
Query OK, 0 rows affected (0.03 sec)

mysql> truncate table new_orders;
Query OK, 0 rows affected (0.02 sec)

mysql> truncate table order_line;
Query OK, 0 rows affected (0.03 sec)

mysql> truncate table orders    ;
Query OK, 0 rows affected (0.02 sec)

mysql> truncate table stock     ;
Query OK, 0 rows affected (0.02 sec)

mysql> truncate table warehouse ;
Query OK, 0 rows affected (0.02 sec)

mysql>
mysql> set foreign_key_checks = 1;
Query OK, 0 rows affected (0.00 sec)

mysql>

データサイズをCloudWatchで確認すると以下のようになり、サイズに変更がありません。TRUNCATEでは内部でテーブルの再作成をしているため既存のデータに変更が無く、データ量に変化がないと考えられます。

CloudWatch_Management_Console

レコードをDELETEした時の挙動

今度はTRUNCATEではなく全件DELETEをしてみます。

mysql> set foreign_key_checks = 0;
Query OK, 0 rows affected (0.02 sec)

mysql> delete from customer  ;
Query OK, 300000 rows affected (23.90 sec)

mysql> delete from district  ;
Query OK, 100 rows affected (0.02 sec)

mysql> delete from history   ;
Query OK, 300000 rows affected (12.00 sec)

mysql> delete from item      ;
Query OK, 100000 rows affected (3.59 sec)

mysql> delete from new_orders;
Query OK, 90000 rows affected (3.32 sec)

mysql> delete from order_line;
Query OK, 2997884 rows affected (1 min 56.95 sec)

mysql> delete from orders    ;
Query OK, 300000 rows affected (12.10 sec)

mysql> delete from stock     ;
Query OK, 1000000 rows affected (57.22 sec)

mysql> delete from warehouse ;
Query OK, 10 rows affected (0.02 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

今度はCloudWatch上のデータサイズが増加しました。レコードを削除しているのですが、データの変更により実際にコピーされたためデータサイズが増えたと考えられます。

CloudWatch_Management_Console

クローンを多数作成した時の挙動

制限事項に『同じソースデータベースの他のクローンから作成されたクローンを含めて、最大15個のクローンを現在持つことができます。それ以降のクローンはソースデータベースの完全コピーになります』という物があるため、実際に完全コピーとなるか確認してみます。

CLIでクローンを作成して、クローンを合計で16個作成してみました。しかし、データ量は70MBと少しとなっており完全コピーがされずに済んでいます。

CloudWatch_Management_Console_と_投稿の編集_‹_Developers_IO_—_WordPress

そこで17個目のクローンを作成してみました。すると今度は1GB程度のデータサイズとなり完全コピーされていると分かります。

CloudWatch_Management_Console

16個目で完全コピーされなかったのは一時的に制限が緩和されているだけだと思われますので、本来は完全コピーされるものと思われます。同じデータを多数のクラスタやインスタンスで参照するとパフォーマンスの劣化を招くと考えられますので大量のクローンは作成しないほうが良いと思われます。

ソースデータベースを変更した時の挙動

今まではクローンデータベース側を変更していましたが、ソースデータベースを変更した時の挙動を確認してみます。データサイズの変化が大きかった全件DELETEをソースデータベースに対して実行してみます。

mysql> set foreign_key_checks = 0;
Query OK, 0 rows affected (0.02 sec)

mysql> delete from customer  ;
Query OK, 300000 rows affected (23.90 sec)

mysql> delete from district  ;
Query OK, 100 rows affected (0.02 sec)

mysql> delete from history   ;
Query OK, 300000 rows affected (12.00 sec)

mysql> delete from item      ;
Query OK, 100000 rows affected (3.59 sec)

mysql> delete from new_orders;
Query OK, 90000 rows affected (3.32 sec)

mysql> delete from order_line;
Query OK, 2997884 rows affected (1 min 56.95 sec)

mysql> delete from orders    ;
Query OK, 300000 rows affected (12.10 sec)

mysql> delete from stock     ;
Query OK, 1000000 rows affected (57.22 sec)

mysql> delete from warehouse ;
Query OK, 10 rows affected (0.02 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

この時のデータサイズの変化をCloudWatchで確認するとソースデータベースのサイズだけ増えています。Log Structured Storageのお陰でソースデータベースの既存データが残った状態で、変更分を追記しているためクローンデータベースのサイズに変化がないと思われます。

CloudWatch_Management_Console

まとめ

データベースクローンは素早く作成できて、コスト効率も良くデータベースを複製できます。これにより大量のデータを保存している本番DBと同じデータを使用した検証が簡単にできるようになりました。この機能によりDBへの変更を伴うアプリケーションのデプロイなどでも活用できると思われます。新しいアプリケーションをデプロイする時にクローンに対してDB変更を実施すれば、不具合があった場合の切り戻しも容易になります。

しかし、多量のデータ更新を行うと実際にデータコピーされることで、使用データサイズがスナップショットからリストアを行った場合と同程度になることもあります。データの追加だけでなく、データ削除の場合もコピーがされるので注意が必要です。