0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人開発の2プロダクトを、RDS 1台に同居させて月$40台で運用している

0
Posted at

個人で作っているSaaSが2つあって、どちらもLambda + Postgresの構成。最初はそれぞれにRDSを立てていたが、1台あたり月$20〜30かかる。売上がまだ立っていない検証段階でこれは重い。なのでRDSを1台に集約して、スキーマで分けることにした。今は db.t3.micro 1台に2プロダクトが同居している。

スキーマで分けて、越境は権限で禁止する

プロダクトごとに別スキーマを切って、接続時に search_path を固定する。アプリのDBユーザーには自分のスキーマしか見えないようにして、間違って隣のプロダクトのテーブルを触れないようにしておく。

-- プロダクトAの接続ユーザー
GRANT USAGE ON SCHEMA app_a TO app_a_user;
ALTER ROLE app_a_user SET search_path = app_a;
-- 他スキーマへの権限は渡さない

テーブル作成やマイグレーションのDDLは、アプリユーザーではなく管理者ユーザーで別に流す。アプリ側にDDL権限を持たせないので、実行時に隣を壊す事故が構造的に起きない。ここは「たぶん大丈夫」で済ませず、権限で閉じておきたかった。

Lambdaからの接続でハマったところ

Lambdaは実行のたびにコンテナが使い回されたり捨てられたりする。SQLAlchemyのプールをそのまま使うと、しばらく放置されたコネクションが向こうで切れていて、次のリクエストで死ぬ。pool_recycle を短め(300秒)にして、古いコネクションを掴まないようにした。

もう一つ、非同期処理で asyncio.run を挟んだあとにHTTPレスポンスを返すと、閉じたイベントループ上の接続でエラーになることがあった。これは接続まわりというより実装の順序の問題で、本番でしか出ず、特定に一番時間を使った。

インスタンスが小さいので、張れる接続数もそう多くない。プールサイズは控えめにして、同時実行の上限側でも絞っている。

コストの内訳

  • db.t3.micro(24時間起動): 約$28/月
  • NATはGatewayを使わず t3.nano の自前NATインスタンス: 約$4/月
  • Secrets Manager / KMS / Route53 など: 合わせて$5前後

2プロダクト合わせて月$40台に収まっている。NAT Gatewayを素直に使うとそれだけで$32/月かかるので、ここを自前にしているのが効いている。RDSを常時起動にしているのはwebhookをいつでも受ける必要があるからで、ここは削れない。

売上が立つまではこの構成で粘って、ダメなら丸ごと落とせば$0近くまで下がる。撤退が安いのは、検証段階だと地味に大事だと思っている。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?