AuroraServerlessを使う機会があったのでその過程で学んだことをメモ。
AuroraServerlessの良さ
- サーバレス
- AutoScaling
- コスト削減
- Lambdaとの相性
まずサーバレスが助かる。
通常のEC2にDBを構築したりRDSを使ったりする場合、定期的にサーバの証明書更新が必要となる。後々の運用を考えると出来るだけ手離れはよくしたいし、メンテナンスの都度サービスを止めるということもしたくない。
次にAutoScaling
AuroraServerlessではDBの処理とストレージが分離されている。急激にアクセスが増加し処理が多くなった場合には勝手にスケーリングしてくれる。
そしてピークがすぎるとスケールインして最後は処理部分を完全に畳むことができる。(0にするかは設定次第で調整可能)
3つ目、コスト削減。
AutoScalingにより処理部分はリクエストが来ない間は完全に眠らせることが可能だ。つまりこの間にかかるコストはストレージ分のみ。
DBのアクセスが予め見積れる場合には通常のDBを使ったケースと比較すると安く利用できるメリットを受けることができる。
最後にLamdbaとの相性。最近はRDSプロキシなどが使えるようになり大丈夫なのかもしれないが、コネクションプーリング等の問題でRDSとLambdaは相性が悪いと言われていた。
API Gatewayからの初回アクセスには注意が必要
DataAPIを介してSQL文を送り込む方法をとるとなると、API GAteway → Lambda → AuroraServerless構成が簡単にできる。→以前の記事
ただしここには注意が必要。API Gatewayは最大でも29秒しか待てないのだ。
上記の通り、AuroraServerlessはリクエストに応じてスケーリングし、誰もリクエストしない時には完全に眠っていることになる。
この状態でアクセス(初回アクセス)するとサーバを起動するところから始めるのでまあまあ時間がかかる。10秒とかもう少しくらいはかかっているんじゃなかろうか。
APIを介して複数のデータ書き込みや時間のかかる処理を行おうとする場合、初回アクセス時にはタイムアウトするリスクが伴う。
また厄介なのはAPIは29秒で504を返のに、DBからレスポンスが来ると内部の処理はそのまま続行するクライアント側はもう一回実行しようとする。冪等性のない処理だったりすると危険。
マイクロサービス化と疎結合の重要性に気づく
簡単な解決策としてはAuroraServerlessをどんなにアクセスがなくても最小のスケールで稼働させて寝かさないようにすること。
でもサーバレスの良さが損なわれてしまう。24時間付けっ放しなら普通のDBの方が安いじゃんってなる。
API GatewayとAuroraServerlessは合わせられないのか・・?
違う。今回の問題は内部の処理は続行しているのにAPI Gatewayがタイムアウトしてしまうからクライアント側の認識とバックエンドの処理にズレが生じることが問題。
なので、一度リクエストという形で受け取ったらその時点でAPIに返事をすることで解決される。(もちろん仕様や要件にもよると思う)
たどり着いた答えとしてはAPI Gateway → Lambda → SQS → Lambda → AuroraServerless
APIではリクエストを受けた時点でキューに積み202 Acceptedを返そう。SQSではエンキューをトリガーにしてこれまでのLambdaを呼んであげる。
こうすることで29秒が限度だった一連の処理をLambdaの上限値15minまで伸ばすことができる。
SQSで一旦受け止めるのはAPI GatewayとStepFunctionsを繋ぐ時にも有用なのではなかろうか?
SQSにDLQは必須
SQSを使うからにはDLQの設定を確実にした方がいい。
なぜか?SQSでは処理中のメッセージは見ることができない(処理中のメッセージとなる)。
仮にSQSのLambdaトリガーで呼ばれたLambdaの内部で処理にコケた場合、通知等をして問題がわかってもそのメッセージをピンポイントにキューから取り出すのが困難になる。(再処理ポリシーを指定しないとSQS→Lambdaを無限に繰り返しうる。)
また、Lambdaトリガーで呼ばれるLambdaがタイムアウトした場合も同じで可視性タイムアウトを抜けると即座にリトライがかかるためそのメッセージを取り出してあげることができなくなる。
DataAPIの返り値の整形
DataAPIの返り値は少し使いにくいので整形した方がいい。→以前の記事
アーキテクチャ
この辺りがベストプラクティスになるのかな。