15 Februar 2010

[Howto] memcached-Probleme zweier Django-Instanzen fixen

Kategorien: HowTos
Tags: Django

Wenn zwei Django-Instanzen sich den gleichen memcached als Cache-Backend teilen, kann es zu Anzeige-Problemen der Templates kommen. Dieser Artikel beschreibt die Bedingungen sowie eine entsprechende Lösung genauer. Wenn zwei Django-Instanzen den gleichen memcached als Caching-Backend nutzen, kann dies zu Anzeige-Problemen führen, falls die Templates Dateien mit gleichem Namen, aber unterschiedlichem Inhalt verwenden: es wird das falsche Template zum eigentlichen Inhalt angezeigt. Dieses Verhalten kann auch in allen Django-Programmen beobachtet werden, welche die Einstellung CACHE_MIDDLEWARE_KEY_PREFIX nicht berücksichtigen. Der entsprechende Bug report erwähnt, dass in einem solchen Fall eine Design-Entscheidung notwendig ist – die oben genannte Einstellung sollte eigentlich nur in Middleware-Installationen genutzt werden, und nicht im Rahmen der Templates. Ohne diese Einstellung können sich aber unterschiedliche Django-Instanzen gegenseitig beeinflussen. Dies ist nicht nur wegen der möglichen optischen Erscheinung der Instanzen von Gewicht, sondern auch wegen der Möglichkeit, CMS-Nutzerberechtigungen in den memcached einzubringen, und so die Rechte anderer Instanzen zu verändern. Eine Möglichkeit ist nun, sicherzustellen, dass die Konfigurationsoption CACHE_MIDDLEWARE_KEY_PREFIX für jeden Zugriff genutzt wird. Der dargestellte Code, als benutzerdefiniertes Cache-Backend genutzt, garantiert dies.

from django.conf import settings
from django.core.cache.backends.memcached import CacheClass as DjangoMemcachedCacheClass
from django.utils.hashcompat import md5_constructor
 
class CacheClass(DjangoMemcachedCacheClass):
    def __init__(self, server, params):
        self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
        super(CacheClass, self).__init__(server, params)
 
    def _genkey(self, origkey):
        return md5_constructor("%s:%s" %(self.key_prefix, origkey)).hexdigest()
 
    def add(self, key, value, timeout=0):
        return super(CacheClass, self).add(self._genkey(key), value, timeout)
 
    def get(self, key, default=None):
        return super(CacheClass, self).get(self._genkey(key), default)
 
    def set(self, key, value, timeout=0):
        return super(CacheClass, self).set(self._genkey(key), value, timeout)
 
    def delete(self, key):
        return super(CacheClass, self).delete(self._genkey(key))
 
    def get_many(self, keys):
        return super(CacheClass, self).get_many(self._genkey(key))
 
    def incr(self, key, delta=1):
        return super(CacheClass, self).incr(self._genkey(key), delta)
 
    def decr(self, key, delta=1):
        return super(CacheClass, self).decr(self._genkey(key), delta)

Darüber hinaus ist es wesentlich schwerer, gefälschten Cache-Inhalt einzufügen, wenn ein md5hex-digest als Schlüssel genutzt wird. Allerdings sollten sowieso nie wichtige Informationen in einem memcached gespeichert werden – in einem solchen Fall wäre locmem, file oder db als Backend wesentlich besser geeignet, da sie eine bessere Rechteverwaltung ermöglichen!

 

Dieser Artikel wurde ursprünglich geschrieben von Bernd Zeimetz.

Kategorien: HowTos
Tags: Django


Beitrag teilen: