J'ai récemment lu un article sur le blog 37Signals et je me demande comment il obtient la clé de cache.
C'est bien d'avoir une clé de cache qui inclut l'horodatage de l'objet (cela signifie que lorsque vous mettez à jour l'objet, le cache sera invalidé); mais comment utilisez-vous ensuite la clé de cache dans un modèle sans provoquer un hit de base de données pour l'objet même que vous essayez de récupérer dans le cache.
Plus précisément, comment cela affecte-t-il les relations un à plusieurs dans lesquelles vous affichez les commentaires d'un message, par exemple.
Exemple dans Django:
{% for comment in post.comments.all %}
{% cache comment.pk comment.modified %}
<p>{{ post.body }}</p>
{% endcache %}
{% endfor %}
La mise en cache dans Rails est-elle différente des simples demandes de memcached par exemple (je sais qu'ils convertissent votre clé de cache en quelque chose de différent). Cache-t-il également la clé de cache?
post.body
censé l'êtrecomment.body
?Réponses:
Pour mettre en cache un vidage direct d'un seul objet déjà chargé, oui, vous ne gagnez rien ou presque rien. Ce n'est pas ce que ces exemples décrivent - ils décrivent une hiérarchie, où tout changement vers quelque chose de plus bas devrait également déclencher une mise à jour de tout ce qui est plus haut dans la hiérarchie.
Le premier exemple, du blog 37signals, utilise
Project -> Todolist -> Todo
comme hiérarchie. Un exemple rempli pourrait ressembler à ceci:Donc, disons a
Bang3
été mis à jour. Tous ses parents sont également mis à jour:Ensuite, quand vient le temps de rendre, le chargement à
Project
partir de la base de données est fondamentalement inévitable. Vous avez besoin d'un point pour commencer. Cependant, commelast_modified
c'est un indicateur de tous ses enfants , c'est ce que vous utilisez comme clé de cache avant de tenter de charger les enfants.Bien que les articles de blog utilisent des modèles distincts, je vais les regrouper en un seul. Espérons que voir l'interaction complète en un seul endroit le rendra un peu plus clair.
Ainsi, le modèle Django pourrait ressembler à ceci:
Supposons que nous transmettions un projet qui
cache_key
existe toujours dans le cache. Étant donné que nous propagons les modifications de tous les objets associés au parent, le fait que cette clé particulière existe toujours signifie que tout le contenu rendu peut être extrait du cache.Si ce projet particulier venait d'être mis à jour - par exemple, comme avec
Foo
ci-dessus - alors il devra rendre ses enfants, et alors seulement il exécutera la requête pour tous les Todolists pour ce projet. De même pour une Todolist spécifique - si la clé cache_key de cette liste existe, alors les todos qu'elle contient n'ont pas changé, et le tout peut être extrait du cache.Notez également comment je n'utilise pas
todo.cache_key
dans ce modèle. Cela ne vaut pas la peine, car comme vous le dites dans la question,body
a déjà été retiré de la base de données. Cependant, les hits de base de données ne sont pas la seule raison pour laquelle vous pouvez mettre en cache quelque chose. Par exemple, prendre du texte de balisage brut (tel que ce que nous tapons dans des boîtes de questions / réponses sur StackExchange) et le convertir en HTML peut prendre suffisamment de temps pour que la mise en cache du résultat soit plus efficace.Si tel était le cas, la boucle interne du modèle pourrait ressembler davantage à ceci:
Donc, pour tout rassembler, revenons à mes données d'origine en haut de cette réponse. Si nous supposons:
Bang3
vient d'être mis à jourexpensive_markup_parser
)Ensuite, voici comment tout serait chargé:
Foo
est récupéré de la base de donnéesFoo.cache_key
(2014-05-16) n'existe pas dans le cacheFoo.todolists.all()
est interrogé:Bar1
etBar2
sont récupérés de la base de donnéesBar1.cache_key
(2014-05-10) existe déjà dans le cache ; récupérer et sortirBar2.cache_key
(2014-05-16) n'existe pas dans le cacheBar2.todos.all()
est interrogé:Bang3
etBang4
sont récupérés de la base de donnéesBang3.cache_key
(2014-05-16) n'existe pas dans le cache{{ Bang3.body|expensive_markup_parser }}
est renduBang4.cache_key
(2014-04-01) existe déjà dans le cache ; récupérer et sortirLes économies du cache dans ce petit exemple sont:
Bar1.todos.all()
expensive_markup_parser
3 fois évité:Bang1
,Bang2
etBang4
Et bien sûr, la prochaine fois qu'il sera visualisé,
Foo.cache_key
il sera trouvé, donc le seul coût du rendu est la récupérationFoo
seule de la base de données et l'interrogation du cache.la source
Votre exemple est bon s'il nécessite une récupération ou un traitement des données pour chaque commentaire. Si vous prenez simplement le corps et l'affichez - le cache sera inutile. Mais vous pouvez mettre en cache tous les arbres de commentaires (y compris {% pour%}). Dans ce cas, vous devez l'invalider avec chaque commentaire ajouté, vous pouvez donc placer l'horodatage du dernier commentaire ou le nombre de commentaires quelque part dans Post et créer une clé de cache de commentaires avec. Si vous préférez des données plus normalisées et utilisez des commentaires sur une seule page, vous pouvez simplement effacer une clé de cache lors de l'enregistrement du commentaire.
Pour moi, enregistrer le nombre de commentaires dans Post semble assez bon (si vous ne permettez pas de supprimer et de modifier les commentaires) - vous avez une valeur à afficher n'importe où avec la publication et une clé pour la mise en cache.
la source