こんにちは、小西です。
これまで紹介してきたGoogle App Engine(GAE)ですが、無料枠が大きいとはいえ、ちょっと重い処理があるときにリクエストが立て続けに来ると、すぐに2台以上インスタンス起動してしまいます。
インスタンス時間の無料枠は28時間なので、この範囲内で抑えることが重要です。
先月、月間50万PVほどあるサイトをGAEに移行し、1ヶ月ほど無料で運用することができたので、その際にやったことをお伝えします。
PHPで試したものですが、基本的にはPython, Go, Javaの場合も同じはずです。*1
何に課金されるのか
完全無料で運用するために、まずは何に課金されるのか確認しましょう。
(App Engine — Google Cloud Platformより)
必ずかかる料金としては、一番上の「インスタンス時間」と、転送量である「ネットワークトラフィック(送信)」です。受信は無料なので、GAE→インターネット方向のみ課金されます。このあたりはGCPやAWSと同じですね。
それ以外は使った分だけ課金されます。他の部分を無料で運用するのは、無料枠以上使わなければいいので、一般的な方法と同じです。 memcachedであれば必要な分だけキャッシュするとか、必要なログだけ送るとかになります。
今回は、インスタンス時間に焦点を当てます。
なおGAEでは2011年に料金体系が大幅に変更されました。かつてはPVベースで料金が決まっていたりしましたが、そのルールは廃止になりました。GAE関連で検索すると2010年ころの記事が多くヒットするのでご注意ください。この記事はわかりやすいよう2016年と書いておきましたw
インスタンス時間
「インスタンス時間」は、インスタンスの稼働台数×時間を分単位で累積したものです。 1日おきに計算され、毎日リセットされます。なので、1日だけ無料枠を超えても課金対象になります。 ちなみにGAEの1日は、おなじみのPSTなので、JST-17になります。つまり日本時間17時頃リセットされます。*2
無料運用するためにやること
施策① threadsafeにする
これは基本中の基本、ということになります。
デフォルトではGAEは、シリアルにアクセスを処理します。つまり、あるリクエストの処理が終わるまで、次が処理できません。 (なんでこんな仕様になっているんだ・・・ why google people!!!)
そこで、app.yaml
に以下を追記します。PHPの場合、並列に処理することは一般的なのでこれによる不具合は起きにくいと思います。
threadsafe: true
施策② AutoScalingの設定の調整
GAEでは、アクセス数に応じてインスタンスが自動調整されるようになっています。
デフォルトだと、これがかなり保守的というか、ホイホイインスタンスが立ち、なかなか死なないようになっています。 これだと28時間を超えてしまうので、
という調整をします。
konisimpleというサイトで実際に使われている設定は以下になります。 それぞれのパラメータの意味もコメントに書いておきます。
automatic_scaling: min_idle_instances: automatic # idle状態にあるインスタンスの最小値 max_idle_instances: 1 # idle状態にあるインスタンスの最大値 min_pending_latency: 3000ms # リクエストを処理するまでに許される待ち時間の最小 max_pending_latency: automatic
この設定だと、
- idleなインスタンスが、1を超えたときは落とす(max_idle_instances)
- pending latencyが3秒を超えたらinstanceを増やす(min_pending_latency)
という挙動になります。
実際のインスタンス数の増減を見てみましょう。
1と2で大体推移していますね。28インスタンス時間以内にするために、基本は1台起動、増えた時だけ2台にする、という挙動になっていますね。
施策③ エッジキャッシュを活用する
GAEは、エッジキャッシュに対応しています。エッジキャッシュはものすごく強力です。
cssやjs、画像などの静的リソースは、デプロイ直後からstatic serverから配信されるので、そのそもインスタンス時間を全く消費しません。 HTMLの配信は、基本的にインスタンス時間を消費します。 返却するHTMLの内容が、全ユーザーに対して全く同じで良い場合は、HTMLの配信もエッジキャッシュを活用しましょう。
利用方法は簡単です。キャッシュして欲しいページのHTTPレスポンスヘッダに以下を追記するだけです。 PHPでは以下のコードで実現できます。
header("cache-control: public, max-age=3600");
3600のところは何でも構いません。
このヘッダを返し、数回叩くと、以降はキャッシュが使われます。 ちなみにGAEを西海岸リージョンで使うと数百msがラウンドトリップでかかってしまいますが、エッジキャッシュに乗ったコンテンツは50msくらいで帰ってきます。これは東京から返っているものと思われます。
キャッシュに載っているか確認する
GAEに乗っているこのサイトをChromeのインスペクタで見た様子です。50ms程度でレスポンスが来ていて、レスポンスヘッダにAge
というフィールドが追加されているのがわかります。これがキャッシュ取得からの秒数です。
施策④ キャッシュできるコンテンツをmemcacheにのせる
これは一般的な方法なので割愛します。
予算設定
上記の方法で、無料での運用ができるようになりました。
一応不安なら、「予算」を設定したり、一定の金額に達したらアラートを飛ばすこともできます。
まとめ
あとはもう完全に放置プレーでOKです。素敵ですね。
参考サイト
*1:Javaの場合は、クラスロードが毎回走るのが遅い云々という話も対応が必要かも。。
*2:「Daily quotas are replenished daily at midnight Pacific time」https://cloud.google.com/appengine/docs/quotas?hl=ja