Caching: Aktueller Stand?

Hier können Probleme und alles andere in Deutscher Sprache gelöst werden.
Post Reply
onli
Regular
Posts: 2724
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Caching: Aktueller Stand?

Post by onli »

Ich hatte eben die unangenehme (naja) Situation, dass der Blog ein paar Besucher mehr als normal abbekommen hat. Die Serverlast stieg von normal in etwa 0.2 auf 1.46, 1.56, 1.18, was ja nicht gerade bedrohliche Werte sind, aber sich mit starkem Lag deutlich bemerkbar machte.

Ich habe daraufhin das realtimecomment-Plugin heruntergeschmissen und zuerst das simple-cache-plugin aktiviert. Das senkte die Belastung sofort und die Ladezeiten waren extrem viel besser, was sehr schön zu sehen war. Nur: sporadisch schoss der Server doch immer wieder in hohe Lastbereiche.

Deswegen die Fragen: Gibt es etwas am simple-cache-Plugin, dass diese sporadischen Lastspitzen erklärt, kam es von dem Plugin? Wie ist allgemein der Zustand des Plugins? Ich habe keine dynamischen Features, abgesehen vom honeypot, der durch js kaum betroffen sein sollte, wie wahrscheinlich ist es, dass Besucher wegen des Plugins seltsame Seiten sehen oder dass der Honeypot falsch funktioniert? Würde es sonst gerne anlassen, die bessere Ladezeit ist sehr angenehm. Mir wurde damals nicht klar, woher genau die Probleme mit durch den Cache falsch gelieferten Seiten genau stammen.

Wurde vielleicht alternativ etwas aus dem powercache, kann man das vielleicht mit wenigen ausgetauschten Dateien aktivieren? Das war mir damals zu sehr mit Warnungen versehen. Aber an sich sollte jeder Blog, der ja viel öfter gelesen als geschrieben wird, doch komplett gecached sein.
garvinhicking
Core Developer
Posts: 30020
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Re: Caching: Aktueller Stand?

Post by garvinhicking »

Hi!

Nun, der Stand ist, dass Caching in s9y durchaus etwas Liebe vertragen könnte. Ich bin da gedanklich nicht so richtig zu einem Fazit gekommen, wie man das technisch am besten implementieren kann ohne dass sämtliche funktionalität flöten geht.

Simplecache läuft so dass bei jedem Aufruf die gesamte Seite statisch gespeichert wird, es sei denn jemand schickt einen POST Request, oder ruft gewisse Backend-URLs auf. Jede Cachedatei kriegt dann einen Timestamp. Die Lastspitze könnte man sich so erklären dass wenn der cache zum ersten mal invalidiert wird, die Datenbankabfragen et.c alle wieder ausgeführt werden, um den Cache zu erzeugen.

Powercache war leider nie mehr als eine kleine Spielwiese von mir um eine Idee von Kris Köhntopp zu implementieren, in der jedes Element einer dynamischen Seite gecacht wird. Alleine daran zu basteln hat mir keinen Spaß gemacht, daher ist das eingeschlafen.

Viele Grüße,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
onli
Regular
Posts: 2724
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Caching: Aktueller Stand?

Post by onli »

Danke für die Antwort :)

Sehe ich da im Code vom cachesimple-Plugin javascript-code, der irgendwie die Kommentarformularfelder retten soll? Das würde erklären, warum das honeypot-Plugin nicht mehr richtig funktioniert... (valide Kommentare wurden durch das captcha moderiert)
Das Plugin registriert den frontend_shortcircuit-Event, danach beendet sich s9y und führt dabei die shutdown-function aus, die den cache ausgibt? Wenn das stimmt, klingt es doch recht solide.

Ist der powercache-code vielleicht etwas, was wir in 2.0 integrieren sollten? Dadurch würden wir zwangsläufig damit herumspielen.

Ich denke wirklich, dass ein kompletter cache möglich sein sollte. Alles was wir wollen ist ja, dass jede Seite beim ersten Laden gespeichert wird und beim erneuten Aufruf nicht mehr zusammengebaut, sondern aus dem cache geholt. Cache-Invalidation dann entweder komplett bei jedem beliebigem Write zur Datenbank oder gezielt, wenn wir absehen können, dass ein Kommentar nur diese Artikelseite verändert. Wenn wir das so grob machen, ohne Kris an sich schönere iframe/Element-Caching, sollte das doch etwas sein, was mit wenigen Codezeilen erledigt und überhaupt keine schädlichen Auswirkungen haben sollte (abgesehen von der leicht erhöhten Ladezeit durch die Cacheerstellung beim ersten Laden)?

Im Sinne von:
index.php: onShutdown && POST.length == 0 : cacheSite
database.inc.php: onWrite: invalidateCache
garvinhicking
Core Developer
Posts: 30020
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Re: Caching: Aktueller Stand?

Post by garvinhicking »

Hi!
Sehe ich da im Code vom cachesimple-Plugin javascript-code, der irgendwie die Kommentarformularfelder retten soll? Das würde erklären, warum das honeypot-Plugin nicht mehr richtig funktioniert... (valide Kommentare wurden durch das captcha moderiert)
Das Plugin registriert den frontend_shortcircuit-Event, danach beendet sich s9y und führt dabei die shutdown-function aus, die den cache ausgibt? Wenn das stimmt, klingt es doch recht solide.
Ja, korrekt. Das Vorausfüllen von Formularfeldern geht in einem gecachten Umfeld nicht mehr; daher wird versucht das mittels Cookie-Werten und JS auszufüllen.
Ist der powercache-code vielleicht etwas, was wir in 2.0 integrieren sollten? Dadurch würden wir zwangsläufig damit herumspielen.
Der powercache-Code hat den s9y Stand von Version 1.3 oder 1.4...das wurde nie gebackported, und war noch vor dem github Umzug. Ich bin da derzeit zu wenig drin um das zu portieren; um das Konzept an sich zu testen würde die alte Version natürlich reichen, und wenn man das zufriednestellend gelöst bekäme, könnte man es auch sicher in den 2.0er Tree rüberziehen können.

Mein Hauptproblem ist halt, dass man so ein Cachingplugin nur dann nutzen kann wenn da keine dynamischen Plugins drinhängen die auf PHP-Basis laufen und dann nicht mehr ausgeführt werden. Dazu würden Dinge wie Klickzähler, API-Aufrufe á la Flickr, Twitter etc. zählen. Das simplecache-Plugin ignoriert sowas sozusagen vollständig.

Schwer ist halt auch herauszufinden, ob eine Seite irgendwelche Abhängigkeiten in der URL oder so enthält; simplecache geht einfach alle GET-Parameter und die Stamm-URL durch, das sorgt halt potentiell dafür dass extrem viele URLs/Daten gecacht werden, sobald Benutzer anfangen da Parameter einzubasteln...

Auch das individuelle invalidieren ist schwierig, wenn man bei jedem DB-Write ALLE Caches löscht kostet das sehr viel Power; und ohne viel genauere introspection kriegt man nicht raus, welche DAten man gezielt invalidieren müsste....
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
onli
Regular
Posts: 2724
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Caching: Aktueller Stand?

Post by onli »

Mir war nicht klar, dass das mit dem powercache so lange her ist. Dachte, das wäre 1.5 gewesen. Hm.
Mein Hauptproblem ist halt, dass man so ein Cachingplugin nur dann nutzen kann wenn da keine dynamischen Plugins drinhängen die auf PHP-Basis laufen und dann nicht mehr ausgeführt werden
Ja. Das ist bei mir kein Problem, weil ich kein solches nutze, aber klar dass s9y bestenfalls die Möglichkeit trotz cache bieten soll. Dass mit den Parametern finde ich nicht schlimm, solch ein Angriff sollte ja eher selten vorkommen. Für manche Seiten wäre es durchaus eine Option, wenn ein optionaler Cache solche Features zerstört.

Könnte man für den Cache + Plugins nicht in der genpage.inc.php ansetzen und entweder die normale serendipity_printEntries aufrufen, die dann ihr Ergebnis cached, oder eine serendipity_printEntriesSemiCached, die dann zwar nicht mehr selbst die Datenbank abfragt - sondern den Cache nutzt - aber noch die hooks für solche Plugins ausführt? Wäre natürlich teils problematisch, diesen hooks dann die richtige Daten zu geben.

Selbst wenn das funktioniert bleibe immer noch das Problem der Cache-Invalidation.
Invalidieren muss nicht löschen heißen. Die Cachedateien könnten durchaus einfach in templates_c/ verbleiben und einfach nur nicht mehr genutzt werden. Sonst hast du recht, alle zu löschen kostet zuviel.
Abgesehen davon bin ich gar nicht so sicher, dass ein genaueres Abschätzen unmachbar ist. Kommentare sind nur unter einem Eintrag, abgesehen von der /comments-view und dem recentcomments-sidebar-plugin.
Einträge dagegen sind wirklich problematisch, weil die ja auf der Eintragsseite, im Archiv, in Kategorienübersichten, in Tagübersichten und natürlich auf der Startseite sein könnten. aber dafür werden die seltener geschrieben und bei ihnen wäre eine komplette Cache-Invalidation einfacher vertretbar.

PS: Sehe jetzt, warum das alleine keinen Spaß machte. Potentiell ein tiefer Eingriff ins System mit viel Testbedarf.
Timbalu
Regular
Posts: 4598
Joined: Sun May 02, 2004 3:04 pm

Re: Caching: Aktueller Stand?

Post by Timbalu »

Sagt mal.... kommt hier nicht auch eventuell die neue Smarty Cache Option ins Spiel?

Nicht das ich damit viel Erfahrung hätte, aber die lässt sich meines Wissens sogar feintunen, wenn man die Smarty 3 Inheritance Möglichkeiten nutzt, so a la

Code: Select all

$smarty->caching = true; 

but not caching blocks in tpl

{nocache}
<form>
....
</form>
{/nocache} 

or 
{include file="a.tpl" nocache} vs {include file='b.tpl' inline}

or in php assigning single elements

$smarty->assign("adresse_value", $data['adresse'], true); 
Oder spielt sich die powercache/simplecache Geschichte auf einer anderen Ebene ab?
Regards,
Ian

Serendipity Styx Edition and additional_plugins @ https://ophian.github.io/ @ https://github.com/ophian
garvinhicking
Core Developer
Posts: 30020
Joined: Tue Sep 16, 2003 9:45 pm
Location: Cologne, Germany
Contact:

Re: Caching: Aktueller Stand?

Post by garvinhicking »

Hi!

Den Smarty3-Cache könnte man sicher auch nutzen, müsste dann aber wenn man das pauschal aktiviert ganz schön viel Arbeit investieren alle Funktionen durchzutesten um die Auswirkungen abzuschätzen. Cooler wäre es also nicht mit {nocache} zu arbeiten, sondern eher mit {cache}. Aber auch dann müsste man alle TPL Dateien überarbeiten und könnte nicht template-unabhängig etwas basteln.

Ich glaube daher eine Pluginlösung wäre die komfortablere für Blogger, sonst müssten die alle auch ein Template immer anpassen, und wie gesagt wir ewig gucken was z.b. das für auswirkungen im Backend mit sich zieht...

simple/powercache setzt oberhalb von Smarty auf, also auf den Ergebnissen die Smarty produziert.

Grüße,
Garvin
# Garvin Hicking (s9y Developer)
# Did I help you? Consider making me happy: http://wishes.garv.in/
# or use my PayPal account "paypal {at} supergarv (dot) de"
# My "other" hobby: http://flickr.garv.in/
onli
Regular
Posts: 2724
Joined: Tue Sep 09, 2008 10:04 pm
Contact:

Re: Caching: Aktueller Stand?

Post by onli »

Ich hab mal ein bisschen rumprobiert. Wenn man Caching im Code verankern, aber trotzdem dynamische Plugins zulassen wollte, könnte man das in etwa so versuchen:

In der genpage.inc.php wird erst der cache geprüft und sonst die normale Funktion aufgerufen:

Code: Select all

// Welcome screen or whatever
        default:
            if (! serendipity_printEntriesCached(serendipity_fetchEntries(null, true, $serendipity['fetchLimit']), $extended = 0, $preview = false, $smarty_block = 'ENTRIES', $smarty_fetch = true, $use_hooks = true, $use_footer = true, $use_grouped_array = false, $use_cache = true) ) {
                serendipity_printEntries(serendipity_fetchEntries(null, true, $serendipity['fetchLimit']), $extended = 0, $preview = false, $smarty_block = 'ENTRIES', $smarty_fetch = true, $use_hooks = true, $use_footer = true, $use_grouped_array = false, $use_cache = true);
            }
            break;
Die normale serendipity_printEntries füllt am Ende den Cache:

Code: Select all

if ($use_cache) {
        @include_once 'Cache/Lite.php';

        if (!class_exists('Cache_Lite')) {
            #$this->debugMsg('Cache_Lite not available.');
            return false;
        }

        $options = array(
            'cacheDir' => $serendipity['serendipityPath'] . 'templates_c/',
            'lifeTime' => 3600,
            'hashedDirectoryLevel' => 2
        );

        $cache = new Cache_Lite($options);

        $args = func_get_args();
        $args = array_values($args);
        $key = md5(serialize($args)); 
        $cache->save(serialize($dategroup), $key, "printEntries");
    }
    unset($entries, $dategroup);
} // end function serendipity_printEntries
Und die serendipity_printEntriesCached holt den Cache und simuliert die hooks:

Code: Select all

function serendipity_printEntriesCached($entries, $extended = 0, $preview = false, $smarty_block = 'ENTRIES', $smarty_fetch = true, $use_hooks = true, $use_footer = true, $use_grouped_array = false, $use_cache = false) {
    global $serendipity;
    
    echo "serendipity_printEntriesCached";
    
    echo "fetch cache";
    @include_once 'Cache/Lite.php';

    if (!class_exists('Cache_Lite')) {
        #$this->debugMsg('Cache_Lite not available.');
        return false;
    }

    $options = array(
        'cacheDir' => $serendipity['serendipityPath'] . 'templates_c/',
        'lifeTime' => 3600,
        'hashedDirectoryLevel' => 2
    );

    $cache = new Cache_Lite($options);

    $args = func_get_args();
    $args = array_values($args);
    $key = md5(serialize($args));
    echo "key: $key";

    if (($dategroup = $cache->get($key, "printEntries")) !== false) {
        $dategroup = unserialize($dategroup);
        $serendipity['smarty']->assign('entries', $dategroup);

        #now let plugins do their magic and hope they don't do it twice
        foreach($dategroup as $dategroup_idx => $properties) {
            foreach($properties['entries'] as $x => $_entry) {
                $addData = array('from' => 'functions_entries:printEntries');
                if ($entry['is_cached']) {
                    $addData['no_scramble'] = true;
                }
                serendipity_plugin_api::hook_event('frontend_display', $entry, $addData);

                $entry['display_dat'] = '';
                serendipity_plugin_api::hook_event('frontend_display:html:per_entry', $entry);
                $entry['plugin_display_dat'] =& $entry['display_dat'];
            }
        }

        
        if (isset($serendipity['short_archives']) && $serendipity['short_archives']) {
            serendipity_smarty_fetch($smarty_block, 'entries_summary.tpl', true);
        } elseif ($smarty_fetch == true) {
            serendipity_smarty_fetch($smarty_block, 'entries.tpl', true);
        }
        return true;
    } else {
        return false;
    }
    
}
Cache-Invalidation ginge im Zweifel erstmal mit Cache_Lite::clean, oder der key wird angepasst, evtl. um die Anzahl der Einträge und Kommentare ergänzt?

Ja, das ist nicht trivial und stimmt, da fehlen noch Daten, die gecached werden müssten. Aber grundsätzlich könnte das funktionieren. Im Falle eines Cache-Hits spart man die Datenbankabfrage (vorausgesetzt, fetchEntries cached äquivalent) und einen Haufen Logik.

PS: Was genau cached der Smarty-Cache? Speichert er die aus dem PHP-template-Code generierte Seite, oder geht es um die Erstellung des PHP-template-Codes selbst? Letzteres wäre ja egal, ersteres hätte dann wieder das Problem mit den Hooks.
Timbalu
Regular
Posts: 4598
Joined: Sun May 02, 2004 3:04 pm

Re: Caching: Aktueller Stand?

Post by Timbalu »

onli wrote:PS: Was genau cached der Smarty-Cache? Speichert er die aus dem PHP-template-Code generierte Seite, oder geht es um die Erstellung des PHP-template-Codes selbst?
Caching is used to speed up a call to display() or fetch() by saving its output to a file. If a cached version of the call is available, that is displayed instead of regenerating the output. Caching can speed things up tremendously, especially templates with longer computation times. Since the output of display() or fetch() is cached, one cache file could conceivably be made up of several template files, config files, etc.

Since templates are dynamic, it is important to be careful what you are caching and for how long. For instance, if you are displaying the front page of your website that does not change its content very often, it might work well to cache this page for an hour or more. On the other hand, if you are displaying a page with a timetable containing new information by the minute, it would not make sense to cache this page.

With caching enabled, the function call to display('index.tpl') will render the template as usual, but also saves a copy of its output to a file (a cached copy) in the $cache_dir. On the next call to display('index.tpl'), the cached copy will be used instead of rendering the template again.
Regards,
Ian

Serendipity Styx Edition and additional_plugins @ https://ophian.github.io/ @ https://github.com/ophian
Post Reply