AWSでクソアプリのアーキテクチャを2週間でガチガチに改修した

AWS雰囲気使いを卒業するために、既存アプリのアーキテクチャを
2週間で結構強固なものに改造してみたので改造前と改造後、そして将来的に実装したいFuture workを書き残しておこうと思います。

(ほとんど自己満足で行ったので、必要以上のことをしてしまっている部分があったり、説明を省いている部分があります。)

##既存アプリの詳細
今回改造することにしたアプリケーションは非同期でチャットができるようなwebアプリで、いわゆるL○NEやカカ○ークのようなチャットアプリのwebブラウザバージョンと思っていただけたらと思います。

改造前は、2つのAZ上のpublic subnetにおいたEC2(t2micro)をロードバランサーに設定したうえ、単一のRDSをprivate subnetに置いただけの設計で、ストレージもそれぞれのEC2インスタンス(Ruby on Rails内)が保持し、DBに画像ファイルのパス名を格納しているというもはや完全に不具合とも捉えられる状態でした。

このままではユーザー数が増えた際のEC2インスタンスのサーバーダウンが容易に考えられ、またDBのフェイルオーバー、スケールアップ等もカバーされていない状態です。

他にも、インフラをdockerを用いて殆ど手動で管理していて、サーバーを起動するのにそれぞれのインスタンス内に接続してdocker-compose upしないといけないような、色々と管理コストの高いアプリケーションでした。

##改善したポイント
2週間で実装できる範囲で最低限アプリケーションを強固なものし、また今後のインフラの管理コストをできるだけ下げるべく、ほとんどの管理工程の自動化を試みました。


- ストレージにS3の導入
- EC2スケーリング,  復旧,  ストレージ最適化等の自動化
- Auroraの導入、DBスケーリングの自動化,  キャッシュメモリの導入
- AWSリソースの管理をコード化(インフラ構築の自動化、CI/CDパイプラインの構築)
- システム状況を可視化


##改善後アーキテクチャ

改善後のアーキテクチャ図はこんな感じです。
![スクリーンショット 2020-09-02 13.33.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/382190/72181988-8f2d-f088-bf6c-90f62c5693e0.png)

###使用AWSリソース
- CloudFront
- S3
- ElastiCache
- Aurora
- Amazon SNS
- Code pipeline
- Code build
- Code deploy
- Cloud watch
- Compute optimizer
- Cloudformation

## 主な変更点

1.ストレージにS3の導入
2.EC2スケーリング,  復旧,  ストレージ最適化等の自動化
3.DBスケーリングの自動化,  キャッシュメモリの導入
4.AWSリソースの管理をコード化(インフラ構築の自動化)
5.システム状況を可視化

###1.ストレージにS3の導入
- 画像ファイルをS3に保管する
→現状のコードを少し修正する必要がある
- バックアップのスナップショットもS3に保存
- アクセスはしないが消したくないデータ(ログなど）はS3 glacierに保存

まず、最低限ストレージをS3に統一します。
これをしないと、あるEC2インスタンスでアップロードされた画像が他のインスタンスからは表示されないといった不具合が生じます。

また、後で説明するDBのバックアップもスナップショットしてS3に保存します。

さらに、アクセスはしないが消したくないデータ(ログなど）はS3 glacierに保存しておくとより低コストに抑えられるので、導入しました。

###2.EC2スケーリング,  復旧,  ストレージ最適化等の自動化
- Autoscalingによるスケーリング自動化
- Compute Optimizerでインスタンスタイプ, Autoscalingの最適化
- Cloudwatchアラーム設定でEC2インスタンス の自動復旧
- Amazon SNSによる障害、自動復旧の通知

今後ユーザー数が増えた際に、サーバーに対してリクエスト過多が発生してしまう可能性があります。その際にEC2のスケールアウトを自動化しておくために、Autoscalingを導入します。

また、現在はt2microを採用しているのですがこちらのインスタンスタイプの最適化もCompute Optimizerを導入することによって自動化することができます。

さらに、万が一EC2インスタンスが破損してしまった場合の対策として、Cloudwatchというサービスのアラーム設定をしておくと、EC2インスタンスを自動復旧をしてくれるようになります。
ここで念のため、Amazon SNSでEC2破損時にメールにて通知がくるように設定しておくと、即座に破損のお知らせが届くようになるので、予め設定しておきます。

###3.DBスケーリングの自動化,  キャッシュメモリの導入
- Aurora MySQLの導入
→MySQLの5倍のスループット
- Amazon Aurora Auto Scalingで自動スケーリング
- キャッシュ(ElastiCache)で高速化
- DB故障時はAmazon SNSで即座に通知
- DBの冗長化

まずDBをより高性能なAuroraに変更しました。

現状RDSのMySQLを使用しているということで、モデル変更などの必要はなく、Aurora MySQLに代替することにそれほど作業コストはかかりませんし、 Auroraのデフォルト機能でS3にDBバックアップのスナップショットを保存してくれます。

また、 Aurora Auto Scalingで、自動スケーリングも対応させます。
これにより、DBの移行、管理コストをほぼ0にすることが実現できます。

さらに、DBキャッシュであるElastiCacheを導入することで、データの読み込みを最適化します。

最後に、念のため別AZにAuroraをもう一つ設置しておきます。これによって万が一単一のデータセンターで災害がおきてしまった場合もアプリケーションを持続させることが可能になります。

ここまでいくと自己満足です。

###4.AWSリソースの管理をコード化(インフラ構築の自動化)
- CloudFormation
→コードでAWSリソースの管理
- Former2
→templateの自動生成
- CodeBuild
→buildを自動化
- CodeDeploy
→deployの自動化
- CodePipeline
→パイプライン化しインフラ構築、デプロイを自動化

これまでインフラの構築を手動で行っていたのを自動化し、AWSリソース自体をコードで管理できるようにします。

ここでCloudFormationというサービスを利用するのですが、こちらはAWSのシステム構成をJSONで記述してテンプレート化し、構成の管理、修正、再利用を容易にするサービスのことです。

CloudFormationを導入する際には、システム構成を構築する際のテンプレートの作成に手間が少々かかってしまいがちですが、ここでサードパーティーであるFormer2が大活躍してくれます。これは既存のAWSのリソース情報を取得し、CloudFormation, Terraform, Troposphere のテンプレートを生成してくれるようなOSSで、利用しない手はありませんでした。

また、CodeBuild、CodeDeploy、CodePipelineを用いてCI/CDパイプラインを構築し、リリースプロセスを自動化しました。

###5.システム状況を可視化
- Cloudwatchでシステム状況を可視化
→全体のシステムのどの部分に費用がかかっているか可視化
- CloudMapper(サードパーティ)によりアーキテクチャ図を自動で生成
→全体図が把握しやすく, 担当の引き継ぎなどが容易になる

## Future work
今回は2週間という期間だったので実現しきれなかったものの、将来的に実現させてみたことを何点か最後に記させていただきます。

- サーバレス化
- NoSQLへの移行
- SPAの実現
- テスト

現段階では、大量同時接続に弱いRDBを用いていますが、将来的にはユーザー数の増加に伴いDynamoDBなどのNoSQLに移行することが望ましいと思っています。
また、現在EC２に保管しているアプリケーションを完全にS3に移すことでSPAも実現させたいです。
おまけとして、これらの移行がかなった際には、Locust等のツールを用いて負荷増大テストとかもやってみるのも夢です。