21億の壁を突破せよ！Aurora Blue/Green DeploymentでINTからBIGINTへ

# 1. 背景
あるECプロジェクトで、AWS Aurora MySQLを利用しています。テーブルの主キー（IDカラム）を`INT`型の`AUTO_INCREMENT`に設定していましたが、購買履歴テーブルのレコード数が`INT`型の上限（2,147,483,647）に迫る状況に直面しました。
この上限に達すると、新規レコードの追加ができなくなり、サービス停止という重大な事態につながる可能性があります。そのため、カラムの型を`INT`型から`BIGINT`型に変更し、上限を引き上げる必要がありました。
本記事では、Aurora のBlue/Green Deploymentを用いて`INT`型のカラムを`BIGINT`へ変更する過程で直面した課題とその解決策についてまとめます。この経験が誰かの役に立てば幸いです。
なぜINTからBIGINTへの変更は大変なのか？については以下の記事をご参考ください。

https://qiita.com/dennis_wang/items/ba869fd0ffb81993516d

# 2. INTからBIGINTへの変更を行う案の概要
当初は以下の2種類の案を調査、整理しました：
1. `pt-online-schema-change`を利用する案（同じインスタンス、同じDBで新しいテーブル作成）
2. レプリケーションを利用するBlue/Green Deploymentの案（完全に新しい環境/インスタンスを作成し、レプリケーションを通じてリアルタイムにデータ同期）
さらにこちらは以下の案に分けられます：
    - 手動`binlog`レプリケーション
    - RDS read replica利用
    - AWS DMS
    - RDS Blue/Green Deployment

https://qiita.com/dennis_wang/items/cfb5050c8761e8cf8293

Auroraを使用しているため、Blue/Green Deployment方式であればフルサポートが可能なRDS Blue/Green Deploymentが最適と判断し、それ以外の3つの案は除外しました。
今回は`pt-online-schema-change`案と`RDS Blue/Green Deployment`案の2つに絞って比較しました。


# 3. pt-online-schema-change利用の案
## 3.1 pt-online-schema-changeの概要
pt-online-schema-change(pt-osc)はPercona Toolkitの一部で、MySQLテーブルの構造を変更する際にダウンタイムを最小限に抑えるツールです。
```sql
pt-online-schema-change --alter "MODIFY COLUMN id BIGINT" D=database,t=table
```
## 3.2 動作原理
pt-online-schema-change (pt-osc)の動作原理について、主要なポイントを詳しく解説します：

1. 新しいテーブルの作成:
   - pt-oscは元のテーブルと同じ構造を持つ新しいテーブルを作成します。
   - 新しいテーブル名は通常、元のテーブル名の前に "_" を付けたものになります。
    - 非常に短時間（通常はミリ秒単位）のメタデータロック、この間、DDL操作はブロックされますが、SELECT/INSERT/UPDATE/DELETEは影響を受けません

2. 新テーブルへのALTER文の適用:
   - 指定されたALTER文(この場合は`MODIFY COLUMN id BIGINT`)を新しいテーブルに適用
        ```sql
        ALTER TABLE table_name MODIFY COLUMN column_name BIGINT;
        ```
   - この時点では新テーブルにはデータがないため、高速に完了します。

3. トリガーの作成:
   - 元のテーブルにINSERT、UPDATE、DELETEの3つのトリガーを作成します。

   - これらのトリガーは、元のテーブルへの変更を新テーブルにリアルタイムで反映させます。

4. データのコピー:
   - 元のテーブルから新テーブルへデータをチャンク（小さな単位）でコピーします。
   - コピー中も元のテーブルへの書き込みは可能で、トリガーによって新テーブルに反映されます。

5. テーブルの入れ替え:
   - データコピーが完了したら、RENAME TABLE文を使用して新旧テーブルを瞬時に入れ替えます。
   - 入れ替える際に短時間（通常は1秒未満）のロックが発生
       - すべての書き込み操作がブロック
       - 読み取り操作は通常影響を受けません）

6. クリーンアップ:
   - 古いテーブルの削除とトリガーの削除を行います。
:::note info
レプリケーションへの対応:
pt-oscはレプリケーション環境を考慮して設計されています。マスターでの操作がスレーブに正しくレプリケートされるよう、以下の対応をしています。これにより、マスターでの変更がスレーブに正確に反映され、データの整合性が保たれます。
  1. バイナリログの形式をROWに設定することを推奨
  2. トリガーの作成・削除をバイナリログに記録
  3. RENAME TABLE操作をバイナリログに記録
:::

## 3.3 注意点
1. 非常に単純で、コマンド一つで実行可能ですが、同じインスタンス上で大規模なデータコピーが発生するため、本番データベースのパフォーマンスに影響を与える可能性があります。実施する前に、一時的にインスタンスのスペックを上げることなどの必要性を検討したほうがよいでしょう。
1. コスト面：
ツール自体は無料ですが、実行中のパフォーマンス影響を考慮してインスタンスのスペックアップが必要な場合があります。
    例：一時的にインスタンスタイプをr5.2xlargeからr5.4xlargeにアップグレードする場合、数時間から数日の追加コストが発生する可能性があります。
1. 非常に大規模なテーブルの場合、処理時間が長くなる可能性があります。

この方法により、pt-oscはテーブルへのアクセスを維持しながら、大規模なスキーマ変更を安全に実行することができます。

参考記事：

https://developers.freee.co.jp/entry/introduction-of-pt-online-schema-change

https://www.s-style.co.jp/products/percona/toolkit/pt-online-schema-change

https://qiita.com/an_sony/items/9b8fcb625cccb959f6a0

## 3.4 replicationを利用するBlue/Green Deploymentの案
`Blue/Green Deployment`は<font color="red">新しい概念でも Aurora 専用の手法でもありません</font>。
これは、<font color="red">アプリケーションの新バージョンをリリースする際に広く使用される一般的なデプロイメント戦略</font>です。
最近はインフラエンジニアにとってはもはや<font color="red">当たり前</font>になってきました。

Blue/Green Deploymentsでは、本番環境をコピーしてグリーン環境を作成し、そこで変更をテストすることができます。この手法を用いることで、本番環境に影響を与えることなく、データベースのメジャーまたはマイナーバージョンのアップグレードやデータベースパラメータの変更を行うことができます。グリーン環境での変更をテストし、問題がなければ、グリーン環境を新しい本番環境としてプロモートすることができます。

https://qiita.com/dennis_wang/items/cfb5050c8761e8cf8293#34-4%E3%81%A4%E3%81%AE%E6%A1%88%E3%81%AE%E6%AF%94%E8%BC%83


## 3.5 ２つの案の比較
| 特性 | pt-online-schema-change | Aurora Blue/Green Deployment |
|------|-------------------------|------------------------------|
| 処理場所 | <font color="red">同一インスタンス、同一DB、新しいtable</font> | <font color="red">別々の環境(別々のインスタンス)</font> |
| 複雑さ | 低<br>- 単一コマンドで実行可能 | 中<br>- AWS設定が必要 |
| 実装時間 | 短い - 自動化された処理 | 中 - 環境構築に時間要 |
| リスク | 中<br>- 短時間ロックあり<br>- 同一インスタンスでの処理によるオーバーヘッドあり | 低<br> - 切り替え前環境維持、別環境で処理、切り替え時のみ影響 |
| コスト | 低<br>- ツール無料、一時的なインスタンス増強の必要性あり | 高<br> - 環境複製で一時的にコスト倍増 |
| データ整合性 | 高<br>- ツールが自動管理 | 高<br>- AWS管理で保証 |
| ロールバック容易性 | 中<br>- 現環境に対して修正するため、手動復旧が必要な場合あり | 高<br> - 切り替え前環境が維持されるため容易 |
| アプリケーション変更 | 不要 | 不要 |
| プラットフォーム依存性 | 低<br>- MySQL環境であれば基本的に使用可能 | 高<br>- AWS MySQL専用 |
| バイナリログ影響 | なし | あり <br>- 有効化が必要で若干のオーバーヘッドあり |
| 大規模データベース対応 | 中 - 大規模DBでは時間がかかる可能性あり | 高 - 大規模DBでも効率的に処理可能 |

この比較表から、以下のような結論が導き出せます：
1. pt-online-schema-changeは、シンプルさ、コスト効率、柔軟性において優れています。特に小規模から中規模のデータベース、またはAWS以外の環境でも使用可能です。

2. Blue/Green Deploymentは、完全に別のGreen環境で作業するため、安全性、スケーラビリティ、大規模データベース対応において優れています。特にAWS Aurora MySQLを使っているので、最後にRDS Blue/Green Deploymentを使うことにしました。


# 4. Aurora Blue/Green Deploymentsを利用してみる
## 4.1 利用の条件
- バイナリログの有効化: Blue環境でバイナリログを有効にする必要があります。バイナリログのフォーマットはROWが推奨されますが、以下のことが注意したほうがよい。
- ログの肥大化やディスク容量の増加
- I/O速度(パフォーマンスへの影響):通常5%未満
- クラスタの再起動が必要：
    クラスターパラメータグループの変更が適用されていないと、グリーン環境を作成できない。変更後はクラスタの再起動が必要です。
- 一時的に2つの環境を維持する必要があるため、コストが倍増する期間がある。

## 4.2 切替までの流れ
切替までの流れは大まかに以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/80619c2f-7a49-f005-9e70-c7a61baea500.png)

1. バイナリログの有効化：Aurora再起動が必要なので注意
    - パラメータグループの作成
    RDS/AuroraのBlue/Greenデプロイを実施するためにはDBクラスタ用のパラメータグループの`binlog_format`(デフォルトはOFF)を`MIXED`に変更する必要があります。
    尚、デフォルトのパラメータグループはパラメータの変更ができないため新規で作成してパラメータ変更を行う必要があります。
    - パラメータの変更
    作成したDBクラスタ用のパラメータグループを編集して、`binlog_format`を`MIXED`に変更します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/4852b12f-32f3-59a1-4532-94a59ca29e04.png)
    
    - 既存のAurora Clusterのパラメータグループを変更(Aurora再起動が必要なので注意)

2. AuroraにRDS Blue/Green Deploymentsを有効化して、新Aurora Cluster(Green環境)を作成
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/fa8f705a-2bdf-fab4-0795-b496609fe5ef.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/f04373b7-adb2-3ebb-d12d-35e21491ce9b.png)

    :::note info
    Green環境作成時にBlue環境DBの停止は発生するか？
    検証結果としてはライター(読み書き)、リーダー(読み込み)どちらも停止がなかった。
    CPU利用率については、ライターのCPU使用率5％ほど1分間増えただけで、後は平常と変わっていない。
    :::

3. Green環境で`ALTER TABLE`を実行して、`int`型を`bigint`型に変更
    ```sql
    SHOW CREATE TABLE purchase_history;
    
    CREATE TABLE `purchase_history` (
      `purchase_id` int(11) NOT NULL AUTO_INCREMENT,
      `user_id` int(10) unsigned NOT NULL,
      `product_id` int(10) unsigned NOT NULL,
      `quantity` int(10) unsigned NOT NULL,
      `purchase_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
      PRIMARY KEY (`purchase_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
    ```
    ```sql
    ALTER TABLE purchase_history 
    MODIFY COLUMN purchase_id BIGINT AUTO_INCREMENT;
    ```
    Green環境でのALTER TABLE操作には約60時間を要しましたが、この間も現行Aurora（Blue環境）は通常通りにトラフィックを処理し続けたため、長時間のサービス停止を回避できました。

1. ALTER TABLE実行完了後、以下の点を慎重に観察：
    - レプリケーションが継続していること
    - binlog有効化によるBlue環境への影響（CPU使用率やメモリ使用率など）
    - Blue環境とGreen環境間のデータ同期にレイテンシーが発生していないこと
    CloudWatchの`ReplicaLag`メトリクスでレイテンシー確認できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/4ea5336f-b61c-a116-e139-ec8185eba80f.png)

1. Green環境で一通り機能テストを実施
1. 本番切替時にRDS Blue/Green DeploymentsのSwitch Overを実行し、Green環境を新本番環境に昇格させました。この操作には以下の特徴がありました：
    - <font color="red">アプリケーション側の変更不要</font>：
    元のデータベースエンドポイントが自動的にGreen環境に向けられたため、アプリケーション側のコード変更や設定変更は一切必要ありませんでした。
    - **短時間のサービス中断**：
        - <font color="red">切替に要した時間は約2分</font>でした。この間、データベースへの接続が一時的に中断されるため、サービスは利用できません。
        - <font color="red">2分間の切替時間以外は、サービスは通常通り利用可能</font>でした。つまり、全体のプロセスの中で、実際のサービス中断時間は非常に短く抑えられました。

    :::note info
    1. サービスのダウンタイムを測定：
    サービスのダウンタイムを正確に測定するために、APIのエンドポイントへcurlコマンドを継続的に実行してみます。
        ```shell
        $ while true; do date; curl http://***/api/path ; date; sleep 1; done | tee -a /tmp/tee.log
        ```
    
    2. 切り替え後に切り戻しはできるか?
    切り替え後もBlue環境は保持されますが、Green環境からのレプリケーションが切断された、読み取り専用（Read-only）のクラスターとなります。
    Blue環境には切り替え時点のデータしか残っておらず、ユーザーからのトラフィックを停止しない限り、Blue環境とGreen環境の間にデータの差分が発生します。そのため、<font color="red">切り替え後に簡単にBlue環境に戻すことはできません。</font>
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/a914dfaa-95d8-9710-5fa7-d6de4005dd63.png)


1. 旧環境を別途削除


# 5. まとめと考察
1. `pt-online-schema-change`と`RDS Blue/Green Deployment`の比較：
`pt-online-schema-change`は興味深いツールですが、同一インスタンス上で新しいテーブルを作成してデータをコピーする方式であるため、既存の本番環境へのパフォーマンス影響が懸念されました。一方、`RDS Blue/Green Deployment`はマネージドサービスとして提供されており、より安全性と信頼性が高いと判断し、最終的にこちらを選択しました。
2. Auroraでの`binlog`有効化の影響：
Auroraでは`binlog`を有効にする必要があり、これによってBlue環境に対して若干のパフォーマンス影響が生じる可能性があります。そのため、実施中は環境の状態を入念に監視し、必要に応じて対応を取ることが重要です。
3. 短時間のダウンタイムは避けられませんでしたが、全体としてはサービスへの影響を最小限に抑えつつ、大規模なデータベース変更を安全に実施できました。この点を考慮すると、RDS Blue/Green Deploymentの採用は非常に効果的な選択だった。

この方法により、技術的な複雑さを抑えつつ、ビジネス継続性を維持しながら重要なインフラストラクチャの更新を実現できました。今後同様の作業を行う際の有効な参考事例になると幸いです。