最終更新日:2018/3/6
こんにちは、小西です。
これまで紹介してきたGoogle App Engine(GAE)ですが、無料枠が大きいとはいえ、ちょっと重い処理があるときにリクエストが立て続けに来ると、すぐに2台以上インスタンス起動してしまいます。
インスタンス時間の無料枠は28時間なので、この範囲内で抑えることが重要です。
先月、月間50万PVほどあるサイトをGAEに移行し、1ヶ月ほど無料で運用することができたので、その際にやったことをお伝えします。
PHPで試したものですが、基本的にはPython, Go, Javaの場合も同じはずです。*1
GAEってなんじゃ?という方はまずはこちらをどうぞ:
さくっとPHPでサイト作るならGoogle App Engineが最高 - koni blog
Node.jsの方は無料で使えないみたいです。詳しくは一番下。
何に課金されるのか
完全無料で運用するために、まずは公式サイトのAlways Free のページ とGoogle App Engine の料金ページ で何に課金されるのか確認しましょう。
ずっと無料で使えるもの
上記2つをまとめると以下になります。
- インスタンス時間 28時間/日
- ネットワークトラフィック(送信=GAE→ユーザー) 1GB/月
- ネットワークトラフィック(受信=ユーザー→GAE) 無料
- 5GBのクラウドストレージ (GCSのことです)
- 共有Memcache (GAEからのみ使えるキャッシュサーバ)
- の検索オペレーション 1000回/日
- 検索インデックス作成 10 MB
- メール 100件/日
- DataStore データ保存:1GB/日 読み取り 50000件/日 書き込み 20000件/日
この範囲内で運用することで、無料運用が可能となります。 ここに入っていないものはいきなり課金対象になるので、無料で運用したい場合は諦めます。
必ずかかる料金としては、一番上の「インスタンス時間」と、転送量である「ネットワークトラフィック(送信、受信)」です。
受信は無料なので、GAE→インターネット方向のみ課金されます。このあたりは他のGCPのプロダクトやAWSと同じですね。
それ以外は使った分だけ課金されます。他の部分を無料で運用するのは、無料枠以上使わなければいいので、一般的な方法と同じです。 memcachedであれば必要な分だけキャッシュするとか、必要なログだけ送るとかになります。
今回は、インスタンス時間に焦点を当てます。
なおGAEでは2011年に料金体系が大幅に変更されました。かつてはPVベースで料金が決まっていたりしましたが、そのルールは廃止になりました。GAE関連で検索すると2010年ころの記事が多くヒットするのでご注意ください。この記事はわかりやすいよう2016年と書いておきましたw
インスタンス時間
「インスタンス時間」は、インスタンスの稼働台数×時間を分単位で累積したものです。 1日おきに計算され、毎日リセットされます。なので、1日だけ無料枠を超えても課金対象になります。 ちなみにGAEの1日は、おなじみのPSTなので、JST-17になります。つまり日本時間17時頃リセットされます。*2
インスタンスクラスについて(2017/11/30追記)
「インスタンス時間」は以前は1種類(F1
)のみでしたが、2016 年あたりから拡張され、他のインスタンスクラスも選ぶことができるようになりました。
F1
だとメモリ128MB、CPU600MHz となっています。
F2はF1の2倍のスペックでだいたい料金も2倍となりますが、料金計算では、F2を1時間利用するとF1を2時間利用したとして計算されます。つまりF2だと28/2=14時間しか無料になりませんのでご注意ください。
無料運用するためにやること
施策① 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台にする、という挙動になっていますね。
施策③ 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
というフィールドが追加されているのがわかります。これがキャッシュ取得からの秒数です。
施策⑤ キャッシュできるコンテンツをmemcacheにのせる
これは一般的な方法なので割愛します。
予算設定
上記の方法で、無料での運用ができるようになりました。
一応不安なら、「予算」を設定したり、一定の金額に達したらアラートを飛ばすこともできます。
その他の方法
実は、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
また、JavaやPythonの場合は、1インスタンスが同時に処理できるリクエスト数を設定するmax_concurrent_requests
という設定があり、これを上げる、という方法も取れそうです。
ちなみにこれはPHP版は対応していません。*4詳細は以下をご覧ください。
An Overview of App Engine | App Engine standard environment for Java | Google Cloud
まとめ
あとはもう完全に放置プレーでOKです。素敵ですね。
GAE関連の他の記事
SSL証明書も完全無料で運用しましょう!: koni.hateblo.jp
PHPでさくっと作る場合のGAEの特徴をまとめました: koni.hateblo.jp
PHPで、5分で動かすところまで行くハンズオンな記事です: koni.hateblo.jp
参考サイト
追記(2015/1/6 15:40)
Google App Engineを無料で運用する方法(2017年版) - koni blogb.hatena.ne.jp参考になりました。ちなみにこれは何らかのPHPフレームワークを使用していますか?
2016/01/06 14:52
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
東京リージョン開設について (2016/11/15 追記)
東京リージョンが開設し、GAEも使えるようになりました。 米国・ヨーロッパのリージョンと比べると、3割ほど高いですね
更新履歴
2017/1/30(インスタンスクラスについて追記)
*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.」というエラーが出ます。