Magentoperformance

Performanceprobleme bei Magento erkennen, analysieren und beheben

22. März 2012
von Sebastian
Keine Kommentare

Schneller Import von konfigurierbaren Produkten

Als ich vor kurzem für einen Kunden seinen Produktstamm von über 120.000 Tausend Produkten in einen neuen Magento Shop importieren sollte, bin ich wieder mal an die Grenzen von Magento gestoßen.

Jeder, der bereits einmal die hauseigene Import-Funktion von Magento genutzt hat, weiß, dass ein Import – je nach verwendeter Hardware – auch mal zwei Sekunden pro Produkt benötigt. Außerdem war es die Anforderung des Kunden, seine auf mehrere CSV-Dateien verteilten Produkte als konfigurierbare Produkte zu importieren, da je nach Variante unterschiedliche Preise möglich sein mussten.

Wie sich im Nachhinein herausstellte, musste der Produktstamm mehrmals importiert werden, da immer wieder Änderungen an den Produktdaten übernommen werden mussten. Daher war es die Richtige Entscheidung, einen eigenen Import zu schreiben. Dieser war zugegebenermaßen auf diesen Einzelfall zugeschnitten, an Performance dann aber auch kaum zu überbieten.

Vorweg: Am Ende brauchte der selbst entwickelte Importer nicht circa zwei Sekunden pro Produkt, sondern schaffte pro Sekunde circa 20 (konfigurierbare) Produkte!

Die Umsetzung erfolgte am Magento-Core vorbei und fügt die Produkte “von Hand” in die Datenbank ein. Um dabei alle Attribute, Verknüpfungen und Abhängigkeiten zu berücksichtigen, habe ich zuerst die Attribut-Tabellen inklusive der möglichen Attributwerte geladen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// $_p ist hier ein beliebiges bestehendes Produkt im Shop
// Dieser weg vereinfacht es an die Produktattribute heran zu kommen
// ATTRIBUTDATENBANK AUFBAUEN
// ATTRIBUTDATENBANK AUFBAUEN
$_pa = $_p->getTypeInstance($_p)->getEditableAttributes($_p);
$_a = array();
$_av = array();
$_tables = array();
 
foreach($_pa AS $_ak=>$_ao)
{
	$_a[$_ak] = array("id"=>$_ao->getId(),"code"=>$_ak,"table"=>$_ao->getBackendTable(),"type"=>$_ao->getFrontendInput(),"source"=>$_ao->getSourceModel(),"label"=>$_ao->getFrontend()->getLabel());
	$_av[$_ao->getId()] = array();
 
	if(!in_array($_ao->getBackendTable(), $_tables))
	{
		$_tables[] = $_ao->getBackendTable();
	}
}
 
// ATTRIBUTWERTDATENBANK AUFBAUEN
$results = $read->fetchAll("SELECT eao.option_id AS oid, eao.attribute_id AS aid, eaov.store_id AS sid, eaov.value AS v FROM eav_attribute_option AS eao, eav_attribute_option_value AS eaov WHERE eao.option_id = eaov.option_id");
foreach($results AS $r)
{
	if(!isset($_av[$r["aid"]]))
	{
		$_av[$r["aid"]] = array();
	}
 
	$_av[$r["aid"]][$r["oid"]] = array("s"=>$r["sid"],"v"=>$r["v"]);
}

Danach wurden die Produktoptionsdatenbank und der Kategoriebaum geladen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// PRODUKTOPTIONSDATENBANK AUFBAUEN
$results = $read->fetchAll("SELECT CONCAT(entity_id,'##',attribute_id) AS k, value FROM catalog_product_entity_int");
$_po = array();
foreach($results AS $r)
{
	$_po[$r["k"]] = $r["value"];
}
 
// KATEGORIEDATENBANK AUFBAUEN
$rootId = $store->getRootCategoryId();
$_cache = array();
$_categoryCache = array();
 
if (!$rootId) {
    return array();
}
$rootPath = '1/'.$rootId;
if (empty($_categoryCache[$store->getId()])) {
    $collection = Mage::getModel('catalog/category')->getCollection()
        ->setStore($store)
        ->addAttributeToSelect('name');
    $collection->getSelect()->where("path like '".$rootPath."/%'");
 
    foreach ($collection as $cat) {
        $pathArr = explode('/', $cat->getPath());
        $namePath = '';
        for ($i=2, $l=sizeof($pathArr); $i<$l; $i++) {
            $name = $collection->getItemById($pathArr[$i])->getName();
            $namePath .= (empty($namePath) ? '' : '/').trim($name);
        }
        $cat->setNamePath($namePath);
    }
 
    $cache = array();
    foreach ($collection as $cat) {
        $cache[strtolower($cat->getNamePath())] = $cat;
        $cat->unsNamePath();
    }
    $_categoryCache[$store->getId()] = $cache;
}
$cache =& $_categoryCache[$store->getId()];

Es ist nötig diese Daten alle vorher zu laden um zum Beispiel Produkte in bestehende Kategorien einzufügen und um keine Duplikate in den Attributtabellen zu erhalten.

Nun kann mit dem eigentlichen Import begonnen werden.

Zuerst wird überprüft, ob es die Zielkategorie für das Produkt im Shop bereits gibt. Da der Kategoriebaum bereits so gut wie vollständig war, habe ich eventuell fehlende Kategorien per Magento-Core eingefügt. Hier spielte die Geschwindigkeit also keine große Rolle.

Ab jetzt können die Produktdaten selber per SQL direkt in die Datenbank geschrieben werden. Dabei waren Einträge in folgende Tabellen notwendig:

  • catalog_product_entity (inkl der zugehörigen Datentyp-Tabellen)
  • catalog_product_enabled_index
  • catalog_category_product
  • catalog_category_product_index
  • catalog_product_super_attribute
  • catalog_product_super_attribute_label
  • catalog_product_super_attribute_pricing
  • catalog_product_super_link
  • cataloginventory_stock_item
  • cataloginventory_stock_status
  • catalog_product_website
  • eav_attribute_option
  • eav_attribute_option_value

Bei der Menge an zusammenhängenden Inserts pro Produkt ist es wichtig das in einer Datenbanktransaktion zu bündeln, da bei Problemen ansonsten eine Menge Datenmüll in den Tabellen zurück bleiben kann.

Weitere Performancesteigerungen lassen sich beim Import durch “Multiple Inserts” und den Betrieb des Import-Scripts direkt auf dem Server, der auch die Datenbank hostet, erreichen.

Auch wenn ich den kompletten Sourcecode hier nicht veröffentlichen kann, so hat man anhand des Artikels trotzdem einen guten Start wenn man vor ähnlichen Problemen steht.

4. Januar 2012
von Sebastian
Keine Kommentare

“sales_flat_quote” Tabelle zu groß

Mit diesem Blogeintrag möchte ich hier eine neue Kategorie im Magento Performance-Blog eröffnen: die Alltagsprobleme. Kleine Codeschnipsel oder Tipps die zwischendurch hilfreich sein können. Der Großteil der Einträge in dieser Kategorie werden wahrscheinlich direkten Bezug zu Problemen stehen vor denen ich in dem Moment stehe. Ich hoffe das ich damit ein paar Gleichgesinnten helfen kann.

Los geht’s mit einem teilweise etwas langsamen Shop und meinem Kollegen aus der Technik-Abteilung der mich auf eine relativ große Datenbank in einem Magento-Shop aufmerksam machte. Das auf allen unseren Servern übliche nächtliche Backup der MySQL Datenbank betrug stattliche 1,5GB.

Da der Shop auf einer etwas älteren Magento-Version basiert, sind dort leider noch nicht so viele Aufräum-Cronjobs integriert wie es in den aktuellen Versionen der Fall ist.

Die üblichen Verdächtigen – nämlich die “log_XXX” Tabellen – waren in diesem Fall aber nicht die Schwergewichte. Scheinbar legten die unterschiedlichsten Suchmaschinen-Crawling-Bots gerne, und häufig irgendwelche Produkte in den Warenkorb des Shops, was die Tabellen “sales_flat_quote” und “sales_flat_quote_address” enorm anwachsen ließen. Jeweils ca 1,6 Millionen Einträge beinhalteten diese.

Da Magento diese scheinbar nicht selbst aufräumt habe ich dort mit einem nächtlichen Cronjob abhilfe geschaffen:


// Magento Core includieren und initialisieren
require_once './app/Mage.php';
Mage::app('admin');

// Datenbank-Objekt erstellen
$write = Mage::getSingleton('core/resource')->getConnection('core_write');

// Alle Einträge aus der 'sales_flat_quote' löschen die seit mindestens 4 Tagen nicht geändert wurden
$write->query("DELETE FROM `sales_flat_quote` WHERE updated_at < DATE_SUB(Now(),INTERVAL 4 DAY)");

Die “log_url_XXX”- und “log_visitor_XXX”-Tabellen können natürlich im gleichen Zug mit geleert werden. Das Ergebnis des kleinen Cronjobs ist übrigens eine auf ein sechstel reduzierte Größe des Datenbank-Backups.

Herausgefunden das es Suchmaschinen waren, habe ich übrigens anhand der Tabellenspalte “sales_flat_quote.remote_ip”. Eine whois-Abfrage der dort auftretenden IP-Adressen hat unter anderem Google und Baidu als “Täter” identifiziert.

18. November 2011
von Sebastian
2 Kommentare

Den Magento-Cache für eigene Module nutzen

Von Haus aus ist der Cache in der Standard-Installation bereits gut in das System integriert. Aber bei vielen Shops wird es nicht bei der Standardinstallation bleiben. Es kommen eigene oder Drittanbieter-Module hinzu. Da man bei Letzteren oft nicht weiß wie diese implementiert wurden, können solche Module  zum Beispiel durch aufwändige Datenbank-Operationen die Shop-Performance stark beeinträchtigen.

Muss nun ein bestehendes Modul beschleunigt werden oder steht eine Eigenentwicklung an? Hier ein paar Tipps:

Block-Caching für eigene Module einschalten / steuern:

Um dem eigenen Modul das bereits in Magento integrierte Block-Caching beizubringen ist nicht viel Arbeit notwendig:


public function __construct()
{
  parent::__construct();
  ...
  // In der Funktion __construct() des Moduls folgende Zeilen ergänzen
  $this->addData(array(
    'cache_lifetime' => 1800,
    'cache_tags'     => array("MYMODULE_BLOCK"),
    'cache_key'      => "MYMODULE_BLOCK_ONE"
  ));
  // Ende
}

“cache_lifetime” Gibt den Zeitraum (in Sekunden) an, in welchem das einmal erzeugte Template im Cache bleibt und nicht neu erzeugt wird.

“cache_tags” Anhand von Cache-Tags entscheidet Magento welche Blöcke vorzeitig aus dem Cache gelöscht werden müssen wenn sich zum Beispiel Produktdaten ändern. Mögliche, bereits in Magento verwendete Cache-Tags können im jeweiligen Modul nachgelesen werden. Um beim Beispiel der Produktdaten zu bleiben sollte im eigenen Modul dann folgender Cache-Tag verwendet werden: Mage_Catalog_Model_Product::CACHE_TAG

“cache_key” Anhand dieser ID sucht Magento den Block im Cache. Wenn es einen Cacheeintrag mit der ID findet wird dieser ausgeliefert, und der Block wird nicht noch einmal neu erzeugt.

ACHTUNG! Unbedingt darauf achten, dass hier eine eindeutige ID gewählt wird. Ansonsten werden eventuell falsche Blöcke an den Browser geschickt. Außerdem bedeutet ein fester Cache-Key, dass immer derselbe, bereits gecachte Block ausgeliefert wird. Egal ob beispielsweise im Shop-Frontend gerade ein Gast oder ein Bestandkunde die Seite anzeigt. Hat man also einen Block/Template das von anderen Faktoren, wie Kunden oder Produkten abhängt und anhand solcher Daten generiert wird ist hier höchste Vorsicht geboten. Je nach Funktionalität werden bestimmte Informationen Webseitenbesuchern angezeigt, die diese eventuell nicht sehen dürfen.

Magento-Collections anstelle von direktem SQL nutzen:

Ein allgemeiner Tipp:  Man sollte, besonders bei oft wiederkehrenden Abfragen immer die Magento-Collections und Ressource-Modelle für Datenbankabfragen nutzen. Magento legt bereits angeforderte Collection-Daten nämlich automatisch im Cache ab, was spätere Abfragen enorm beschleunigen kann.

Wenn kein Weg an direktem SQL vorbei führt, kann zumindest versuchst werden einzelne Berechnungsergebnisse oder ganze Datenbank-Antworten von Hand im Cache abzulegen.

Den Cache für eigene Daten nutzen:

Lassen sich eigene SQL-Abfragen oder sonstige zeitaufwendige Berechnungen nicht vermeiden, so kann man wiederverwendbare Ergebnisse auch selber im Cache ablegen:

...
$_cachekey = "MYMODULE_BERECHNETE_DATEN";
$_cachetags = array("MYMODULE_BERECHNETE_DATEN_CACHETAG");

// Magento Cache Object holen
$_cache = Mage::app()->getCache();

//liegen die Daten bereits im Cache?
if(!$_cache || !$_cache->test($_cachekey))
{
  // Daten nicht im Cache gefunden
  $_data = ... // Aufwendige Berechnungen

  if($_cache)
  {
    // Berechnungen im Cache sichern
    $_cache->save($data,$_cachekey,$_cachetags,null, 10)
  }
}
else
{
  // Daten im Cache gefunden
  $_data = $_cache->load($_cachekey);
}
...

Die Funktion “$_cache->save()” erwartet beim Aufruf folgende Parameter, von denen jedoch lediglich der erste verpflichtend ist:

  • Die zu cachenden Daten [mixed] (je nach Konfiguration kann es hier auch nötig sein die Daten bereits in serialisierter Form als String zu übergeben)
  • Ein Cachekey [string]
  • Die Cachetags [array([string])]
  • Die Cachezeit in Sekunden [integer]
  • Priorität der Daten [int, 0-10]
Weitere Erläuterungen finden sich in den Kommentaren zur Implementierung der Funktion in der Klasse “ZEND_CACHE_CORE” im Verzeichnis /lib/Zend/Cache/core.

3. November 2011
von Sebastian
Keine Kommentare

Den Magento Cache verstehen und einrichten

Im Idealfall wird ein Produkt in einem Onlineshop öfter vom Kunden angeschaut als vom Shopbetreiber bearbeitet. Oder anders gesagt: Es gibt mehr lesende als schreibende Zugriffe. Lesende Zugriffe sind natürlich schneller erledigt als schreibende, bei einem viel besuchten Shop ist das Erzeugen einer Produktseite mit allen Informationen dank der komplexen Datenbank-Struktur (EAV-Modell) aber dennoch eine aufwendige Operation.

In Magento sind aus diesem Grund unterschiedliche Beschleunigungs-Mechanismen eingebaut. Zum einen werden seitens der Datenbank zusätzlich zu den EAV-Tabellen noch Flat-Tabellen genutzt, auf die ich noch in einem zukünftigen Blogeintrag genauer eingehen werde. Zum anderen werden bereits erzeugte Ergebnisse wie zum Beispiel gerenderte HTML-Blöcke oder Sammlungsdaten (Collections) im Cache gesichert, damit diese bei späteren Abfragen schneller abgerufen werden können.

Nach dem Aufsetzen und Konfigurieren des Shops werden daher auch oft alle zu Verfügung stehenden Cache-Optionen in der Magento Administration aktiviert. Wird nun ein Datensatz im Cache abgelegt, erstellt Magento eine Datei mit den zu speichernden Daten im Ordner /var/cache . Da ein Abruf des Datensatzes dann aber immer noch ein Zugriff auf die Festplatte ist, hört die Performanceoptimierung hier natürlich nicht auf.

Neben diesem Dateisystemcache bietet Magento von Haus aus auch andere Caching-Backends. Genauer gesagt werden diese bereits vom in Magento verwendeten Zend-Framework bereit gestellt. Der Dateisystemcache ist hier nur die langsamste, dafür auf fast jeder Serverumgebung verfügbare Variante für das Caching.

Bei einigen stark frequentierten Shops für Kunden konnte ich auf das Memcache- oder das APC-Caching zurückgreifen. Hierfür mussten wir auf dem Webserver (alternativ auch extern) zuerst die Server-Module der jeweiligen Technologie installieren. Bei Memcache ist das ein Deamon-Prozess auf dem Server plus PHP-Modul, bei APC ist es nur ein zusätzliches PHP-Modul.

Ohne genauer auf die jeweilige Technologie einzugehen reicht hier denke ich die Aussage, das Memcache und APC die Datensätze im Arbeitsspeicher und nicht im Dateisystem ablegen. Der Performancegewinn ist hier also enorm.

Am Beispiel Memcache  möchte ich die notwendigen Einstellungen in Magento hier nun einmal durchspielen. Voraussetzung ist natürlich das entweder der Webhoster überhaupt einen Memcache-Server anbieten kann. Oder, wie in meinem Fall, das die firmeneigene Techik-Abteilung im Nachbarraum die Memcache-Einrichtung auf dem Server übernimmt.

1. Serverkonfiguration prüfen

Eine .php-Datei mit “phpinfo()” auf dem Server erstellen und prüfen ob das Memcache-Modul geladen wird. Es sollte ein Bereich ähnlich diesem zu finden sein:

Memcache auf der phpinfo()-Seite

Memcache auf der phpinfo()-Seite

Der zweite Schritt ist es zu prüfen ob der Memcache-Server läuft. Hier empfehle ich einfach direkt ein Monitoring-Tool zu installieren: http://code.google.com/p/phpmemcacheadmin

Clusteransicht des phpmemcacheadmin

Clusteransicht des phpmemcacheadmin

In der Konfiguration des phpmemcacheadmin muss lediglich die Adresse des Memcache-Servers eingetragen werden um eine umfangreiche Statistik über die Nutzung des Memcache-Servers zu erhalten.

2. Memcache in Magento einrichten

Vorweg  der Code für die /app/etc/local.xml

...
<cache>
 <backend>memcached</backend>
 <memcached>
  <servers>
   <server>
    <host><![CDATA[127.0.0.1]]></host>
    <port><![CDATA[11211]]></port>
    <persistent><![CDATA[1]]></persistent>
   </server>
  </servers>
  <compression><![CDATA[0]]></compression>
  <cache_dir><![CDATA[]]></cache_dir>
  <hashed_directory_level><![CDATA[]]></hashed_directory_level>
  <hashed_directory_umask><![CDATA[]]></hashed_directory_umask>
  <file_name_prefix><![CDATA[]]></file_name_prefix>
 </memcached>
</cache>
...

Dieser Code muss innerhalb des global-Tags eingebunden und konfiguriert werden. Speziell müssen der Host und der Port des Memcache-Servers eingetragen werden. Hier sind noch ein paar Konfigurationseinstellungen für den File-Cache integriert auf den Magento im Fehlerfall des Memcache zurückgreifen kann.

Prinzipiell sollte man solche Umbauarbeiten eh nur auf planmäßig offline genommen Shops oder Testsystemen vornehmen, dennoch gilt es folgendes zu beachten:

Man sollte man nicht direkt die Sessionverwaltung mit in den Memcache umziehen und unbedingt vor der Memcache-Konfiguration in Magento mindestens den Config-Cache deaktivieren. Funktioniert der Memcache-Zugriff nämlich nicht korrekt, hat man sich aus dem eigenen Shop-Backend ausgesperrt und das Entfernen des obigen Codes aus der local.xml schafft auch keine Abhilfe, da diese Einstellung wahrscheinlich noch irgendwo zwischengespeichert wurde.

Falls das doch einmal passieren sollte kann man in der Magento-DB in der Tabelle core_cache_option die einzelnen Cache-Typen von Hand deaktivieren. In älteren Magento-Versionen wurden diese Einstellungen noch in der Datei cache.ser im /app/etc Ordner gespeichert. Diese kann man einfach löschen und danach den Magento-Cache Ordner leeren.

Weitere mögliche Konfigurationen für das Caching finden sich in der von Magento mitgelieferten Beispieldatei /app/etc/local.xml.additional. Hier findet man Beispiele wie auch noch die Sessionverwaltung entweder in die Datenbank oder den Memcache-Server verlegt wird.

Hat alles funktioniert sollte sich das Magento-Grundsystem nun schneller “anfühlen”. Je nach Implementierung und gewähltem Shop-Design können die Geschwindigkeitszuwächse aber stark variieren.

Wie man auch Drittanbieter-Erweiterungen oder nachlässig erstellte Shop-Designs optimiert werde ich in einem der folgenden Blogeinträge behandeln.

13. Oktober 2011
von Sebastian
2 Kommentare

Magento Code-Profiling mit Xdebug

Im ersten Beitrag möchte ich mich hier mit der Optimierung der PHP-Ausführungszeit auf dem Server beschäftigen.

Magento ist zwar ein komfortables und flexibles System, aber die komplexe Struktur und die hohe Anzahl an Quellcode-Dateien fordern ihren Preis. Denn der Aufruf einer Katalogseite enthält nicht immer nur die Produkte der Kategorie, sondern eventuell auch andere Blöcke. Je nach Shopdesign können die Up/Cross-Selling- oder  ”Kunden die diesen Artikel gekauft haben.. “-Blöcke den Aufruf der Seite deutlich verlangsamen.

Besonders bei Shopdesigns von Dritt-Anbietern wurde da vielleicht nicht unbedingt auf Performance geachtet.

Wie findet man dort nun die paar Zeilen Code, die den Server in die Knie zwingen?

Die PHP Erweiterung Xdebug war für mich bisher das Hilfsmittel der Wahl! Dabei handelt es sich um einen Profiler der den kompletten Ablauf einer Serveranfrage aufzeichnet und als Trace-Datei ablegt. Unter anderem wird dabei jeder Funktions- und Unterfunktions-Aufruf mit der jeweils benötigten Ausführungszeit protokolliert. Die Einstiegstiefe in den Call-Stack reicht je nach Modulkonfiguration bis auf das Level der php-internen Funktionen herunter.

Um Xdebug zu verwenden muss dieses erst auf dem Server installiert werden (danke nochmal an unsere Technik Abteilung).

Ein paar Hinweise zu Xdebug-Konfiguration:

  • Der Config-Switch xdebug.profiler_enable_trigger=1 bewirkt das Xdebug nur den PHP-Aufruf aufzeichnet wenn der URL der Parameter XDEBUG_PROFILE angehangen wurde. Das ist in sofern sinnvoll, da ein Aufruf mit Xdebug den Seitenaufruf aufgrund des Loggings selber noch einmal verlangsamt. Mit dieser Einstellung kann man gezielter nur die Seiten analysieren die zu langsam sind.
  • Es ist irrelevant das Xdebug den Seitenaufruf noch weiter verlangsamt, da sich das Logging proportional auf alle Funktionsaufrufe in der Trace-Datei auswirkt. 
  • Je nach Magento Cache-Einstellungen, Shop-Design und gewählter Seite kann liegt nach dem Trace eine Log-Datei auf dem Server, die auch mal Dateigrößen im dreistelligen MB Bereich annehmen. Hier kann man pauschal schonmal sagen: Je kleiner, je besser ist das System bereits optimiert.
  • Es lohnen sich erstmal keine Trace-Aufzeichnung bei ausgeschaltetem Magento-Cache. Es sollte die Endkonfiguration getestet werden, die auch im Produktiv-System der Magento-Installation eingestellt ist.

Um die erzeugte Log-Datei zu analysieren bieten sich jetzt unterschiedliche Werkzeuge an. Ich persönlich nutze WinCacheGrind für Windows.

WinCacheGrind mit Magento Trace-File

WinCacheGrind mit Magento Trace-File

In der linken Spalte wird der vollständige Call-Stack des Seitenaufrufs dargestellt. Wählt man hier einen Knoten – welcher einem Funktionsaufruf entspricht – aus, werden rechts Funktionsaufrufe aufgelistet die innerhalb der gewählten Funktion passiert sind.

Das wirklich hilfreiche ist nun diese Liste nach der Spalte Cumulated zu sortieren. Dabei werden die Ausführungszeiten von jedem Aufruf inklusiver aller Aufrufe in Unterfunktionen aufsummiert, also des gesamten Call-Stacks ab dem Knoten bis hin zu den php-internen Funktionen.

Von hier aus kann man bequem tiefer in den Call-Stack eintauchen und die Performance-Bremsen finden. Aufgrund der komplexen Seitenaufruf-Struktur von Magento macht es Sinn sich den Page Request Flow vorher verinnerlicht zu haben.

 

15. September 2011
von Sebastian
Keine Kommentare

Los geht’s mit magentoperformance.de

Mit diesem Beitrag starte ich nun meinen Blog über das eCommerce Shopsystem Magento. Hauptsächlich wird es darum gehen, wie man das System beschleunigt. Die Kunden sollen schließlich kaufen und nicht darauf warten, dass der Online-Shop die Seite lädt.

Ich versuche hier Themen aus meiner täglichen Arbeit mit dem Shopsystem für die Allgemeinheit aufzubereiten. Dabei wird es nicht nur um Codeoptimierung am System selbst, sondern auch um Datenbank- und Server-Optimierung gehen.

Auch werde ich die Linkliste noch etwas ausbauen, wenn ich weitere interessante Blogs und Seiten zum Thema finde.