xt:Commerce Ramdisk Query-Cache

Heute hatte ich das zweifelhafte Vergnügen, an einem alten, aufgebohrten xt:Commerce Shop arbeiten zu dürfen. Der Server ist mit 16 GB Ram und einem starken Prozessor ausgestattet, aber trotzdem kommt es zu Lastspitzen bei denen der Apache und MySQL aussteigen. Die Lösung war relativ simpel, da die Hauptlast von den xx Suchanfragen pro Sekunde kam. Ein Cache musste her.

Code-Änderungen

Die Datei inc/exanto_cache.inc.php erstellen:

<?php
 
// Cache for 30 minutes
 
define('RAMCACHEDIR', DIR_FS_DOCUMENT_ROOT . 'cache/ramdisk/');
 
function exantoGetCacheFile(Array $hashStuff, $time = 1800) 
{
    $hash = md5(serialize($hashStuff));
    $path = RAMCACHEDIR . '/' . substr($hash, 0, 1) . '/' . substr($hash, 1, 2);
    if (! is_dir($path)) {
        mkdir($path, 0777, true);
    }
    $cacheFile = $path . "/$hash.ser";
    if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $time) {
        return array(
            'status'    => 'valid',
            'result'    => unserialize(file_get_contents($cacheFile)),
            );
    }
    return $cacheFile;
}

Diese Datei muß in der includes/application_top.php eingebunden werden, am Besten oben bei den Datenbank-Includes (~ Zeile 105):

require_once (DIR_FS_INC.'exanto_cache.inc.php');

Diese Funktion kann alles mögliche cachen, unter anderem auch die Produktlisten die von der Suchfunktion zurück gegeben werden. Die Datei ist includes\modules\product_listing.php:

/* :ORIGINAL:
$listing_split = new splitPageResults($listing_sql, (int)$_GET['page'], MAX_DISPLAY_SEARCH_RESULTS, 'p.products_id');
*/
// [start] :ADDED: exanto.de - Ramdisk Cache
$cacheFile = exantoGetCacheFile(array($listing_sql, (int)$_GET['page'], MAX_DISPLAY_SEARCH_RESULTS, 'p.products_id'));
if (is_array($cacheFile)) {
    $listing_split = $cacheFile['result'];
} else {
    $listing_split = new splitPageResults($listing_sql, (int)$_GET['page'], MAX_DISPLAY_SEARCH_RESULTS, 'p.products_id');
    file_put_contents($cacheFile, serialize($listing_split));
}
// [ end ] :ADDED: exanto.de - Ramdisk Cache

und

    if ($listing_split->number_of_rows > 0)
    {
        /* :ORIGINAL:
        $listing_query = xtDBquery($listing_split->sql_query);
        while ($listing = xtc_db_fetch_array($listing_query, true))
        {
            $rows ++;
            $module_content[] =  $product->buildDataArray($listing);
        }
        */
        // [start] :ADDED: exanto.de - Ramdisk Cache
        $cacheFile = exantoGetCacheFile(array($listing_split->sql_query));
        if (is_array($cacheFile)) {
            $module_content = $cacheFile['result'];
        } else {
            $listing_query = xtDBquery($listing_split->sql_query);
            while ($listing = xtc_db_fetch_array($listing_query, true))
            {
                $rows ++;
                $module_content[] =  $product->buildDataArray($listing);
            }
            file_put_contents($cacheFile, serialize($module_content));
        }
        // [ end ] :ADDED: exanto.de - Ramdisk Cache
    }

Ramdisk erstellen

Je nach Last und vorhandenem Ramspeicher muß die Ramdisk dimensioniert sein. In meinem Fall war Ram kein Problem, daher habe ich ein Gigabyte für die Ramdisk genommen. Der Eintrag in /etc/fstab lautet:

none    /var/www/xtc/cache/ramdisk  ramfs     defaults,user,size=1G,nr_inodes=10k,mode=0777     0     0

Nach einem sudo mount -a ist die Ramdisk eingebunden. Natürlich muß der obige Pfad angepasst werden, so daß die Ramdisk im Cache-Ordner des betreffenden xt:c Shopverzeichnisses erstellt wird.

Ramdisk aufräumen via Cronjob

Die veralteten Ergebnisse in der Cache-Datei werden überschrieben wenn die Suchabfrage erneut ausgeführt wird, aber viele Anfragen werden nie oder nur sehr selten wiederholt und belegen dann unnötig Speicherplatz. Daher habe ich noch einen Cronjob unter /etc/cron.d/cleanRamdisk erstellt, der alle 10 Minuten die veralteten Dateien löscht:

MAILTO=""
# Clean the ramdisk we use for SQL-Cache
*/10 * * * * www-data cd /var/www/xtc/cache/ramdisk;find . -cmin +40 -name '*.ser' | xargs rm

Fazit

Wenn alles richtig eingerichtet wurde, sollten unter cache/ramdisk Unterverzeichnisse auftauchen, in denen unter einem Hash gespeichert die Ergebnisse der Suchabfragen und anderer Produktlisten liegen. Dieser Cache macht sich besonders bemerkbar, wenn oft die gleichen Suchabfragen getätigt werden. In meinem Fall ging der Load sofort rapide zurück.

Getagged mit: , , , ,
3 Kommentare zu “xt:Commerce Ramdisk Query-Cache
  1. Clemens P. sagt:

    Ich habe zwar keine 16 GB Arbeitsspeicher zur Verfügung, werde aber deine Methode auch mal versuchen. Es nervt nämlich, dass jeden Tag der Server platt ist obwohl er eigentlich Stand halten sollte. Danke jedenfalls für die Veröffentlichung deiner Vorgehensweise!

  2. Chris sagt:

    dabei heißts dann aber auch dringendst das memory_limit im Auge zu behalten, da ja nicht mehr speicherschonend aus dem mysql-result gefetched wird, sondern der gesamte result in einen PHP-Array gezogen wird, auf jeden Fall mal die error Logs checken. Ist ein uralter „Bug“ aus xtcommerce queryCache Zeiten. Hatte schon dutzendfach Probleme bei Usern an genau dieser Stelle. Gruß Chris

  3. The solution was relatively simple, since the main result was obtained from queries in a few seconds.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.