読者です 読者をやめる 読者になる 読者になる

koni blog

東京のウェブエンジニア koni です!ウェブサービスをガシガシ作っていきます!

Google App Engineを無料で運用する方法(2016年版)

Google App Engine PHP

こんにちは、小西です。

これまで紹介してきたGoogle App Engine(GAE)ですが、無料枠が大きいとはいえ、ちょっと重い処理があるときにリクエストが立て続けに来ると、すぐに2台以上インスタンス起動してしまいます。

インスタンス時間の無料枠は28時間なので、この範囲内で抑えることが重要です。

先月、月間50万PVほどあるサイトをGAEに移行し、1ヶ月ほど無料で運用することができたので、その際にやったことをお伝えします。

PHPで試したものですが、基本的にはPython, Go, Javaの場合も同じはずです。*1

GAEってなんじゃ?という方はまずはこちらをどうぞ:

さくっとPHPでサイト作るならGoogle App Engineが最高 - koni blog

Node.jsの方は無料で使えないみたいです。詳しくは一番下。

何に課金されるのか

完全無料で運用するために、まずは何に課金されるのか確認しましょう。

f:id:konisimple:20161115094127p:plain

(App Engine - Platform as a Service  |  Google Cloud Platformより。2016/11/15 東京リージョン開設にあわせて画像を更新しました。米国・ヨーロッパのリージョンと比べると、3割ほど高いですね)

必ずかかる料金としては、一番上の「インスタンス時間」と、転送量である「ネットワークトラフィック(送信)」です。受信は無料なので、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)

という挙動になります。

実際のインスタンス数の増減を見てみましょう。

f:id:konisimple:20160106124936p:plain

1と2で大体推移していますね。28インスタンス時間以内にするために、基本は1台起動、増えた時だけ2台にする、という挙動になっていますね。

施策③ static serverを活用する

js, cssや画像など、静的なコンテンツは、static serverから配信するようにすると、インスタンス時間を一切消費せず、転送量のみで済みます。

この設定は、app.yamlに以下のように書きます。

handlers:

# 画像が入っているディレクトリ/img をまるごとstatic serverから配信する場合
- url: /img
  static_dir: img

# 1ファイルだけstatic serverから配信する場合
- url: /img/example.png
  static_files: img/example.png
  upload: img/example.png

施策④ エッジキャッシュを活用する

GAEは、エッジキャッシュに対応しています。エッジキャッシュはものすごく強力です。

cssやjs、画像などの静的リソースは、デプロイ直後からstatic serverから配信されるので、そのそもインスタンス時間を全く消費しません。 HTMLの配信は、基本的にインスタンス時間を消費します。 返却するHTMLの内容が、全ユーザーに対して全く同じで良い場合は、HTMLの配信もエッジキャッシュを活用しましょう。

利用方法は簡単です。キャッシュして欲しいページのHTTPレスポンスヘッダに以下を追記するだけです。 PHPでは以下のコードで実現できます。

header("cache-control: public, max-age=3600");

3600のところは何でも構いません。

このヘッダを返し、数回叩くと、以降はキャッシュが使われます。 ちなみにGAEを西海岸リージョンで使うと数百msがラウンドトリップでかかってしまいますが、エッジキャッシュに乗ったコンテンツは50msくらいで帰ってきます。これは台湾から返っているものと思われます。*3

2016年11月、東京リージョンでも利用できるようになったので、エッジキャッシュ使わなくてもラウンドトリップは数十ms台になりました! ただ、無料運用という点では、インスタンスを動かさないことがキモなので、この方法は引き続き重要です。

キャッシュに載っているか確認する

GAEに乗っているこのサイトをChromeのインスペクタで見た様子です。50ms程度でレスポンスが来ていて、レスポンスヘッダにAgeというフィールドが追加されているのがわかります。これがキャッシュ取得からの秒数です。

f:id:konisimple:20160106125843p:plain:w400

施策⑤ キャッシュできるコンテンツをmemcacheにのせる

これは一般的な方法なので割愛します。

予算設定

上記の方法で、無料での運用ができるようになりました。

一応不安なら、「予算」を設定したり、一定の金額に達したらアラートを飛ばすこともできます。

f:id:konisimple:20160106130206p:plain:w200

その他の方法

実は、GAEのインスタンス数の制御方法は以下の3種類あります。

  • Basic Scaling
  • Manual Scaling
  • Automatic Scaling

通常サイトを運用する場合は、アクセス数に応じてインスタンス数を柔軟に変えたいと思うので、この記事ではAutomatic Scaling を選択しました。もしも、絶対に1インスタンスだけで運用したい、みたいな場合は、

  • Manual Scalingにして、instances を固定値にする
  • Basic Scalingにして、max_instancesを固定値にする

という対応も可能ですが、これだとアクセス増に対して対応できない場合があるので、通常のサイトではあまり使うことはないと思います。

詳細はこちら:

An Overview of App Engine  |  App Engine standard environment for PHP  |  Google Cloud Platform

また、JavaやPythonの場合は、1インスタンスが同時に処理できるリクエスト数を設定するmax_concurrent_requestsという設定があり、これを上げる、という方法も取れそうです。 ちなみにこれはPHP版は対応していません。*4詳細は以下をご覧ください。

An Overview of App Engine  |  App Engine standard environment for Java  |  Google Cloud Platform

まとめ

あとはもう完全に放置プレーでOKです。素敵ですね。

GAE関連の他の記事

SSL証明書も完全無料で運用しましょう!: koni.hateblo.jp

PHPでさくっと作る場合のGAEの特徴をまとめました: koni.hateblo.jp

PHPで、5分で動かすところまで行くハンズオンな記事です: koni.hateblo.jp

参考サイト

追記(2015/1/6 15:40)

Google App Engineを無料で運用する方法(2016年版) - koni blog

参考になりました。ちなみにこれは何らかのPHPフレームワークを使用していますか?

2016/01/06 14:52
b.hatena.ne.jp

PHPのCodeIgniterというフレームワークを使っています。 フレームワークも問題なく動いています。

Flexible Environmentについて (2016/10/3追記)

この記事は「App Engine Standard Environment」のものです。

裏でVMが立ち上がってSSHログインができたりする、「App Engine Flexible Environment」(旧Managed VMs=MVMs)ではまた別の対応が必要そうです。

Node.jsの場合、Standard Environmentはなく、Flexible Environmentのみしかないとのこと。 なので、無料枠は使えません。

逆にPHPはFlexible Environmentにはデフォルトではそもそも対応していません。Custom Runtimeで実行することは可能そう。まあそこまでやるならGCEかな。

Google App Engine を安く Node.js で使う - Qiita

*1:Javaの場合は、クラスロードが毎回走るのが遅い云々という話も対応が必要かも。。

*2:「Daily quotas are replenished daily at midnight Pacific time」https://cloud.google.com/appengine/docs/quotas?hl=ja

*3:2015/1/7 9:00 頂いたコメントから修正しました

*4:「automatic_scaling.max_concurrent_requests not available for php55 runtime.」というエラーが出ます。