はじめに
こんにちは、エモーションテック SREのおかざきです。 今回は弊社プロダクトで利用しているGoogle CloudのCloud Runについて、実際に動かしてみた中で生じた疑問点を検証してみました。
疑問点
リクエストタイムアウトを超えた処理はどうなるのか
Cloud Runのドキュメントには以下のように記述されています。
Setting request timeout (services) | Cloud Run Documentation | Google Cloud
If a response isn't returned within the time specified, the request ends and an error 504 is returned. Note that the container instance that served the request is not terminated.
timeoutを超えた時点でクライアントには504レスポンスが返却されるようですが、コンテナインスタンスは停止されないようです。 では、コンテナインスタンスで行われていた処理はどうなるのでしょうか。
簡単ですが以下の構成で検証してみました。
- Cloud Run
- Node.js + Expressによる簡単なWebサーバを作り、リクエストを受信すると任意の時間sleepしてレスポンスを返す
- Sidecarとしてシェルスクリプトを実行し、1秒ごとに標準出力に「起動中のリビジョン名と起動からの経過秒数」を出力させる
- SidecarにてSIGTERMをトラップし、標準出力でSIGTERMを受信した旨を出力させる(こちらのドキュメントよりSidecar含むコンテナインスタンス終了時にはSIGTERMが送信される)
設定項目 | 設定値 |
---|---|
Cloud Run世代 | 第一世代 |
リージョン | asia-northeast1 |
Cloud Run timeout (timeoutSeconds) | 30sec |
maxScale | 1 |
minScale | パターンによって変化させる |
Webサーバーがレスポンス返却するまでのsleep時間 | 60sec |
Always on CPU | 有効化 (有効/無効でtimeout時の挙動に変化は見られなかった) |
minScale = 0、minScale = 1の場合の2パターン検証しました。
minScale = 0の場合
クライアントから接続後に30sec後に504が返却されましたが、その後もコンテナインスタンスのログは出力され続け、1分後にExpressよりレスポンスを処理した旨のログが出力されました。 冒頭で参照したドキュメントの通り、504返却後もコンテナインスタンスは停止されないようです。 そして、レスポンス返却後の15分後にSIGTERMが発生し、コンテナインスタンスが停止されました。
15分後というのは以下のドキュメントの記述に対応しているようです。
CPU allocation (services) | Cloud Run Documentation | Google Cloud
An instance will never stay idle for more than 15 minutes after processing a request
minScale = 1の場合
クライアントから接続後に30sec後に504が返却されましたが、その後もコンテナインスタンスのログは出力され続け、1分後にExpressよりレスポンスを処理した旨のログが出力されました。 その後コンテナは長時間起動したままとなりました。 今回試したところ、SIGTERMが検知されたのは起動から13000〜14000 sec経過後でした。
minScaleの数を満たすためのコンテナインスタンスについてはレスポンス返却後もしばらく起動したままになるようです。 ただ、timeout時間を超えて同じコンテナインスタンスが起動して処理が走り続ける時間については、以下のドキュメントにあるように保証されていないものと推測されます。 Container runtime contract | Cloud Run Documentation | Google Cloud
For Cloud Run services, an idle instance can be shut down at any time, including instances kept warm via a minimum number of instances.
なお、Cloud Runのtimeoutの上限(2024/1時点では3600sec)を超えて長時間の処理を行いたい場合は2023/9にCloud Run Jobsの長時間処理がGAになっているので、そちらを利用するのが良さそうです。 また、Cloud Runではtimeout経過後も条件によってはSidecarやバックグランドの処理が継続されますが、Cloud Run Jobsではtimeoutに到達した時点でジョブが失敗と判定され、コンテナインスタンスが停止されるようです。指定したtimeoutで確実に処理を止めたい場合もCloud Run Jobsを選択するのが良さそうです。
デプロイ時に旧リビジョンで稼働していた処理はどうなるのか
以下の条件で検証してみました。
設定項目 | 設定値 |
---|---|
Cloud Run世代 | 第一世代 |
リージョン | asia-northeast1 |
Cloud Run timeout (timeoutSeconds) | パターンによって変化させる |
maxScale | 1 |
minScale | 1 |
Webサーバーがレスポンス返却するまでのsleep時間 | パターンによって変化させる |
Always on CPU | 有効 (有効/無効でtimeout時の挙動に変化は見られなかった) |
デプロイ時のトラフィック切替割合 | 即時100%にする。 |
いくつかパラメータを変更して試した結果は以下の通りでした。
パターン | Cloud Run timeout | sleep時間 | 結果 |
---|---|---|---|
パターン1 | 1200sec | 600sec | デプロイ前のリビジョンのExpressにてレスポンス処理完了のログが出力された レスポンス返却直後にすぐに古いリビジョンのコンテナインスタンスに対してSIGTERMが送られた |
パターン2 | 3600sec | 3599sec | デプロイ前のリビジョンのExpressにてレスポンス処理完了のログが出力された レスポンス返却直後にすぐに古いリビジョンのコンテナインスタンスに対してSIGTERMが送られた |
パターン3 | 3600sec | 10800sec | 3600sec後に504が返却された 同時に古いリビジョンのコンテナインスタンスにSIGTERMが送られた |
パターン4 | 30sec | 60sec | 30sec後に504が返される。この時点ではSIGTERMが発生せず、60sec経過後にデプロイ前のリビジョンのExpressにてレスポンス処理完了のログが出力された 504発生から約1分半後にコンテナインスタンスにSIGTERMが送られた |
timeout に収まる範囲内では古いリビジョンで処理が継続され、レスポンス処理が終わったタイミングで古いリビジョンのコンテナインスタンスは停止されました。 timeoutを超えるような処理の場合は、レスポンス処理が継続中であっても古いリビジョンのコンテナインスタンスは停止されました。
基本的にはtimeoutに収まる範囲であれば、デプロイによってリクエスト処理中のコンテナインスタンスが急に停止されることはなく、ユーザーには配慮されているようです。
おわりに
いかがでしたでしょうか。記事に示した製品の挙動は、ドキュメントを読むことである程度把握できると思います。しかし、実際にいくつかのケースを想定し、他製品と比べながら動作検証を行うことで、知識として定着することもあるかと思います。
個人的にはCloud RunのベースはKnativeとのことなので、(Cloud Runが全くKnativeと同一であるとは言えないですが) 今回調べた挙動についてより追求するならば、Knativeにも興味が湧いてきました。
日々の開発、運用に追われつつもこのような検証は少しずつ行なっていきたいと思います。
エモーションテックでは顧客体験・従業員体験の改善をサポートし世の中の体験を変えるプロダクトを開発しております。もし弊社に興味を持って頂けましたら、ぜひ採用ページからご応募をお願いいたします。