Anahtar tabanlı önbellekleme nasıl çalışır?


10

Geçenlerde 37Signals blogunda bir makale okudum ve önbellek anahtarını almanın nasıl olduğunu merak ediyorum.

Her şey iyi ve nesnenin zaman damgasını içeren bir önbellek anahtarına sahip olmak iyidir (bu, nesneyi güncellediğinizde önbelleğin geçersiz kılınacağı anlamına gelir); ancak önbellekten almaya çalıştığınız nesne için DB isabetine neden olmadan şablonda önbellek anahtarını nasıl kullanırsınız?

Özellikle bu, örneğin bir Gönderi Yorumunu oluşturduğunuz Bire Çok ilişkilerini nasıl etkiler?

Django'daki örnek:

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

Rails önbellekleme sadece örneğin memcached istekleri farklı (önbellek anahtarınızı farklı bir şeye dönüştürmek biliyorum). Önbellek anahtarını da önbelleğe alıyorlar mı?


Django örneği için rossp.org/blog/2012/feb/29/fragment-caching adresine bir göz atın !
vdboor

Zaten buna bir göz attım ve bu tamamen aynı problemden muzdarip gibi görünüyor. Önbelleğe erişmek için önbelleğe almaya çalıştığı veriler gereklidir. Tasarruf ettiği tek şey, bu tür önbellekleme için çoğu kullanım durumunun aksine olan pahalı iç işlemdir.
Dominic Santos

Bu doğru, 37 işaret kodu ile de olur, oluşturma koduna odaklanır. Hile, tüm listeyi başka bir kapsayıcıda da önbelleğe almak veya nesnenin başka bir yerde alınmasını önbelleğe almaktır.
vdboor

Aslında önbellek stratejileri biraz daha eğitimli görünüyor. Bu makaleyi de tavsiye ederim: 37signals.com/svn/posts/…
JensG

Kod pasajınız bir yazım hatası var gibi görünüyor - olması post.bodyamaçlandı comment.body?
Izkata

Yanıtlar:


3

Önceden yüklenmiş tek bir nesnenin düz bir dökümünü önbelleğe almak için, evet, hiçbir şey kazanmazsınız. Bu örneklerin tarif ettiği şey bu değildir - daha düşük bir şeyde yapılacak herhangi bir değişikliğin hiyerarşide daha yüksek olan her şey için bir güncelleme başlatması gereken bir hiyerarşiyi tanımlarlar.

İlk örnek, 37 işaret bloğundan, Project -> Todolist -> Todohiyerarşi olarak kullanılır. Doldurulmuş bir örnek şöyle görünebilir:

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)

Diyelim ki Bang3güncellendi. Tüm ebeveynleri de güncellenir:

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

Daha sonra oluşturma zamanı geldiğinde Project, veritabanından yükleme temel olarak kaçınılmazdır. Başlamak için bir noktaya ihtiyacınız var. Ancak, tüm çocuklarınınlast_modified bir göstergesi olduğundan, çocukları yüklemeye çalışmadan önce önbellek anahtarı olarak kullandığınız şey budur.


Blog gönderileri ayrı şablonlar kullanırken, bunları bir araya getireceğim. Umarım tüm etkileşimi tek bir yerde görmek onu biraz daha açık hale getirecektir.

Django şablonu şöyle görünebilir:

{% 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 %}

Diyelim ki cache_keyhala önbellekte bulunan bir projeye katıldık. İlgili tüm nesnelerde değişiklikleri üst öğeye yaydığımız için, söz konusu anahtarın hala mevcut olması, oluşturulan tüm içeriğin önbellekten alınabileceği anlamına gelir .

Belirli bir Proje daha yeni güncellenmişse (örneğin, Fooyukarıdaki gibi), o zaman çocuklarını oluşturması gerekir ve ancak o zaman o Proje için tüm Todolists için sorguyu çalıştırır. Aynı şekilde belirli bir Todolist için - eğer bu listenin cache_key'i varsa, içindeki todos değişmez ve her şey önbellekten çekilebilir.

Ayrıca todo.cache_keybu şablonda nasıl kullanmadığımı da fark et. Buna değmez, çünkü soruda söylediğin gibi body, zaten veritabanından çekildi. Ancak, bir şeyi önbelleğe almanın tek nedeni veritabanı isabetleri değildir. Örneğin, ham biçimlendirme metni (StackExchange'te soru / cevap kutularına yazdıklarımız gibi) almak ve HTML'ye dönüştürmek, sonucun önbelleğe alınmasının daha verimli olması için yeterli zaman alabilir.

Öyleyse, şablondaki iç döngü daha çok benzeyebilir:

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

Her şeyi bir araya getirmek için, bu cevabın üstündeki orijinal verilerime geri dönelim. Eğer varsayarsak:

  • Tüm nesneler orijinal hallerinde önbelleğe alınmıştı
  • Bang3 yeni güncellendi
  • Değiştirilen şablonu oluşturuyoruz (dahil expensive_markup_parser)

O zaman her şey böyle yüklenecekti:

  • Foo veritabanından alınır
  • Foo.cache_key (2014-05-16) önbellekte mevcut değil
  • Foo.todolists.all()sorgulanır: Bar1ve Bar2veritabanından alınır
  • Bar1.cache_key(2014-05-10) önbellekte zaten var ; al ve ver
  • Bar2.cache_key (2014-05-16) önbellekte mevcut değil
  • Bar2.todos.all()sorgulanır: Bang3ve Bang4veritabanından alınır
  • Bang3.cache_key (2014-05-16) önbellekte mevcut değil
  • {{ Bang3.body|expensive_markup_parser }} işlendi
  • Bang4.cache_key(2014-04-01) önbellekte zaten var ; al ve ver

Bu küçük örnekte önbellekten tasarruflar:

  • Veritabanı isabetinden kaçınıldı: Bar1.todos.all()
  • expensive_markup_parserkaçınılması 3 kez: Bang1, Bang2, veBang4

Ve elbette, bir dahaki sefere görüntülendiğinde, Foo.cache_keybulunacaktı, bu yüzden oluşturmanın tek maliyeti Fooveritabanından tek başına almak ve önbelleği sorgulamak.


-2

Her yorum için bir miktar veri alması veya işlenmesi gerekiyorsa örneğiniz iyidir. Sadece vücudu alıp sergilerseniz - önbellek işe yaramaz. Ancak tüm yorum ağacını önbelleğe alabilirsiniz (% için {%} dahil). Bu durumda, eklenen her yorumda geçersiz kılmanız gerekir, böylece son yorum zaman damgasını veya yorum sayısını bir yere Post içine koyabilir ve yorum önbellek anahtarı oluşturabilirsiniz. Daha normalleştirilmiş verileri tercih ederseniz ve yorumları yalnızca bir sayfada kullanırsanız, yorum kaydetme konusunda bir önbellek anahtarını silebilirsiniz.

Benim için yorum sayısını Post'ta kaydetmek yeterince iyi görünüyor (yorumları silmek ve düzenlemek için izin vermiyorsanız) - Post ile herhangi bir yerde gösterilecek bir değeriniz ve önbellek için bir anahtarınız var.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.