Як працює кешування на основі ключів?


10

Нещодавно я прочитав статтю в блозі 37Signals, і мені залишається цікаво, як вони отримують ключ кешу.

Все добре і добре мати кеш-ключ, який включає часову позначку об'єкта (це означає, що при оновленні об’єкта кеш буде недійсним); але як потім використовувати ключ кешу в шаблоні, не викликаючи звернення БД для самого об'єкта, який ви намагаєтеся отримати з кеша.

Зокрема, як це впливає на відносини "Один до багатьох", коли, наприклад, ви надаєте коментарі до публікації.

Приклад у Django:

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

Чи кешування в Rails відрізняється від, наприклад, просто запитів, які потрібно записувати (я знаю, що вони перетворюють ваш кеш-ключ у щось інше). Чи вони також кешують кеш-ключ?


Погляньте на rossp.org/blog/2012/feb/29/fragment-caching для прикладу Django!
vdboor

Я вже мав на це погляд, і, схоже, страждає саме та сама проблема. Дані, які він намагається кешувати, потрібні для доступу до кешу. Єдине, на чому він, начебто, економить, - це внутрішня дорога операція, яка на відміну від більшості випадків використання для кешування цього типу.
Домінік Сантос

Це правда, також буває з кодом 37сигналів, він зосереджений на коді візуалізації. Трюк полягає в тому, щоб кешувати весь список в іншому контейнері або кешувати пошук об'єкта в іншому місці.
vdboor

Насправді їх кеш-стратегія здається трохи освіченішою. Я також рекомендую цю статтю: 37signals.com/svn/posts/…
JensG

Схоже, у вашому фрагменті коду є помилка друку - це було post.bodyпризначено comment.body?
Ізката

Відповіді:


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це показник для всіх його дітей , саме це ви використовуєте як кеш-ключ, перш ніж намагатися завантажити дітей.


Поки в блогах використовуються окремі шаблони, я збираюся зібрати їх в один. Сподіваємось, побачення повної взаємодії в одному місці зробить це трохи зрозумілішим.

Отже, шаблон Джанго може виглядати приблизно так:

{% 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зазначено вище - тоді він повинен буде надати своїх дітей, і лише тоді він виконуватиме запит для всіх тодолістів для цього проекту. Так само і для конкретного Todolist - якщо cache_key цього списку існує, то тодоси всередині нього не змінилися, і все це можна витягнути з кеша.

Також зауважте, як я не використовую 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 рази: Bang1, Bang2іBang4

І звичайно, наступного разу, коли його буде переглянуто, Foo.cache_keyбуло б знайдено, тож єдиною витратою на надання є вилучення Fooсамостійно з бази даних та запит кеша.


-2

Ваш приклад хороший, якщо він потребує певного пошуку чи обробки даних для кожного коментаря. Якщо ви просто візьмете тіло і покажете його - кеш буде марним. Але ви можете кешувати всі дерева коментарів (включаючи {% для%}). У цьому випадку вам потрібно визнати його недійсним з кожним доданим коментарем, щоб ви могли поставити останню часову мітку коментарів або коментарі десь підписати до повідомлення та створити з неї ключ кешу коментарів. Якщо ви віддаєте перевагу більш нормалізованим даним та використовуєте коментарі лише на одній сторінці, ви можете просто очистити кеш-клавішу щодо збереження коментарів.

Для мене збереження підрахунків коментарів у Пості виглядає досить добре (якщо ви не дозволяєте видаляти та редагувати коментарі) - у вас є значення для показу в будь-якому місці за допомогою публікації та ключа кешування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.