1. はじめに
AWS上でECS(Springアプリケーション)とRDSを使用したシステムを運用しており、ECS, RDSともに毎日決まった時刻に停止、起動させていました。
ECS上のSpringアプリケーションは、起動時にDB接続を前提とした処理が組み込まれていたのですが、この定時起動によるSpringアプリケーションの起動時にデータベース接続に失敗し、必要な起動処理ができていないままアプリケーションが立ち上がってしまうことが稀に起こっていたことが発覚しました。
2. 発生した問題
ECS上でSpringアプリケーションがRDSに接続できず、アプリケーション起動処理にてエラーが発生。
ECSとRDSは同時刻に起動するようにしていましたが、RDSの起動の方が遅くなった場合に、DBに接続できず、必要な処理ができていない状態でSpringアプリケーションが起動してしまっていました。
ECS, RDSの運用担当者は、Springアプリケーションの実装自体には関わっていないため、起動順序によっては正常な稼働ができない、ということを把握できていなかった。
Springの起動処理の設計ミス
DB接続を前提とした初期化処理が含まれており、起動タイミングが少しずれただけで正常な稼働ができないリスクを抱えてしまっていた。
また、DBが立ち上がった状態であっても、なんらかの原因で接続に失敗した場合は同様の事象が発生してしまう設計になっていました。
起動処理にてDB接続に失敗した場合の考慮不足
起動処理にてDB接続に失敗し、必要な処理ができていない状態でもアプリケーションの起動自体は成功してしまっており、ログも出していなかったため、特定のリクエストの処理でたまにエラーが出るが、再起動したら解消し、再現条件も根本原因も不明、という状況になってしまいました。
3. 対応
基本的にはこれが一番かと思います。今回の問題以外でも、さまざまな問題の原因となるリスクがあるため、できるだけ避けるのがベストかと思います。
リトライロジック
DB接続が確立できるまで、一定時間ごとにリトライする仕組みを設ける。
イベント駆動の処理
DBが準備できたことをイベントで受け取り、そのタイミングでDB依存の処理を開始する。
DB接続に失敗した場合の考慮
DB接続に失敗した場合でも正常な稼働ができる仕組みにする or 起動自体失敗するようにする。失敗が起きたことを確実に検知できる仕組みを作る。など
4. まとめ
失敗の教訓
DB接続に依存した起動時処理は、サービス全体の安定性に悪影響を与えるリスクがあります。特に、インフラの起動順序に左右される場合は危険。
DB接続に依存しないようにすることで、より柔軟で信頼性の高いアプリケーション起動が可能となり、将来的なトラブルを回避できます。
どうしても設計上難しい場合は、DB接続に失敗した場合の考慮をしっかり行うべき