📘

API課金を気にしない!EventBridge×Lambda×DynamoDBで実現する低コストなデータ取得

に公開

今回は以前に投降した記事の技術的な部分にフォーカスした内容となっています。
サービスの概要などはこちらをご参照ください。
https://zenn.dev/kimkim0743/articles/f90c2abe135906

改めて今回私が採用した構成は以下です。

まずこの開発におけるコンセプトは「できるだけお金をかけずに開発、運用できること」です!
したがってパフォーマンス <<< コストという軸でいろいろと取捨選択しました。

こだわりポイント

ウェブアプリのホスティング

ウェブアプリのホスティングをAWS上で行うにあたり、最初に検討したのが「EC2で構築するか」「Amplifyを使うか」という選択でした。

EC2は仮想サーバーとしての自由度が高く、OSやミドルウェアの構成、セキュリティ設定などを細かく制御できます。DockerやCI/CDの仕組みを自前で組みたい場合には非常に柔軟です。ただしその分、インスタンスの立ち上げからセキュリティグループの設定、SSL証明書の導入、スケーリングの設計など、インフラ周りの作業が多くなります。

一方でAmplifyは、静的ホスティングやSPA(Single Page Application)との相性が非常によく、GitHubなどのリポジトリと連携するだけで自動デプロイが可能。CloudFrontによるCDN配信やSSLの自動設定も含まれており、インフラ構築にかかる時間を大幅に削減できます。バックエンド連携も、必要に応じてLambdaなどと組み合わせることで、十分な拡張性を持たせることができます。

料金面でも、Amplifyは無料枠が充実していて、開発初期の段階ではほぼコストゼロで運用可能。EC2は常時稼働させる場合、インスタンスタイプやリージョンによってはコストが積み上がりやすく、スケーリングや停止のタイミングも自分で管理する必要があります。

今回のプロジェクトでは、スピード感と開発効率を重視していたため、インフラ構築に時間を割くよりも、アプリケーションのロジックやUI/UXに集中したいという思いがありました。 そのため、最終的にはAmplifyを選択しました。

低コストなデータ取得

アプリ内で「天気」と「為替」の情報を表示する必要があり、それぞれ外部APIを通じて取得する構成にしていました。初期段階では、アプリから直接API Gatewayを経由してLambdaを呼び出し、そこから外部APIをコールする形をとっていました。

ただし、これらの外部APIは従量課金制であるため、アクセス頻度が増えるとコストが無視できなくなります。特に為替情報などは頻繁に参照される可能性があるため、コスト最適化が重要な課題でした。

そこで、夜間にバッチ処理を走らせて、APIの結果をDynamoDBに保存する方式に変更しました。これにより、アプリ側は外部APIを直接呼び出す代わりに、DynamoDBから最新の情報を取得するだけで済むようになり、APIコール数を大幅に削減。

一時はS3への保存も検討しましたが、ストレージとスループットの両面で今回のアプリの特性である
「頻繁に小さなデータを読み取る」では、DynamoDBの方がトータルコストが安くなるという結論に至りました。※人気が出た場合のアクセス数で考慮

(料金比較表 *[1] *[2])

DynamoDBは単価が高く見えますが、最初の25GBは無料なので、少量データの保存には非常に有利です。つまり、頻繁に小さなデータを読み取る用途では、DynamoDBの方がトータルコストが安くなるという結論に至りました。

さらに、DynamoDBへのアクセス数も最小限に抑えるため、アプリ側にはLRU Cacheを実装。天気や為替の情報は基本的に1日単位でしか変化しないため、一度取得したデータはアプリ内でキャッシュしておくことで、同じ日のリクエストに対してはDynamoDBすら呼ばずに済むようになりました。

夜間のバッチ処理には、EventBridgeのScheduler機能を使用。これにより、Lambdaを定期的に実行して外部APIを呼び出し、DynamoDBに最新データを格納する流れを自動化しています。インフラ側の構成もシンプルで、メンテナンス性の高い設計になりました。

API Gatewayのステージ使い分けとアクセス制限

API Gatewayでは、ステージ機能を活用して dev(開発用)と prod(本番用)を分けて運用しています。これにより、環境ごとに設定や挙動を切り替えられるため、開発と本番の使い分けが明確になります。

✅本番ステージ(prod)
本番環境では、セキュリティとコスト管理の観点から、すべてのリクエストに対してAPIキーの提示を必須としています。これにより、無制限なアクセスを防ぎ、誰がどれだけ使っているかを把握できます。
Usage Planによる使用制限 APIキーにはUsage Planを紐づけて、1日あたりのリクエスト数や1秒あたりのスロットル制限を設定しています。これにより、万が一APIエンドポイントが外部に漏れたり、悪意あるアクセス(例:DDoS的な連打)が発生した場合でも、料金が爆発的に発生することを防止できます。

✅開発ステージ(dev)
開発環境では、柔軟性とスピード感を重視しているため、APIキーや使用制限は設けていません。開発者が自由に試せるようにしておくことで、検証やデバッグの効率を高めています。

最後に

初めてAWSのサービスを実際に構築したこと+個人開発を経験しました。
0 → 1を生み出す楽しさと同時に運用レベルまで考えた時に何を第一として取捨選択するか(今回はコスト重視)を少し経験することができたと思っています。
これからも技術力+ビジネス力ともに高めていけるよう頑張っていきたいと思います。
また日時選択の機能については動作確認中に不具合が見つかり根本の対策にはJSのTemporalが必要だということが分かりました。これについてはまた別の記事でまとめたいと思います。

参考
[1] https://aws.amazon.com/jp/s3/pricing/
[2] https://aws.amazon.com/jp/dynamodb/pricing/on-demand/

Discussion