Seite 1 von 1

besseres Caching...

Verfasst: Samstag 31. Dezember 2011, 14:05
von jens
Hab mir mal Gedanken zum Thema Caching gemacht und würde gern eure Meinung hören.

Meine Aktuelle Lösung ist einfach: Alle Requests für Anonyme User cachen. Wenn der Inhalt geändert wurde, wird einfach der komplette Cache gelöscht.

Vorteil: Nie veralteter Cache; sehr hohen Cache-Timeout; Einfach zu Implementieren
Nachteil: Sehr schlecht, bei Frequentierten Seiten: Wenn mehrere Clients kurz nach einem gelöschtem Cache Anfragen stellen, ist die Auslastung sehr hoch, bis der Cache wieder einigermaßen Aufgebaut wurde...

Also sollte man den Cache nicht einfach komplett löschen. Doch wie verhindern das User veraltete Seiten sehen?
Natürlich kann man einfach den Timeout beim Cache sehr niedrig wählen. Aber dann ist er nicht besonders Effektiv.

Als erstes kommt man vielleicht auf die Idee, wirklich nur die geänderten Cache Einträge zu löschen. Aber das ist nicht so einfach wie man denkt. z.B. Ein neuer Blog Eintrag führt ein neues Tag ein. Wo taucht dieser Tag überall auf? Gibt es evtl. eine Seite mit einer "Liste der neusten Änderungen" ? Wenn ja, wo ist diese?
Zweites Beispiel: Man ändert den Slug einer Seite. An welchen Stellen wirkt sich das überall aus? Auf alle Unterseiten. Auf Teile des Hauptmenüs/Sub-Menü und auf alle Links zu dieser Seite und zu allen Unterseiten. Dann noch auf das Sitemap usw...

Eine andere Idee: Man speichert den Zeitpunk der letzten Änderung. Bei jedem Erstellen eines neuen Cache Eintrags (Cache Miss) speichert man auch den Zeitpunkt dazu.
Nun kann man zumindest schnell erkennen, ob beim Cache Hit der Cache Eintrag aktuell oder veraltet ist. Außerdem weiß man wie veraltet er ist.
Nun kann man nicht einfach hingehen und einen Cache Hit der veraltet ist löschen und neu erstellen lassen. IMHO hat man fast das selbe Problem, wie beim komplett löschen.

Die Idee: Man schaut nach wie Ausgelastet das System ist und entscheidet dann, ob man einen veralteten Cache Eintrag ausliefert oder diesen Löscht und neu erstellt.

Die Frage ist, wie stellt man die Auslastung des Systems fest? Eine Idee, wäre auf os.getloadavg() zurück zu greifen.

Man könnte nun beide Werte (Alter des Caches und aktuellen loadavg) ein wenig variable zueinander setzten: Wenn das System stärker ausgelastet ist, wird ein höheres Alter des Caches akzeptiert. Wenn das System quasi Leerlauf hat, dann halt nur ein sehr geringes Alter. Bsp:

Code: Alles auswählen

(
    (0.2, 2) # loadavg <= 0.2 -> max cache alter >= 2 Sek.
    (1.0, 10) # avg >= 1.0 -> cache 10Sek. max
    (2.0, 90) # avg >= 2.0 -> cache 90Sek. max
)
Welche Werte wirklich Sinnvoll sind, weiß ich nicht. Kann man ja dann Konfigurierbar machen.

Eine komplett andere Lösung, die auch die beiden Timestaps nutzt: Es wird immer ein Cache-Hit ausgeliefert, egal ob veraltet. Ein Deamon aktualisiert im Hintergrund den Cache kontinuierlich. Dabei kann der sich vom ältesten zum neusten Eintrag vorarbeiten.

Was meint ihr dazu?

Re: besseres Caching...

Verfasst: Montag 2. Januar 2012, 08:28
von jens
Keiner was zu sagen?

Re: besseres Caching...

Verfasst: Mittwoch 4. Januar 2012, 11:16
von jens
Also ich glaube in meinem Falle lohnt sich das schon. Mein Fall wäre dann: Eine Webseite ohne Community Feature, mit relativ seltenen Änderungen. Ein paar Änderungen pro Tag, aber oft auch Wochenlang das gleiche.
Also nicht so etwas wie ein Forum, wo viele User angemeldet sind und sich ständig was ändert.

Das ganze macht aber nur Sinn, wenn man den Cache Timeout sehr lang wählt. Wie lang, weiß ich nicht. Vielleicht 24h oder gleich 7 Tage?

Re: besseres Caching...

Verfasst: Montag 9. Januar 2012, 17:49
von jens
Hab mal angefangen, sourcen/README hier: https://github.com/jedie/django-tools/t ... date_cache

Ursprünglich wollte ich nur eine Middleware machen. Dann hab ich mir überlegt, das man auch direkt tiefer beim Cache Backend ansetzten kann ;)

z.Z. ist nur das Filebased cache backend implementiert. Weil ich das z.Z. nutzte. Das Prinzip könnte man aber natürlich auch auf die anderen Backends übertragen.

Noch ist das ganze nicht wirklich ausreichend getestet.

Wie alt ein cache Eintrag veraltet sein darf, hängt von os.getloadavg()[0] ab und diese Tabelle legt das dann fest:

Code: Alles auswählen

    # load value, max age in sec.
    (0, 10), #     < 0.5     -> 10sec
    (0.5, 30), #   0.5 - 1.0 -> 30sec
    (1.0, 60), #   1.0 - 1.5 ->  1Min
    (1.5, 120), #  1.5 - 2.0 ->  2Min
    (2.0, 300), #  2.0 - 3.0 ->  5Min
    (3.0, 900), #  3.0 - 4.0 -> 15Min
    (4.0, 3600), # > 4.0     ->  1h
Die Werte sind mehr oder weniger aus der Luft gegriffen. Kann man aber alles per settings ändern. Was wirklich Sinn macht, weiß ich noch nicht...

Re: besseres Caching...

Verfasst: Freitag 24. August 2012, 14:25
von jens
Ich hab die Ursprüngliche Implementierung nochmal überarbeitet: https://github.com/jedie/django-tools/c ... 3b0c3462e9

README: https://github.com/jedie/django-tools/t ... e-backends

Ich habe es vom FileBasedCache los gelöst, sodass es mit allen django cache backends funktioniert!

Das Prinzip ist gleich geblieben. Ich vergleiche allerdings nicht mehr mtime der Datei, Statt dessen:
In cache.set() wird zu den eigentlichen Daten noch time.time() gespeichert.
In cache.get() wird dann der Timestamp mit dem timestamp vom letzten cache.clear() verglichen und verwerfe dann den Eintrag, wenn veraltet und os.getloadavg()[0] Wert entsprechend ist.

Re: besseres Caching...

Verfasst: Freitag 24. August 2012, 19:30
von jens
Hab mir überlegt, das ich cache.clear() ändere, in z.B.: cache.smooth_update()...

Dann kann man, wenn man möchte wirklich den cache komplett leeren...

Re: besseres Caching...

Verfasst: Dienstag 28. August 2012, 16:34
von jens
jens hat geschrieben:Hab mir überlegt, das ich cache.clear() ändere, in z.B.: cache.smooth_update()...
Gesagt getan, mit django-tools v0.25.0: https://github.com/jedie/django-tools/t ... le-changes