Amazon Aurora Serverlessを動かしてみよう！


<iframe width="560" height="315" src="https://www.youtube.com/embed/bwQGNnqY8X4?si=SIyIx7a_KV1PhcVp" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

みなさんこんにちは。

今回はAmazon Aurora Serverlessの特徴と使い方について紹介していきます。

Serverlessとはどういったもの何か、通常のインスタンスとして作る場合と何か違うのかを知りたい場合は、ぜひ参考にしてみてください。

# Aurora Serverlessとは？
![aurora-serverless02.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/b0349477-a881-233d-3da1-7c625b3796ef.jpeg)

Amazon Aurora Serverlessは、フルマネージド型のサーバーレスデータベースサービスです。

従来のプロビジョニング型のAuroraデータベースでは、使用するインスタンスのサイズを事前に決定し、それに応じた料金を支払う必要がありました。一方、Serverlessでは、事前にインスタンスサイズを決める必要がなく、実際の使用状況に応じて自動的にスケールしてくれるため、より効率的なリソース管理が可能です。

# Aurora Serverlessの特徴

主な特徴として以下の様なものが挙げられます。

## 1. 自動スケーリング：
![aurora-serverless03.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/1f1176df-78cd-7aea-349d-bc19372208d0.jpeg)

Aurora Serverlessでは、データベースの処理能力をACU（Aurora Capacity Unit）という独自の単位で管理します。
1ACUは2GBのメモリと、それに対応するCPUおよびネットワーク性能を提供します。
運用時には、ACUの最小値と最大値を事前に設定しておきます。すると処理負荷に応じてこの範囲内で自動的にスケールアップ/ダウンし、必要なリソースを必要な時だけ確保します。

## 2. 柔軟なコスト最適化：
![aurora-serverless04.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/8904f965-7b75-bcba-233a-417255ca0e10.jpeg)

プロビジョンド型のインスタンスでは、設定したインスタンスサイズに対して課金されるため、リソースを使用していない時間帯でも料金が発生してしまいます。
一方、Aurora Serverlessは実際に使用したACU時間とストレージ容量に対してのみ課金されます。普段の使用量が少ない場合はACUを低く設定することで、コストを最小限に抑えることができます。

## 3. 自動停止：
![aurora-serverless05.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/667a91c4-760b-c83f-e1d2-94a0a3561895.jpeg)

これは最近のアップデートで追加された機能です。従来、ACUは最小0.5ACUから最大128ACUまでの範囲で調整可能でした。
最新のServerless Version 2では0ACUまで指定が可能となり、一定時間使用されていない場合に0 ACUまでスケールダウンして自動的に一時停止できるようになりました。一時停止中はインスタンス容量に対する課金は発生しません。このため、SLO（サービスレベル目標）が定まっていないサービスや開発・テスト環境で利用するデータベースなどに特に役立ちます。

これらの特徴により、開発環境やテスト環境、負荷変動の大きいワークロード、負荷の予測が難しいケースではServerlessが適しています。
基本的に従来のプロビジョンド型のAuroraデータベースと機能は同じですので詳しい仕様を知りたい場合は公式ドキュメントを確認してみてください。

# ハンズオン説明
それではここからは試しにAurora Serverlessを構築して、実際にデータベースを作ってみましょう。

今回のハンズオンでは以下の様なことをやっていきます。

1. AWS CloudFormationを使ってAurora Serverless (for MySQL)を構築
2. AWS CloudShellから構築したAurora Serverless for MySQLにアクセスし、簡単なデータベースを作成
3. Aurora Serverlessに負荷をかけてスケーリングテストをしてみる

構成は以下のようになっています。

![aurora-serverless06.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/4dcf6d8a-73ac-4b0a-226f-f0c4b9ecafb4.jpeg)

今回は必要な環境は全てCloudFormationで作成していきます。

- ハンズオン用のVPCネットワークを構築
- パブリックサブネットにCloudShell環境を作成
- バックサブネットにAurora Serverlessを構築（CloudShellからアクセスできる様にする）
    - 今回はSingle-AZ構成の簡易的なものを作成

また、以下のことは説明しませんので、事前に対応をお願いします。

- AWSアカウントの準備
- 必要な権限を持ったIAMユーザーを準備していること

  ※管理者アカウントでも良いが、専用のIAMユーザーを作ることを推奨


## ハンズオン環境構築

ここではCloudFormationを使ってスタックを作成していきます。

以下のテンプレートを作成して、スタックを作成しましょう。

<!-- open属性なし -->
<details><summary>CludFormationテンプレート</summary>

```yaml:aurora-serverless.yml
AWSTemplateFormatVersion: 2010-09-09
Description: Aurora Serverless Handson Template.

Resources:
  # VPC
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 192.168.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: aurora-serverless-vpc

  # Subnet
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      VpcId: !Ref VPC
      CidrBlock: 192.168.10.0/24
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: aurora-serverless-public-subnet-1a

  BackSubnet1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 192.168.20.0/24
      Tags:
        - Key: Name
          Value: aurora-serverless-back-1a
  BackSubnet2:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: ap-northeast-1c
      CidrBlock: 192.168.40.0/24
      Tags:
        - Key: Name
          Value: aurora-serverless-back-1c

  # InternetGateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: aurora-serverless-igw
  InternetGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  # RouteTable
  PublicRouteTable01:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: aurora-serverless-public-rtb
  PublicRoute01:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable01
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicSubnetRouteTableAssociation01:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable01

  BackRouteTable:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: aurora-serverless-back-rtb
  BackRouteTableAssociation1:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref BackSubnet1
      RouteTableId: !Ref BackRouteTable
  BackRouteTableAssociation2:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref BackSubnet2
      RouteTableId: !Ref BackRouteTable

  # SecurityGroup
  DBSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: aurora-serverless-sg
      GroupDescription: SecurityGroup for Aurora Database
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - {
            IpProtocol: tcp,
            FromPort: 3306,
            ToPort: 3306,
            CidrIp: 192.168.0.0/16,
            Description: allow from inner VPC,
          }
      SecurityGroupEgress:
        - { IpProtocol: '-1', CidrIp: 0.0.0.0/0 }
      Tags:
        - Key: Name
          Value: aurora-serverless-sg

  # DBSubnetGroup
  DBSubnetGroup1:
    Type: 'AWS::RDS::DBSubnetGroup'
    Properties:
      DBSubnetGroupDescription: DB Subnet Group
      DBSubnetGroupName: aurora-serverless-dbnet
      SubnetIds:
        - !Ref BackSubnet1
        - !Ref BackSubnet2
      Tags:
        - Key: Name
          Value: aurora-serverless-dbnet

  # DBCluster
  DBCluster1:
    Type: 'AWS::RDS::DBCluster'
    Properties:
      DBClusterIdentifier: aurora-serverless-db
      DBSubnetGroupName: !Ref DBSubnetGroup1
      Engine: aurora-mysql
      EngineVersion: 8.0.mysql_aurora.3.04.0
      MasterUsername: rdsroot
      # change password if neccesary
      MasterUserPassword: PassW0rd
      VpcSecurityGroupIds:
        - !Ref DBSecurityGroup
      StorageEncrypted: true
      EngineMode: provisioned
      ServerlessV2ScalingConfiguration:
        MaxCapacity: 128
        MinCapacity: 0.5
      BackupRetentionPeriod: 3
      Tags:
        - Key: Name
          Value: aurora-serverless-db

  # DBInstance
  DBInstance:
    Type: 'AWS::RDS::DBInstance'
    Properties:
      DBClusterIdentifier: !Ref DBCluster1
      DBInstanceClass: db.serverless
      DBInstanceIdentifier: aurora-serverless-serverless
      Engine: aurora-mysql
      EngineVersion: 8.0.mysql_aurora.3.04.0
      Tags:
        - Key: Name
          Value: aurora-serverless-serverless
```

</details>

スタックが作成完了したら必要な環境の構築は完了です。

![aurora-serverless-handson01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/d19aca67-28f3-dd37-b5ae-e17f61c16306.png)

## データベース作成

構築が完了したら、早速Aurora ServerlessデータベースにMySQL接続してみます。

CloudShell画面を開きます。

![aurora-serverless-handson02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/37abcd61-c645-9205-3cd2-2fc43aec4b35.png)

デフォルトだとCloudShell環境はVPC外で作られるので、
VPC内に手動で作成をする必要があります。
今回はパブリックサブネット上にCloudShell環境を配置します。

![aurora-serverless-handson03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/33f560b7-9660-c83c-71e6-780b4225f4b3.png)
![aurora-serverless-handson04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/56714b5b-7d1a-5f7b-cbfa-7d1d5ad0c7a1.png)

作成が完了したらMySQL接続をしてみましょう。
以下コマンドで必要な情報を入力してMySQL接続をしましょう。

```bash
mysql -h <Writerエンドポイント名> -u <DBマスターユーザー名> -p<DBマスターパスワード>
```

接続が完了したら、簡単なデータベースを作成してみます。
サンプルとして以下コマンドを掲載しておきます。

```sql:sample.sql
-- データベースの作成
CREATE DATABASE `serverlesstest`;
USE `serverlesstest`;

-- テーブル作成
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    birth_date DATE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Create（ユーザー登録）
INSERT INTO users
(username, email, first_name, last_name, birth_date)
VALUES
('yamada_taro', 'taro@example.com', '太郎', '山田', '1990-01-01');

-- Read（ユーザー情報取得）
SELECT * FROM users;
```

ユーザー情報が取得できていれば、データベース操作は問題なさそうです。

![aurora-serverless-handson05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/1680c63c-da01-10e8-eacd-76c5ca9ad3a8.png)


## ACUをスケーリングさせてみよう

それでは、試しにデータベースに負荷をかけてCPU使用率を高騰させ、データベースがどの様にスケールアップするのかを確認してみましょう。
ここではMySQLの標準ツールであるmysqlslapコマンドを使用して一時的に負荷をかけてみます。

CloudShellのターミナルから以下のコマンドを実行してみます。

```bash
mysqlslap \
--concurrency=100 \
--iterations=50 \
--auto-generate-sql \
--auto-generate-sql-add-autoincrement \
--auto-generate-sql-load-type=mixed \
--auto-generate-sql-write-number=1000 \
--number-of-queries=100000 \
--engine=InnoDB \
--host=HOST_NAME \
--user=user \
--password=password
```

以下オプションの値は作成したAurora Serverlessの情報に置き換えてください。

> `-host=v2-localhost`: 接続先のホスト名
`-user=user`: MySQLに接続するためのユーザー名
`-password=password`: MySQLに接続するためのパスワード
>

試しにCloudWatchでACUとCPUの使用率を確認すると、
CPUが上昇と共にACUも増加していることが確認できると思います。

![aurora-serverless-handson06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/727bc291-1663-3bd3-8b52-76655849bd8d.png)
![aurora-serverless-handson07.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524408/66c553f0-4ecc-7baa-4ae7-2025c3998b4e.png)