👁️‍🗨️

SaaS系スタートアップのリアルなAWSアーキテクチャ設計

2021/04/12に公開

概要

AI革命のインフラを目指すSaaS系スタートアップのFastLabel(最近資金調達しました!記事はこちら)で働いているが、今までGCPで動かしていたインフラを訳あってAWSに基盤を載せ替えることになった。

スタートアップは何よりスピードが求められるが、だからといってセキュリティやモニタリング、可用性を疎かにはできないし、大きなインフラコストに耐えられるほど体力もない。

アプリケーション要件を満たしつつ、以下を実現するアーキテクチャを設計する。

  • シンプルな構成・構築の容易さ
  • スピーディな開発・適用
  • 可用性の担保
  • セキュリティの担保
  • 最低限のモニタリング
  • 低コスト(リソース・運用)

ここで紹介するアーキテクチャは実際に運用まで行っており、問題なく稼働しているし、先日AWSの方にレビューしてもらったが、「なかなかイケてる」というお言葉をもらい、特に改善点も指摘されなかった。

結論(アーキテクチャ)

Architecture

技術領域 AWSリソース
フロントエンド CloudFront + S3
バックエンド ALB + Fargate
データベース Aurora MySQL

「流行りの Lambda + DynamoDB ではないのか?」という声が上がってきそうだが(個人的にも個人開発やスタートアップの最初期、アプリケーションが複雑でないなどの場合はこの構成がベストだと思う)、シード期まできて様々なお客さんがつき、色々と要件が見えてきた結果このような構成をとることになった。詳細は後述する。

因みにGCPでは Cloud Functions + Firestore で、 Lambda + DynamoDB にかなり近い構成だった。

考慮事項

アプリケーション要件など考慮事項は下記。

  • フロントエンドはReact、バックエンドはNode.js
  • 割と大きめのデータ通信が発生する
  • ページネーションや集計処理も頻繁に発生する
  • バッチ処理(非同期処理)が必要な処理がある

アーキテクチャの解説

ネットワーク

Network

VPC + Subnet + NatGateway といった基本構成を採用。NatGatewayは少々高いが、セキュリティとその可用性を担保するために Multi AZ に配置している。

データベース、バックエンドリソースはこちらもベストプラクティスにのっとり Private Subnet に配置し、Security Group によりアクセスを制限する。

フロントエンド

Frontend

CloudFront + S3 といった基本構成を採用。S3にReact.jsの静的ファイルをデプロイしている。Amplifyなども候補であったが、こちらの構成の方が利用実績があり、私自身の経験もあったので構築スピードや運用コストを重視した。

CloudFrontにはACMで発行したSSL証明書を紐付けてHTTPS通信にしている。

データベース

Database

Aurora MySQL を採用。Multi AZ に配置し、Readレプリカはオートスケールするように設定してある。パフォーマンスインサイトをONにしたり、スロークエリーログ・エラーログを CloudWatch Logs に出力することで、モニタリングも十分可能。

バックアップに関しても、ポイントインタイムリカバリやバックトラックがサポートされているのでちょっとしたスクリプトを用意しておくだけで簡単にデータを復旧できる。

データベース選定は結構迷ったので、他の選択肢と選んだ理由を説明する。

DynamoDB(NoSQL) vs. RDS(RDB)

コストとスケールの容易さでいうと圧倒的にDynamoDBだが、数多くのトランザクション処理、ページング処理、集計処理を考えると、RDBを採用したほうが結果として開発スピードが上回ると判断した。

また、市場や周りにNoSQLよりRDBを扱えるバックエンドエンド人材が多いことも要因の一つ。

Aurora MySQL vs. Aurora Serverless

リソース・運用コストの軽減を狙い、はじめは Aurora Serverless を採用しようと思ったが、自動スケーリングの問題と、利用実績の少なさが理由で Aurora MySQL を選択した。

自動スケーリングの問題は、スケールアップまでに数十秒の時間がかかり、UXを重視する弊社としては致命的であった。AWSソリューションアーキテクトの方もその点がおすすめできないといった発言をしていた。

また、Aurora Serverless は比較的新しいので本番運用における知見がインターネットにあまり見られないのも憂慮すべき事項だった。問題が生じた時の対応の遅れはスタートアップの命取りとなるし、ビジネスの本質的でない部分に時間を取られたくないという思いもある。

バックエンド

Backend

ALB + Fargate を採用。Multi AZでオートスケールを設定しておけば可用性に問題はない。コンテナインサイトをONにしておけばCPUやメモリなどの基本情報は簡単にモニタリングできる。

APIドキュメントを社内向け、外部向けに公開するので、ALBにはACMで発行したSSL証明書を紐付けてHTTPS通信にしている。

この図には載せていないが、 CloudWatch Alarm + AWS Chatbot + SNS で5XXエラーをSlackに通知するようにしているので、アプリ上で問題が発生した場合はすぐに気づける。

またローカルでDockerを用いて開発することで、ステージング・本番に適用して初めて分かるバグが殆ど発生せず、スムーズに開発・適用までを行える。

上記に書いたようなことは実はLambdaでも問題なく実施できる。実際どちらを採用するか悩んだのでその点について詳細を説明する。

Lambda vs. Fargate

コンテナ運用
コンテナ運用のメリットに関しては、今までは完全にFargate一択だったが、2020年にLambdaがコンテナイメージのサポートを行ったので特に差異はなくなった。CI/CDに関してはむしろLambdaの方が楽かもしれない。
参考 AWS Lambda の新機能 – コンテナイメージのサポート

RDSとの相性
Lambda + RDS というのは今まで典型的なアンチパターンだったが、2019年に RDS Proxy というコネクションプールマネージャが誕生し、特に非推奨ではなくなった。懸念点は比較的新しいということで、先人たちによる情報が多いのはやはり ECS(Fargate、EC2)やEC2 + RDS だ。
参考 Using Amazon RDS Proxy with AWS Lambda

コスト(リソース・運用)
リソースコストはLambdaの方が大体のケースで安い。運用コストに関しては、アーキテクチャによるのでなんとも言えないが基本的にはLambdaの方が大変だと思っている。

Lambdaの利点を活かすなら、処理に応じてメモリや実行時間などを分けるかもしれない。その場合、各Lambda用にDockerfileやIaCを定義したり、ビルドなどもLambdaごとに行う必要があり、並行に適用するための非同期なスクリプトの準備などFargateと比べてやることが多くなる。

もしFargateなどの運用と同様に1つのLambdaをアプリケーションサーバーのように扱うなら、次に扱う制約との闘いになる。

制約
Lambdaは同時実行数、タイムアウト、リクエスト・レスポンスサイズなど制限が多い。
参考 Lambda のクォータ

理想的なアプリケーション設計ができていれば特に問題のない制限ではあるが、インフラの美しさより PMF(Product Market Fit) を急ぎたいスタートアップには痛いことがしばしばある。

「機能のリリースをとりあえず行って、実際に体験してもらい、需要がありそうなら本格的に実装する」といったことを高速に回す必要があり、「これは処理が重たいからバッチとして切り出して、エラー時にはこんなふうにリトライさせて・・」といった暇がない。

本来なら非同期にすべき処理も、最初は同期的に実装してしまって顧客の反応を見ることが望ましいので、制約に縛られないことはかなり重要だった。うちの会社の場合は、データ通信が制限を超える可能性が十分にあったのもFargateを選んだ強い理由の1つになる。

結論
Fargateを採用したのは「制約」がポイントだった。もちろんLambdaを使わないわけではなく、需要のある機能で、バッチ処理など非同期な処理はLambdaにも任せていく。実際画像の加工周りの処理はLambda化されている。

因みにLambda開発やCI/CDについては下記の記事で考察したので是非参考にして欲しい。
私が考えるLambda開発環境のベストプラクティス
私が考えるLambda周りのIaC及びCI/CDのベタープラクティス

2021/5/1追記
事業が進んだ際に本格的なバッチ処理を導入する上で、どのようなサービスを選択すべきかを考察したのでこちらも載せておく。
AWSでバッチ処理を実装する際の選択肢とサービス比較

最後に

上記のアーキテクチャは以下の要件を満たしたのではないかと思う。一点、リソースコストについては低コストとは言えないかもしれないが、大抵は人件費のかかる運用コストの方が高くなりがちなので、そこは目をつぶった。

  • シンプルな構成・構築の容易さ
  • スピーディな開発・適用
  • 可用性の担保
  • セキュリティの担保
  • 最低限のモニタリング
  • 低コスト(リソース・運用)

「もっとこうしたらいいんじゃないか?」といった意見があったら是非教えて欲しいし議論したい。この辺は次々と新しい技術が誕生しているので皆でよりより方法を模索できればと考えている。

よかったらTwitterフォローしてね。

Discussion