【18-c-4】google app engine - 無限の彼方へ
TRANSCRIPT
![Page 1: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/1.jpg)
Takashi MatsuoGoogle, Inc.Feb 18, 2011
![Page 2: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/2.jpg)
App Engineto infinity and beyond
Takashi MatsuoGoogle, Inc.Feb 18, 2011
![Page 3: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/3.jpg)
自己紹介
松尾貴史 @tmatsuo
App Engine Developer AdvocateKay's Daddyhttp://code.google.com/p/kay-framework/
![Page 4: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/4.jpg)
> 10万 Developers / Month
> 15万 Apps / Week
> 10億 Page Views / Day
![Page 5: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/5.jpg)
Apr 2008 Python launchMay 2008 Memcache API, Images APIJul 2008 Logs exportAug 2008 Batch write/deleteOct 2008 HTTPS supportDec 2008 Status dashboard, quota detailsFeb 2009 Billing, Remote API, Larger HTTP request/response size limits (10MB)Apr 2009 Java launch, Bulkloader (DB import), Cron jobs, SDCMay 2009 Key-only queries, Quota APIJun 2009 Task queue API, Django 1.0 supportSep 2009 XMPP API, Remote API shell, Django 1.1 supportOct 2009 Incoming emailDec 2009 Blobstore APIFeb 2010 Datastore cursors, Async URLfetch, App statsMar 2010 Denial-of-Service filtering, eventual consistency supportMay 2010 OpenID, OAuth, App Engine for Business, new bulkloaderAug 2010 Namespaces, increased quotas, high perf image servingOct 2010 Instances console, datastore admin & bulk entity deletesDec 2010 Channel API, 10-minute tasks & cron jobs, AlwaysOn & WarmupJan 2011 High Replication datastore, entity copy b/w apps, 10-minute URLfetchFeb 2011 Improved XMPP and Task Queue, Django 1.2 support
App Engine のこれまで 3 年 - 進化を続けるプラットフォーム
![Page 6: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/6.jpg)
ロードマップ
SSL access on non-appspot.com domainsFull-text Search over DatastoreSupport for Python 2.7Background servers capable of running for longer than 30sSupport for running MapReduce jobs across App Engine datasetsBulk Datastore Import and Export toolImproved monitoring and alerting of application servingLogging system improvements to remove limits on size and storageRaise HTTP request and response size limitsIntegration with Google Storage for DevelopersProgrammatic Blob creation in BlobstoreQuota and presence improvements for Channel API
![Page 7: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/7.jpg)
日本での事例
たくさんのミクシィアプリthe Actress - 60万ユーザーMixi Xmas 2010 - 200万ユーザー
朝日新聞 - メディア配信サービスソニー - Chan-Toru業務用アプリケーションも多数
![Page 8: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/8.jpg)
App Engine for Business とは?
App Engine プラットフォームに加え
99.9% SLAクラウド SQL有償サポートドメインコンソールHosted SSL
![Page 9: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/9.jpg)
本あります
プログラミング Google App Enginehttp://www.oreilly.co.jp/books/9784873114750/
オープンソース徹底活用 Slim3 on Google App Engine for JavaISBN-10: 4798026999
![Page 10: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/10.jpg)
アジェンダ
App Engine で開発する際の注意点
Datastore の設計最小限の仕事をするDatastore Contention を避ける
シャーディングカウンターFork-join queue
Memcache を効果的に使用するさらなる高みへ
![Page 11: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/11.jpg)
Datastore の設計
非正規化 を嫌がらない - No join必要な index のみ作成最小限の Entity Group
トランザクションが必要な箇所のみ可能なら速い方を使う
query より keys_only query が速いquery より get が速い複数の get より batch get が速い
kind の分割が有効なケース一部のプロパティだけ取得
少しの失敗を受け入れるリトライ、deadline の指定
![Page 12: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/12.jpg)
Datastore の設計
非正規化 を嫌がらない - No join必要な index のみ作成最小限の Entity Group
トランザクションが必要な箇所のみ可能なら速い方を使う
query より keys_only query が速いquery より get が速い複数の get より batch get が速い
kind の分割が有効なケース一部のプロパティだけ取得
少しの失敗を受け入れるリトライ、deadline の指定
![Page 13: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/13.jpg)
Datastore の設計 - 非正規化
from google.appengine.ext import db
class User(db.Model): name = db.StringProperty() groups = db.ListProperty(db.Key)
class Group(db.Model): name = db.StringProperty()
user = User.get(user_key)group_names = [group.name for group in db.get(user.groups)]
Before
![Page 14: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/14.jpg)
Datastore の設計 - 非正規化
from google.appengine.ext import db
class User(db.Model): name = db.StringProperty() groups = db.ListProperty(db.Key) group_names = db.StringListProperty()
class Group(db.Model): name = db.StringProperty()
user = User.get(user_key)# group_names = user.group_names
After
![Page 15: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/15.jpg)
Datastore の設計
非正規化 を嫌がらない - No join必要な index のみ作成最小限の Entity Group
トランザクションが必要な箇所のみ可能なら速い方を使う
query より keys_only query が速いquery より get が速い複数の get より batch get が速い
kind の分割が有効なケース一部のプロパティだけ取得
少しの失敗を受け入れるリトライ、deadline の指定
![Page 16: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/16.jpg)
Datastore の設計 - 必要な index のみ作成
from google.appengine.ext import db
class MyModel(db.Model): name = db.StringProperty() total = db.IntegerProperty(indexed=False)
index が増えると書き込み速度は遅くなります
![Page 17: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/17.jpg)
Datastore の設計
非正規化 を嫌がらない - No join必要な index のみ作成最小限の Entity Group
トランザクションが必要な箇所のみ可能なら速い方を使う
query より keys_only query が速いquery より get が速い複数の get より batch get が速い
kind の分割が有効なケース一部のプロパティだけ取得
少しの失敗を受け入れるリトライ、deadline の指定
![Page 18: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/18.jpg)
Datastore の設計 - Entity Group
class MyModel(db.Model): # ...
# 単純にエンティティを作成すると、それ自体新しい Entity Group になる
my_entity = MyModel()my_entity.put()
# 親を指定すると、親と同じ Entity Group に属する
my_second_entity = MyModel(parent=my_entity)my_second_entity.put()
# 同じ kind である必要はない
my_third_entity = MyOtherModel(parent=my_second_entity)my_third_entity.put()
Entity Group 作成の方法
![Page 19: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/19.jpg)
Datastore の設計 - Entity Group
class MyModel(db.Model): # ...
# 単純にエンティティを作成すると、それ自体新しい Entity Group になる
my_entity = MyModel()my_entity.put()
# 親を指定すると、親と同じ Entity Group に属する
my_second_entity = MyModel(parent=my_entity)my_second_entity.put()
# 同じ kind である必要はない
my_third_entity = MyOtherModel(parent=my_second_entity)my_third_entity.put()
Entity Group 作成の方法
![Page 20: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/20.jpg)
Datastore の設計 - Entity Group
親子関係全てに Entity Group を使用するべきではない例えば BlogEntry と Comment には不適切
基本的にはトランザクションが必要な箇所に使う検索用インデックスを自前で作る時などにも有効
![Page 21: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/21.jpg)
Datastore の設計 - Entity Group の使用例
検索用インデックス - Before
class Sentence(db.Model): body = db.TextProperty() indexes = db.StringListProperty()
query = Sentence.all().filter( "indexes =", search_word)search_result = query.fetch(20)
fetch 時に不必要な indexes のデシリアライズが発生
![Page 22: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/22.jpg)
Datastore の設計 - Entity Group の使用例
検索用インデックス - After
class Sentence(db.Model): body = db.TextProperty()
class SearchIndex(db.Model): indexes = db.StringListProperty()
query = SearchIndex.all(keys_only=True).\ filter("indexes =", search_word)search_result = db.get( [key.parent() for key in query.fetch(20)])
保存時に Entity Group を形成
![Page 23: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/23.jpg)
Datastore の設計
非正規化 を嫌がらない - No join必要な index のみ作成最小限の Entity Group
トランザクションが必要な箇所のみ可能なら速い方を使う
query より keys_only query が速いquery より get が速い複数の get より batch get が速い
kind の分割が有効なケース一部のプロパティだけ取得
少しの失敗を受け入れるリトライ、deadline の指定
![Page 24: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/24.jpg)
Datastore の設計
非正規化 を嫌がらない - No join必要な index のみ作成最小限の Entity Group
トランザクションが必要な箇所のみ可能なら速い方を使う
query より keys_only query が速いquery より get が速い複数の get より batch get が速い
kind の分割が有効なケース一部のプロパティだけ取得
少しの失敗を受け入れるリトライ、deadline の指定
![Page 25: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/25.jpg)
Datastore の設計 - Entity 分割
例: ファイルシェアリングサービスファイル自身メタデータ
ファイルの一覧ページで必要なのはメタデータだけファイル自身とメタデータを別エンティティに分割一覧ページでの処理が高速で無駄がなくなる
![Page 26: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/26.jpg)
Datastore の設計
非正規化 を嫌がらない - No join必要な index のみ作成最小限の Entity Group
トランザクションが必要な箇所のみ可能なら速い方を使う
query より keys_only query が速いquery より get が速い複数の get より batch get が速い
kind の分割が有効なケース一部のプロパティだけ取得
少しの失敗を受け入れるリトライ、deadline の指定
![Page 27: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/27.jpg)
Datastore の設計 - リトライ、deadline
from google.appengine.ext import dbfrom google.appengine.runtime.apiproxy_errors import DeadlineExceededErrorfrom google.appengine.runtime import DeadlineExceededError as D
def somefunction(somevalue): handmaid_key = db.Key.from_path("MyModel", 1) new_id = db.allocate_ids(handmaid_key, 1) new_key = db.Key.from_path("MyModel", new_id) my_entity = MyModel(key=new_key, name=somevalue) try: while True: sleep_ms = 100 try: db.put(my_entity, config=db.create_config(deadline=5)) break except (DeadlineExceededError, db.Timeout): time.sleep(sleep_ms) sleep_ms *= 2 except D: # Ran out of retry. Return an error to users.
自動リトライのレシピ
![Page 28: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/28.jpg)
最小限の仕事をする
大事な用語ユーザー向けリクエスト(User Facing Request)
インターネット側から来るもの全てバックグラウンドリクエスト(Background Request)
TaskQueue, Cron 等
大事なポイントユーザー向けリクエストは 1000 ms 以内で返すこと
![Page 29: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/29.jpg)
最小限の仕事をする - より速い方を使用
query より keys_only queryquery より getdatastore より memcachememcache より global 変数(static 変数)
![Page 30: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/30.jpg)
最小限の仕事をする - Task Queue を使用
時間のかかる処理は Task Queue に投げる。Channel API を使えば結果を簡単にプッシュ
![Page 31: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/31.jpg)
Datastore Contention をさける
Entity または Entity Group に対しての書き込み
目安: 1 秒に 1 度程度対策:
Entity Group はなるべく小さくするシャーディングカウンターなどのテクニックを使用する
![Page 32: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/32.jpg)
シャーディングカウンター - シンプルな実装例
from google.appengine.ext import dbimport random
class SimpleCounterShard(db.Model): """Shards for the counter""" count = db.IntegerProperty(required=True, default=0)
NUM_SHARDS = 20
def get_count(): """Retrieve the value for a given sharded counter.""" total = 0 for counter in SimpleCounterShard.all(): total += counter.count return total
def increment(): """Increment the value for a given sharded counter.""" def txn(): index = random.randint(0, NUM_SHARDS - 1) shard_name = "shard" + str(index) counter = SimpleCounterShard.get_by_key_name(shard_name) if counter is None: counter = SimpleCounterShard(key_name=shard_name) counter.count += 1 counter.put() db.run_in_transaction(txn)
http://goo.gl/8dGO
![Page 33: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/33.jpg)
Fork-join queue
Building high-throughput data pipelines with Google App Engine
http://goo.gl/ntlH
シンプルなカウンターの例http://paste.shehas.net/show/137/
![Page 34: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/34.jpg)
memcache を効果的に使用する
使用例人気のあるページを html 丸ごとキャッシュmemcache.incr を使用したカウンター
高速だが 100% 正確とは保証できない頻繁に使用される entity や query 結果をキャッシュ
![Page 35: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/35.jpg)
memcache を効果的に使用する
基本パターン
results = memcache.get('results')if results is None: results = some_complex_work() memcache.set('results', results)
# use results
古いキャッシュを破棄する
![Page 37: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/37.jpg)
さらなる高みへ
Request 数の Fixed Quota はデフォルト 500 QPS 程度それ以上必要な場合は、Quota Increase のフォームから申請するか私宛に相談してください
Tablet Server の Split を抑制頻繁に(数百/秒) Entity の作成などを行う場合
自動採番の id では Split を引き起こしやすいuuid などを key_name として使用する
key_name を使用する場合でも、頭文字が類似だと Split が起きやすい
Hash 値を前置する
![Page 38: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/38.jpg)
まとめ
Datastore に適した設計最小限の仕事をするDatastore Contention を避けるMemcache を効果的に使用するAppStats を使用してパフォーマンス測定するFixed Quota を増やすTablet Server の Split を抑制
![Page 39: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/39.jpg)
無限の彼方へ
![Page 40: 【18-C-4】Google App Engine - 無限の彼方へ](https://reader034.vdocuments.mx/reader034/viewer/2022042518/55621e50d8b42ac6588b4745/html5/thumbnails/40.jpg)
Takashi MatsuoGoogle, Inc.e-mail: [email protected]: @tmatsuo