CFNでRDSリードレプリカを作成する

CloudFormationを使用してRDSリードレプリカを作成する

CloudFormationを使用して、RDSリードレプリカを作成する

以下のページで、マルチAZ配置を取り上げました。

https://awstut.com/2023/01/05/rds-multi-az-deployment-using-cfn

RDSが提供する機能の1つにリードレプリカがあります。

プライマリ DB インスタンスに対して行った更新は、リードレプリカに非同期的にコピーされます。読み込みクエリをアプリケーションからリードレプリカにルーティングすることにより、プライマリ DB インスタンスの負荷を軽減できます。リードレプリカを使うと、単一 DB インスタンスのキャパシティ制約にとらわれることなく伸縮自在にスケールアウトし、読み込み負荷の高いデータベースワークロードに対応できます。

リードレプリカの使用

今回はCloudFormationを使用して、リードレプリカを作成します。
加えてリードレプリカの昇格方法についても確認します。

構築する環境

Diagram of RDS Read Replica using CloudFormation

RDS DBインスタンスを2つ作成します。
1つはプライマリインスタンス、もう1つはリードレプリカインスタンスです。
DBインスタンスのタイプはMySQLとします。

EC2インスタンスも作成します。
DBインスタンスに接続するクライアントとして使用します。
インスタンスは最新版のAmazon Linux 2です。

2種類のVPCエンドポイントを作成します。

1つ目はSSM用です。
SSM Session Managerを使用して、プライベートサブネット内のEC2インスタンスに接続するためです。

2つ目はS3用です。
S3バケット上に構築されたyumリポジトリにアクセスするためです。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

https://github.com/awstut-an-r/awstut-fa/tree/main/111

テンプレートファイルのポイント解説

RDS

Resources:
  PrimaryInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    Properties:
      AllocatedStorage: !Ref DBAllocatedStorage
      DBInstanceClass: !Ref DBInstanceClass
      DBInstanceIdentifier: dbinstance
      DBSubnetGroupName: !Ref DBSubnetGroup
      Engine: !Ref DBEngine
      EngineVersion: !Ref DBEngineVersion
      MasterUsername: !Ref DBMasterUsername
      MasterUserPassword: !Ref DBMasterUserPassword
      VPCSecurityGroups:
        - !Ref DBSecurityGroup

  ReadReplicaInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    Properties:
      DBInstanceClass: !Ref DBInstanceClass
      SourceDBInstanceIdentifier: !Ref PrimaryInstance
Code language: YAML (yaml)

1つ目のリソースがプライマリインスタンスです。
リードレプリカを作成する上で、特別な設定は不要です。

2つ目のリソースがリードレプリカインスタンスです。
SourceDBInstanceIdentifierプロパティでプライマリインスタンスを指定します。

(参考) EC2インスタンス

Resources:
  Instance:
    Type: AWS::EC2::Instance
    Properties:
      IamInstanceProfile: !Ref InstanceProfile
      ImageId: !Ref ImageId
      InstanceType: !Ref InstanceType
      NetworkInterfaces:
        - DeviceIndex: 0
          SubnetId: !Ref InstanceSubnet
          GroupSet:
            - !Ref InstanceSecurityGroup
      UserData: !Base64 |
        #!/bin/bash -xe
        yum update -y
        yum install -y mariadb
Code language: YAML (yaml)

EC2インスタンスからDBインスタンスにアクセスするために、クライアントパッケージを準備する必要があります。
今回はユーザデータを使用して、パッケージをインストールします。

ユーザデータに関する詳細については、以下のページをご確認ください。

https://awstut.com/2021/12/02/ec2-init-4ways

Amazon Linux 2から各種RDSに接続するためのクライアントパッケージについては、以下のページをご確認ください。

https://awstut.com/2022/03/21/al2-connect-to-all-rds

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

https://awstut.com/2021/12/02/cloudformation-nested-stacks

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • EC2インスタンス:i-08ac3e2191dbd318d
  • プライマリDBインスタンス:dbinstance
  • プライマリDBインスタンスのエンドポイントDNS名:dbinstance.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com
  • リードレプリカDBインスタンス:fa-111-rdsstack-1lrqk70uga1zi-readreplicainstance-whcb2xnwbhfb
  • リードレプリカDBインスタンスのエンドポイントDNS名:fa-111-rdsstack-1lrqk70uga1zi-readreplicainstance-whcb2xnwbhfb.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com

AWS Management Consoleから各リソースを確認します。

RDSを確認します。

Detail of RDS 1.

2つのインスタンスが作成されています。
Roleを見ると、一方はプライマリ、もう一方はリードレプリカです。

それぞれの詳細を確認します。

Detail of RDS 2.
Detail of RDS 3.

2つのDBインスタンスが異なるAZ上のサブネットに配置されていることがわかります。

動作確認

プライマリインスタンスにアクセス

EC2インスタンスからプライマリインスタンスに接続します。
EC2インスタンスへのアクセスはSSM Session Managerを使用します。

% aws ssm start-session --target i-08ac3e2191dbd318d
...
sh-4.2$
Code language: Bash (bash)

SSM Session Managerの詳細につきましては、以下のページをご確認ください。

https://awstut.com/2021/12/01/ssm-session-manager-linux

ユーザーデータによるEC2インスタンスの初期化処理の実行状況を確認します。

sh-4.2$ sudo yum list installed | grep mariadb
mariadb.aarch64                       1:5.5.68-1.amzn2                 @amzn2-core
mariadb-libs.aarch64                  1:5.5.68-1.amzn2                 installed

sh-4.2$ mysql -V
mysql  Ver 15.1 Distrib 5.5.68-MariaDB, for Linux (aarch64) using readline 5.1
Code language: Bash (bash)

正常にMySQLクライアントパッケージがインストールされていることがわかります。

このクライアントパッケージを使用して、DBインスタンスに接続します。

sh-4.2$ mysql -h dbinstance.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com  -P 3306 -u testuser -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 21
Server version: 8.0.28 Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

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

MySQL [(none)]> 
Code language: Bash (bash)

接続できました。

試しにテスト用データベースおよびテーブルを作成し、テストデータを保存します。

MySQL [(none)]> CREATE database test;

MySQL [(none)]> use test;

MySQL [test]> CREATE TABLE planet (id INT UNSIGNED AUTO_INCREMENT, name VARCHAR(30), PRIMARY KEY(id));

MySQL [test]> INSERT INTO planet (name) VALUES ("Mercury");

MySQL [test]> select * from planet;
+----+---------+
| id | name    |
+----+---------+
|  1 | Mercury |
+----+---------+
Code language: Bash (bash)

正常に動作しました。

リードレプリカインスタンスにアクセス

続いてリードレプリカインスタンスに接続します。

sh-4.2$ mysql -h fa-111-rdsstack-1lrqk70uga1zi-readreplicainstance-whcb2xnwbhfb.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com  -P 3306 -u testuser -p
Enter password:
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 8.0.28 Source distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

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

MySQL [testdb]>
Code language: Bash (bash)

こちらも正常に接続できました。

試しに読み込み/書き込み時の動作を確認します。

MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+

MySQL [(none)]> use test;

MySQL [test]> select * from planet;
+----+---------+
| id | name    |
+----+---------+
|  1 | Mercury |
+----+---------+

MySQL [test]> INSERT INTO planet (name) VALUES ("Venus");
ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
Code language: Bash (bash)

読み込みは成功しました。
プライマリインスタンスで書き込んだ内容が、リードレプリカにも反映されています。

一方で、書き込みには失敗しました。
これはこのインスタンスが読み込み専用であるためです。

リードレプリカの昇格

リードレプリカは昇格させることができます。

リードレプリカを新しい DB インスタンスに昇格させると、他の DB インスタンスと同等になります。

昇格した DB インスタンスはリードレプリカではなくなったため、レプリケーションターゲットとしては使用できません。

リードレプリカをスタンドアロン DB インスタンスに昇格させる

今回はAWS CLIを使用して、リードレプリカを昇格させます。

$ aws rds promote-read-replica \
--db-instance-identifier fa-111-rdsstack-1lrqk70uga1zi-readreplicainstance-whcb2xnwbhfb
Code language: Bash (bash)

改めてリードレプリカ側の状況を確認します。

Detail of RDS 4.

Roleが「Instance」とありますので、リードレプリカから通常のインスタンスに昇格したことがわかります。

Detail of RDS 5.

イベントログを見ても、通常のインスタンスに昇格後、再起動を実施したことが読み取れます。

改めてこのインスタンスに接続します。

sh-4.2$ mysql -h fa-111-rdsstack-1lrqk70uga1zi-readreplicainstance-whcb2xnwbhfb.cl50iikpthxs.ap-northeast-1.rds.amazonaws.com  -P 3306 -u

MySQL [(none)]> use test;

MySQL [test]> INSERT INTO planet (name) VALUES ("Venus");

MySQL [test]> select * from planet;
+----+---------+
| id | name    |
+----+---------+
|  1 | Mercury |
|  2 | Venus   |
+----+---------+
Code language: Bash (bash)

今回は書き込み処理が成功しました。
リードレプリカから通常のインスタンスに昇格したため、書き込み処理が可能となりました。

まとめ

CloudFormationを使用して、リードレプリカを作成しました。
加えてリードレプリカの昇格方法についても確認しました。