2024/02/29

Cloud Runのインスタンス起動時間

 動機

Cloud Runのドキュメント「実行環境について」については以下の記述があります。
第 2 世代の実行環境は、一般に持続的な負荷の下では迅速に動作しますが、ほとんどのサービスでは、第 1 世代よりもコールド スタート時間が長くなります。
このように書かれると、第1世代/第2世代ともどの程度インスタンスの起動時間がかかるのか、どの程度違うのか気になります。また第2世代のジョブはバックグラウンドで動作するものなので起動時間はあまり気にされるものではありませんが、これも知りたくなってきます。
実行速度は目的によって測定方法も変えることになるので面倒ですが、インスタンスの起動時間については過去の記事「GAEのインスタンス起動時間」「GAEのインスタンス起動時間 #2」と同様に測定できますので測ってみました。


測定方法・条件

今回はCloud Runなので言語やランタイムのバージョンについては、使う人がDockerコンテナを作る際にいいようにすればいいだけの話です。なので純粋にCloud Runのインスタンス起動時間として、Hello World相当のGoでリクエスト→処理開始までを測ることにします。
  • リージョン : 大阪
  • ネットワーク : NTT Flets光 隼、実効300Mbps程度
  • サービス : 
    • ブラウザからAjaxでリクエストし、JavaScriptでレスポンスが返るまでの時間を測定。
    • スピンアップあり/なしの2パターンで、それぞれ10回測定し、平均値を算出。
    • 前記2パターンの差から、インスタンス起動時間を計算。
  • ジョブ : 
    • GAEからジョブを起動し、GAE/Cloud Runそれぞれに仕込んだログから、インスタンス起動時間を測定。
    • スピンアップは毎回行われるのでサービスのような「スピンアップなし」に該当するパターンは無いはず。念のため検証目的で、前回起動から15分以上時間空けてをスピンアップあり相当、前回起動から時間空けずにをスピンアップなし相当として、2パターンでそれぞれ10回測定し、平均値を算出。

測定結果

単位はすべてmsです。測定結果をtableにするのが面倒だったので、今回もExcelのキャプチャ画像です。

スピンアップあり。

スピンアップなし。

そしてインスタンス起動時間。

第1世代第2世代
serviceservicejob
158.7452.59344.4


まとめ


Cloud Runの世代間

公式ドキュメントの記載どおり、インスタンス起動時間は第1世代のほうが速いという結果です。
ジョブの起動時間はおおむね10秒程度でした。ちなみにジョブ終了→GAEで終了を検知も、おおむね10秒程度でした。

GAEとの比較

GAEのインスタンス起動時間 #2」と比較してみるとCloud Runは全体的に遅く、第2世代のサービスだとGAEの素のJavaよりいいくらいになっています。
本稿の趣旨からちょっと外れますが、スピンアップなしのケースではGoだろうがJavaだろうがほぼ確実に100msを切れるGAEに対して、Cloud Runだと3倍程度のレイテンシが発生しています。Webフロントエンド専用のプロダクトとしてgVisorという独自コンテナ技術まで作っただけあって面目躍如といったところで、汎用のDockerコンテナを利用するCloud Runは一歩及びません。

GoのコードはそのままでGAE/Goに実装したRESTful APIを、Cloud Runサービス/Goに変えたところ、ちょっともっさりするようになった気がした経験があります。これは気のせいではなかったと改めて認識しました。
Firebase Hostingには動的コンテンツをCloud Runで配信する機能「Cloud Run を使用した動的コンテンツの配信とマイクロサービスのホスティング」があるのですが、今回の結果を見ると、App Engineにも対応してほしいと思います。

2024/02/09

GAEのインスタンス起動時間 #2

動機

Java17 + レガシーバンドルサービスを実装したところ、GAEインスタンスのスピンアップが若干遅いと感じました。いつの間にかJava21もプレビューになっていましたので、あわせてインスタンス起動時間を再測定してみました。

また前回(GAEのインスタンス起動時間)はログで確認していたのですが、その方法の精度にも疑問を感じたので、測定方法も対象も変更しています。


今回はJava8がすでにサポート終了しているので、対象外としました。


測定条件・方法

  • リージョン : 大阪
  • ネットワーク : NTT Flets光 隼、実効300Mbps程度
  • インスタンスクラスはF1。
  • ServletのアプリはGoogleのサンプルに入っていたHelloWorld。
  • SpringBootのアプリはGoogleのサンプルに入っていたHelloWorldそのままなので、バージョンは2.7.18。
  • レガシーバンドルサービスは、Googleのサンプルは余計なコードが入っていたのでpom.xmlのみ参考にし、Hello World相当を自作。
  • GoもHello World相当を自作、今回はフレームワークなしのパターンのみ。
  • ブラウザからAjaxでリクエストし、JavaScriptでレスポンスが返るまでの時間を測定。
  • スピンアップあり/なしの2パターンで、それぞれ10回測定し、平均値を算出。
  • 前記2パターンの差から、スピンアップ+VM起動+フレームワーク起動の時間を計算。

測定結果

単位はすべてmsです。測定結果をtableにすると横長になってレイアウトが崩れたので、画像です。
まずはスピンアップあり。

続いてスピンアップなし。

そして、スピンアップ+VM起動+フレームワーク起動の時間。
Servletspringレガシー
Java11625.24728.62098.6
Java17599.84769.21655.0
Java21630.24622.92451.5
Go1.20176.9--


所感

起動時間は 17<11≒21。わずかとはいえ、最新の21で悪化しているという意外な結果に。まだプレビューなのも影響しているのでしょうか。

SpringBoot

前回と比べてバージョンが2.6.6→2.7.18と変化していますが、結果はほぼ同じ。他はJava21で遅いのに、なぜかspringだけはJava21が最速と、一致しません。なぜ...

レガシーバンドルサービス

遅い気がしたのは気のせいではありませんでした。Java8のスピンアップが遅かったのはもしかして、Googleのカスタマイズのせいだったのではという疑惑が生じます。そしてJava21での遅延が目立って大きくなっています。残念過ぎる...