atwiki-logo
  • 新規作成
    • 新規ページ作成
    • 新規ページ作成(その他)
      • このページをコピーして新規ページ作成
      • このウィキ内の別ページをコピーして新規ページ作成
      • このページの子ページを作成
    • 新規ウィキ作成
  • 編集
    • ページ編集
    • ページ編集(簡易版)
    • ページ名変更
    • メニュー非表示でページ編集
    • ページの閲覧/編集権限変更
    • ページの編集モード変更
    • このページにファイルをアップロード
    • メニューを編集
    • 右メニューを編集
  • バージョン管理
    • 最新版変更点(差分)
    • 編集履歴(バックアップ)
    • アップロードファイル履歴
    • ページ操作履歴
  • ページ一覧
    • ページ一覧
    • このウィキのタグ一覧
    • このウィキのタグ(更新順)
    • このページの全コメント一覧
    • このウィキの全コメント一覧
    • おまかせページ移動
  • RSS
    • このウィキの更新情報RSS
    • このウィキ新着ページRSS
  • ヘルプ
    • ご利用ガイド
    • Wiki初心者向けガイド(基本操作)
    • このウィキの管理者に連絡
    • 運営会社に連絡(不具合、障害など)
ページ検索 メニュー
とりあえず雑記帳(跡地)
  • ウィキ募集バナー
  • 目安箱バナー
  • 操作ガイド
  • 新規作成
  • 編集する
  • 全ページ一覧
  • 登録/ログイン
ページ一覧
とりあえず雑記帳(跡地)
  • ウィキ募集バナー
  • 目安箱バナー
  • 操作ガイド
  • 新規作成
  • 編集する
  • 全ページ一覧
  • 登録/ログイン
ページ一覧
とりあえず雑記帳(跡地)
ページ検索 メニュー
  • 新規作成
  • 編集する
  • 登録/ログイン
  • 管理メニュー
管理メニュー
  • 新規作成
    • 新規ページ作成
    • 新規ページ作成(その他)
      • このページをコピーして新規ページ作成
      • このウィキ内の別ページをコピーして新規ページ作成
      • このページの子ページを作成
    • 新規ウィキ作成
  • 編集
    • ページ編集
    • ページ編集(簡易版)
    • ページ名変更
    • メニュー非表示でページ編集
    • ページの閲覧/編集権限変更
    • ページの編集モード変更
    • このページにファイルをアップロード
    • メニューを編集
    • 右メニューを編集
  • バージョン管理
    • 最新版変更点(差分)
    • 編集履歴(バックアップ)
    • アップロードファイル履歴
    • ページ操作履歴
  • ページ一覧
    • このウィキの全ページ一覧
    • このウィキのタグ一覧
    • このウィキのタグ一覧(更新順)
    • このページの全コメント一覧
    • このウィキの全コメント一覧
    • おまかせページ移動
  • RSS
    • このwikiの更新情報RSS
    • このwikiの新着ページRSS
  • ヘルプ
    • ご利用ガイド
    • Wiki初心者向けガイド(基本操作)
    • このウィキの管理者に連絡
    • 運営会社に連絡する(不具合、障害など)
  • atwiki
  • とりあえず雑記帳(跡地)
  • Google App Engine
  • キャッシュの計画

とりあえず雑記帳(跡地)

キャッシュの計画

最終更新:2012年06月29日 03:55

Bot(ページ名リンク)

- view
管理者のみ編集可
WebコミックLibraryhttp://web-comi.appspot.com/
GAE/JとSlim3で作成してみた、各出版社から配信されているWebコミックをまとめて閲覧できるサイトです。只今、実験運用中…

概要

Datastoreの主要なQuotaである「Datastore Read Operations」と「Datastore Small Operations」を節約するために、どのようにMemcacheを活用すればよいか、についての考察です。



月並みな話から


まずは、キャッシュの計画については「これが正解だ」というのはありません
  • それがあれば、既にフレームワークとして提供されています…
ということで、対象となるWebアプリケーションの特性に応じた、「最適解」としてのキャッシュの計画を考える必要があります。
  • アクセスされるデータの偏り方
  • データの更新頻度
  • 更新結果を反映させるまでの猶予がどれだけあるか(リアルタイム性)
  • などなど
例えば、現在ひっそりと実験運用中のWebコミックLibraryhttp://web-comi.appspot.com/に関しては
  • データの更新頻度については、原則、一日数回のクローリングでのみ更新なので、クローリング直後の内容をキャッシュしておけば、毎回Datastoreにアクセスする必要が無い
  • クエリ結果も、「サイトの作品全部」や「作品の作者全員」等、決まりきった検索条件ばかりなので、これもどんどんキャッシュしておけば良い
  • クエリ結果のキャッシュは、(クローリングによる更新も含めて)何らかのModelの更新があった時点で、全てクリアでもいいや
  • そこまでリアルタイム性が要求されるデータでは無いので、万が一、キャッシュの内容が古かったとしても、次のクローリングのタイミングで最新化されれば良い。
といった感じです。



前提


計画にあたり、Google App Engine側での、いくつかの前提を確認しておきましょう。

Eventual Consistency(結果整合性)

参考
najeira: Eventual consistencyなクエリ結果のキャッシュ
結果整合性(Eventual Consistency)についての分かりやすいプレゼン資料 - Publickey

デフォルトのHigh Replication Datastoreでは「Eventual Consistency」が採用されています。
これは、「更新された内容は、そのうち全ノードに反映される」→「更新直後のクエリでは、直前の更新内容が取得されない可能性がある」ということです。
まぁ、全ノード反映の時間はかなり早いので、「単一のリクエスト処理内で、更新直後にクエリ発行」ぐらいでしか問題にならないかと思います。
とは言え、そのような「更新前の情報によるクエリ結果」が返ってきた場合に、それをキャッシュしてしまうと、キャッシュにヒットする間は古いクエリ結果のまま、ということが発生してしまいます。

上記により「Eventual Consistencyのためにキャッシュが当てにならない」という声もありますが
  • 仮に古い結果でキャッシュされたとしても、いつまでにキャッシュがご破算になって再取得が発生すれば、実運用上問題ないか?
を検討して、キャッシュのクリアがそこまでに発生するのが判明すれば、Eventual Consistencyとキャッシュは共存可能です。
「WebコミックLibrary」の例で言えば、「更新が発生したクローリング直後のクエリは古い結果になるかも知れないけど、急ぎのデータでもないし、次のクローリングの際にキャッシュがご破算になるから、その後のクエリで最新化できればいいや」という考えです。
むしろ「そのうちキャッシュがご破算になって、正しい内容で最新化される」までを含めて、Eventual Consistencyであると解釈しましょう。

ということで、クエリ結果のキャッシュについては、この特性を前提にして
  • いつ、クエリ結果をキャッシュすべきか
  • いつ、キャッシュをクリアすべきか
を考える必要があります。

Datastore Read OperationsとDatastore Small Operationsのコスト比較

参考
Billing and Budgeting Resources - Google App Engine — Google Developers

「Datastore Read Operations」「Datastore Small Operations」の計算方法は下記の通りです。
  • Datastore Read Operations
    • 「Datastore Entity Fetch Ops」+「Datastore Query Ops」
  • Datastore Small Operations
    • 「Datastore Key Fetch Ops」+「Datastore Id Allocation Ops」
注目は「Datastore Entity Fetch Ops」と「Datastore Key Fetch Ops」ですが、同じクエリでも
  • Query#setKeysOnly()を指定しない場合は、結果件数が「Datastore Entity Fetch Ops」にカウント。
    • Slim3の場合は、ModelQuery#asList()/asIterator()を用いた場合
  • Query#setKeysOnly()を指定した場合は、結果件数が「Datastore Key Fetch Ops」にカウント。
    • Slim3の場合は、ModelQuery#asKeyList()/asKeyIterator()を用いた場合
という計算になります。
これは、filterでEntity(Slim3ならModel)のプロパティを検索キーにしても同様です。

さて、参考ページに記載されているコストをみると
Operation Cost
Read 10万回につき、$0.07
Small 10万回につき、$0.01
と、Readに比べてSmallは7分の1のコストになっています。

これらの内容から考察すると、「Keyに紐づくEntityが全てキャッシュされており、KeyさえあればEntityの取得でDatastoreにアクセスする必要が無い」という前提条件があれば、
クエリはQuery#setKeysOnly()を指定してKeyのみを取得したほうが、同じ件数でも低コスト
ということになります。

もちろん、Entityが必ずしもキャッシュされているとは限らないので、もしキャッシュに存在しない場合はEntityをDatastoreから取得するためにDatastore Entity Fetch Opsが追加で発生します。
よって、その場合はSmallとRead両方にカウントされてしまいます。
まぁ、キャッシュなので、ミスしたときのペナルティはそれなりに発生してしまうもんです…。

ということで、
  • キャッシュされる率が高いEntityについては、クエリ結果はQuery#setKeysOnly()を指定してKeyのみ取得し、実際のEntityはキャッシュから取得することで、コストを削減する
という方針は有効です。

なお「無料枠内なんでコスト関係ないっす」という方についても、Query#setKeysOnly()をまったく指定しなければ全てのクエリ結果がReadのカウントとなってしまいますが、上記の方針ならばReadとSmallに分散されて過度なReadの増加が抑えられるので、やっぱり有効です。



ここから先の議論は、最初にお話した通り、全てのWebアプリケーションに適用できるわけではありません。
が、概ねのモノには当てはまるかと思います。後は、各アプリケーションに応じてカスタムするのが良いかと。



どこで実装するか

実際のデータ参照先がDatastoreなのかキャッシュなのか、については、データを利用する側からは意識したくないので、通常はDAO層で実装します。

キャッシュ対象の分類

キャッシュ対象は、主に「Entity」「クエリ結果」の2つになります。
  • Entity(Slim3ならModel)
    • 「Datastore Entity Fetch Ops」の節約
  • クエリ結果
    • クエリ結果のKeyのListをキャッシュします。
    • 「Datastore Query Ops」と、(Query#setKeysOnly()を指定する場合は)「Datastore Key Fetch Ops」の節約

以下、それぞれについて、どのような方針でキャッシュするかを検討します。
なお、実装はSlim3を例としますが、考え方はそれ以外でも変わらないかと。



Entityのキャッシュ

Memcacheのキーとしては、DatastoreのKeyそのものを用います。

キャッシュの更新方針は、あまり深く考えずに、
  • Entityの登録/更新/削除と同時に、キャッシュにも登録/更新/削除
  • 取得時に、最初にキャッシュを参照し、なければDatastoreから取得して、キャッシュに登録
で良いかと。

Daoクラスの拡張

Slim3の場合、通常はDaoBaseをexntedsして、各Modelの具象Daoを定義しますが、
その間にキャッシュをサポートするDao階層を挟みます。

public abstract class CachingDao<M> extends DaoBase<M> {
 
    @Override
    public M get(final Key key) {
        M model = Memcache.get(key);
        if (model == null) {
            if (!Memcache.contains(key)) {
                // キャッシュミス時
                model = super.get(key);
                Memcache.put(key, model);
            }
        }
 
        return model;
    }
 
    @Override
    public Key put(M model) {
        Key key = super.put(model);
        Memcache.put(key, model);
        return key;
    }
 
    @Override
    public void delete(Key key) {
    	super.delete(key);
        Memcache.delete(key);
    }
}
 

各Modelの具象クラスは、上記CachingDaoをextendsするようにします。

ModelRefへのアクセスのキャッシング

Slim3では、Modelのプロパティの1つとして、他のModelへの参照を表すModelRefクラスがあります。
ModelRefを使った参照では、間接的にDatastoreへのアクセスが発生するので、これもキャッシングの対象とします。
※以前は、setxxxModelでキャッシュに登録していましたが、これをするとDatastoreと同期がとれなくなるので、止めました

@Model(schemaVersion = 1)
public class FooModel implements Serializable {
    ....
 
    private ModelRef<BarModel> barModelRef = new ModelRef<BarModel>(BarModel.class);
 
    public BarModel getBarModel() {
        Key key = barModelRef.getKey();
        if (key == null) {
        	// keyがnullなら、キャッシュ/Datastoreにはアクセスしない
        	return barModelRef.getModel();
        }
 
        M model = Memcache.get(key);
        if (model == null) {
            if (!Memcache.contains(key)) {
            	// キャッシュミス時
                model= barModelRef.getModel();
                Memcache.put(key, model);
            }
	}
 
	return model;
    }
    ....
}
 

大抵の場合、上記の対応だけでも、かなりDatastoreへのアクセスが減ります。
※WebコミックLibraryの場合、コレだけでキャッシュヒット率が94%です。つまり、殆どキャッシュです。



クエリ結果のキャッシュ

Memcacheのキーとしては、クエリの種類や検索条件を表す文字列を用います。
  • 例えば、「クエリを実行したDAOクラス名+メソッド名+検索キー」等
これは、キャッシュ更新方針が難しい(Entityが更新された場合、キャッシュされたクエリ結果をどうするか等)ので、アプリケーション毎に最適な方針を検討します。
(後日追記予定)
「キャッシュの計画」をウィキ内検索
LINE
シェア
Tweet
とりあえず雑記帳(跡地)
記事メニュー

メニュー

  • トップページ
  • コメント
  • とりあえずインターフェース入門
  • Yesod
  • Haskell
  • Slim3
  • JavaScript
  • Google App Engine
  • Android
  • Facebook
  • GWT
  • OpenSocial
  • Struts 2
  • Subversion
  • Apache
  • JSONIC
  • Flex

  • WebコミックLibraryについて

公式サイト

  • Yesod
  • Haskell
  • Slim3
  • JavaScript - MDN
  • App Engine for Java
  • Android Developers
  • Google Web Toolkit
  • Struts
  • OpenSocial
  • OSDE

  • ToDo

ここを編集
記事メニュー2
間違いの御指摘は
コメントまでm(_ _)m

更新履歴

取得中です。


ここを編集

総数: -
本日: -
昨日: -
人気記事ランキング
  1. JavaScript
  2. Slim3/とりあえずSlim3アプリケーションを作ろう/Daoが現れたよ
  3. JavaScript/Functionオブジェクトあれこれ
  4. JSONIC
  5. Slim3/とりあえずSlim3アプリケーションを作ろう/Modelを作る
  6. Slim3/とりあえずSlim3アプリケーションを作ろう/Controllerで画面作成
もっと見る
最近更新されたページ
  • 4398日前

    Haskell
  • 4398日前

    Yesod
  • 4398日前

    トップページ
  • 4507日前

    メニュー
  • 4509日前

    Struts 2
  • 4534日前

    コメント
  • 4703日前

    Google App Engine
  • 4741日前

    Slim3/環境構築とプロジェクト作成
  • 4765日前

    Google App Engine/キャッシュの計画
  • 4775日前

    Slim3/文字列の部分一致検索とページング
もっと見る
人気記事ランキング
  1. JavaScript
  2. Slim3/とりあえずSlim3アプリケーションを作ろう/Daoが現れたよ
  3. JavaScript/Functionオブジェクトあれこれ
  4. JSONIC
  5. Slim3/とりあえずSlim3アプリケーションを作ろう/Modelを作る
  6. Slim3/とりあえずSlim3アプリケーションを作ろう/Controllerで画面作成
もっと見る
最近更新されたページ
  • 4398日前

    Haskell
  • 4398日前

    Yesod
  • 4398日前

    トップページ
  • 4507日前

    メニュー
  • 4509日前

    Struts 2
  • 4534日前

    コメント
  • 4703日前

    Google App Engine
  • 4741日前

    Slim3/環境構築とプロジェクト作成
  • 4765日前

    Google App Engine/キャッシュの計画
  • 4775日前

    Slim3/文字列の部分一致検索とページング
もっと見る
ウィキ募集バナー
新規Wikiランキング

最近作成されたWikiのアクセスランキングです。見るだけでなく加筆してみよう!

  1. MadTown GTA (Beta) まとめウィキ
  2. AviUtl2のWiki
  3. R.E.P.O. 日本語解説Wiki
  4. シュガードール情報まとめウィキ
  5. 機動戦士ガンダム EXTREME VS.2 INFINITEBOOST wiki
  6. ソードランページ @ 非公式wiki
  7. シミュグラ2Wiki(Simulation Of Grand2)GTARP
  8. ドラゴンボール Sparking! ZERO 攻略Wiki
  9. 星飼いの詩@ ウィキ
  10. ヒカマーWiki
もっと見る
人気Wikiランキング

atwikiでよく見られているWikiのランキングです。新しい情報を発見してみよう!

  1. アニヲタWiki(仮)
  2. ストグラ まとめ @ウィキ
  3. ゲームカタログ@Wiki ~名作からクソゲーまで~
  4. 初音ミク Wiki
  5. 検索してはいけない言葉 @ ウィキ
  6. 発車メロディーwiki
  7. 機動戦士ガンダム バトルオペレーション2攻略Wiki 3rd Season
  8. Grand Theft Auto V(グランドセフトオート5)GTA5 & GTAオンライン 情報・攻略wiki
  9. オレカバトル アプリ版 @ ウィキ
  10. 英傑大戦wiki
もっと見る
全体ページランキング

最近アクセスの多かったページランキングです。話題のページを見に行こう!

  1. 参加者一覧 - ストグラ まとめ @ウィキ
  2. モンスター一覧_第2章 - モンスター烈伝オレカバトル2@wiki
  3. 魔獣トゲイラ - バトルロイヤルR+α ファンフィクション(二次創作など)総合wiki
  4. 高崎線 - 発車メロディーwiki
  5. 近藤旬子 - 馬主データベース@Wiki
  6. 地獄のデザイナーさん1 - 【トレパク】 きりつき 検証まとめwiki 【地獄のデザイナーさん】
  7. 召喚 - PATAPON(パタポン) wiki
  8. 細田守 - アニヲタWiki(仮)
  9. ステージ攻略 - パタポン2 ドンチャカ♪@うぃき
  10. 鬼レンチャン(レベル順) - 鬼レンチャンWiki
もっと見る

  • このWikiのTOPへ
  • 全ページ一覧
  • アットウィキTOP
  • 利用規約
  • プライバシーポリシー

2019 AtWiki, Inc.