キーベースのキャッシュはどのように機能しますか?


10

37Signalsブログの記事を最近読んだところ、キャッシュキーがどのように取得されるのか疑問に思いました。

オブジェクトのタイムスタンプを含むキャッシュキーがあれば十分です(つまり、オブジェクトを更新するとキャッシュが無効になります)。しかし、キャッシュからフェッチしようとしているオブジェクトそのものにDBヒットを引き起こさずに、テンプレートでキャッシュキーをどのように使用しますか。

具体的には、これにより、たとえば投稿のコメントをレンダリングする1対多の関係にどのように影響しますか。

Djangoでの例:

{% for comment in post.comments.all %}
   {% cache comment.pk comment.modified %}
     <p>{{ post.body }}</p>
   {% endcache %}
{% endfor %}

Railsでのキャッシュは、たとえばmemcachedへの単なるリクエストとは異なります(キャッシュキーを別のものに変換することは知っています)。キャッシュキーもキャッシュしますか?


Djangoの例については、rossp.org / blog / 2012 / feb / 29 / fragment-cachingご覧ください。
vdboor 2012年

私はすでにそれを見ました、そしてそれは全く同じ問題に苦しんでいるようです。キャッシュにアクセスするには、キャッシュしようとしているデータが必要です。彼が節約しているように見える唯一のものは、このタイプのキャッシングのほとんどのユースケースとは異なる内部の高価な操作です。
ドミニクサントス

それは本当です、37signalsコードでも起こります、それはレンダリングコードに焦点を当てています。トリックは、リスト全体を別のコンテナにキャッシュするか、オブジェクトの取得を別の場所にキャッシュすることです。
vdboor 2012年

実際、彼らのキャッシング戦略はもう少し知識があるようです。私もこの記事をお勧めします。37signals.com/svn/posts/...
JensG

コードスニペットにタイプミスがあるpost.bodyようcomment.bodyです- 意図されていましたか?
イズカタ2014年

回答:


3

既にロードされている単一のオブジェクトのストレートダンプをキャッシュする場合、はい、何も得られないか、ほとんど何も得られません。それはそれらの例が説明しているものではありません-それらは階層を説明しているので、何かより低いものへのいかなる変更も、階層のより上のすべてへの更新をトリガーするはずです。

37signalsブログの最初の例ではProject -> Todolist -> Todo、階層として使用しています。入力された例は次のようになります。

Project: Foo (last_modified: 2014-05-10)
   Todolist:  Bar1 (last_modified: 2014-05-10)
       Todo:  Bang1 (last_modified: 2014-05-09)
       Todo:  Bang2 (last_modified: 2014-05-09)

   Todolist:  Bar2 (last_modified: 2014-04-01)
       Todo:  Bang3 (last_modified: 2014-04-01)
       Todo:  Bang4 (last_modified: 2014-04-01)

それで、Bang3更新されたとしましょう。そのすべての親も更新されます:

Project: Foo (last_modified: 2014-05-16)
   Todolist:  Bar2 (last_modified: 2014-05-16)
       Todo:  Bang3 (last_modified: 2014-05-16)

次に、レンダリングの時間になるとProject、データベースからのロードは基本的に避けられません。開始するにはポイントが必要です。ただし、これlast_modifiedすべての子のインジケーターであるため、子をロードする前にキャッシュキーとして使用します。


ブログの投稿では個別のテンプレートを使用していますが、私はそれらを1つにまとめます。1つの場所で完全なやり取りを確認すると、少しわかりやすくなります。

したがって、Djangoテンプレートは次のようになります。

{% cache 9999 project project.cache_key %}
<h2>{{ project.name }}<h2>
<div>
   {% for list in project.todolist.all %}
   {% cache 9999 todolist list.cache_key %}
      <ul>
         {% for todo in list.todos.all %}
            <li>{{ todo.body }}</li>
         {% endfor %}
      </ul>
   {% endcache %}
   {% endfor %}
</div>
{% endcache %}

cache_keyまだキャッシュに存在するプロジェクトを渡すとします。すべての関連オブジェクトへの変更を親に伝達するため、その特定のキーがまだ存在するという事実は、レンダリングされたコンテンツ全体をキャッシュからプルできることを意味します

その特定のプロジェクトが更新されたばかりの場合(たとえば、Foo上記のように)、その子をレンダリングする必要があり、その後、そのプロジェクトのすべてのTodolistsに対してクエリを実行します。同様に、特定のTodolistの場合-そのリストのcache_keyが存在する場合、リスト内のTodoは変更されておらず、すべてをキャッシュから取得できます。

またtodo.cache_key、このテンプレートで使用していないことに注意してください。あなたが質問で言うように、それbodyはすでにデータベースからプルされているので、それは価値がありません。ただし、何かをキャッシュする理由はデータベースのヒットだけではありません。たとえば、生のマークアップテキスト(StackExchangeの質問/回答ボックスに入力するものなど)を取得してHTMLに変換するには、結果をキャッシュするのに十分な時間がかかる場合があります。

その場合、テンプレートの内部ループは次のようになります。

         {% for todo in list.todos.all %}
            {% cache 9999 todo todo.cache_key %}
               <li>{{ todo.body|expensive_markup_parser }}</li>
            {% endcache %}
         {% endfor %}

すべてをまとめるために、この回答の上部にある元のデータに戻りましょう。仮定すると:

  • すべてのオブジェクトは元の状態でキャッシュされていました
  • Bang3 更新されました
  • 変更されたテンプレート(を含むexpensive_markup_parser)をレンダリングしています

次に、これはすべてがロードされる方法です:

  • Foo データベースから取得されます
  • Foo.cache_key (2014-05-16)キャッシュに存在しません
  • Foo.todolists.all()照会されています Bar1し、Bar2データベースから取得されます
  • Bar1.cache_key(2014-05-10)キャッシュに既に存在します。それを取得して出力する
  • Bar2.cache_key (2014-05-16)キャッシュに存在しません
  • Bar2.todos.all()照会されています Bang3し、Bang4データベースから取得されます
  • Bang3.cache_key (2014-05-16)キャッシュに存在しません
  • {{ Bang3.body|expensive_markup_parser }} レンダリングされます
  • Bang4.cache_key(2014-04-01)はすでにキャッシュに存在します。それを取得して出力する

この小さな例でのキャッシュによる節約は次のとおりです。

  • データベースヒットを回避: Bar1.todos.all()
  • expensive_markup_parser:3回を避けBang1Bang2、およびBang4

そしてもちろん、次に表示されたときにそれFoo.cache_keyが見つかるので、レンダリングするための唯一のコストはFoo、データベースから単独で取得してキャッシュをクエリすることです。


-2

コメントごとにデータの取得または処理が必要な場合、この例は適切です。ボディを取り出して表示するだけの場合、キャッシュは役に立ちません。ただし、すべてのコメントツリーをキャッシュできます({%for%}を含む)。この場合、コメントを追加するたびに無効にする必要があるため、最後のコメントのタイムスタンプまたはコメントの数をPostのどこかに配置し、それを使用してコメントキャッシュキーを構築できます。より正規化されたデータを使用し、1つのページでのみコメントを使用する場合は、コメントの保存時にキャッシュキーをクリアするだけです。

私にとって、投稿でのコメント数の保存は十分に見えます(コメントを削除および編集することを許可しない場合)-投稿とキャッシュ用のキーでどこにでも表示する値があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.