Die Optimierung eines Magento Shops - ein durchaus heikles und schlecht zu kalkulierendes Thema. Seit circa einem Jahr häufen sich Anfragen von Kunden rund um das Thema „Optimierung eines Magento Webshops“. Entweder betreibt der Kunde bereits einen Shop, der aber nicht zu seiner Zufriedenheit funktioniert, oder dieser befindet sich gerade in der Entwicklung und der Kunde stellt fest, dass der Entwickler oder das Unternehmen mit der Umsetzung überfordert ist.
In den meisten Fällen wollen die Kunden wissen, was es kostet, den Shop entweder zu überarbeiten oder die Fertigstellung zu übernehmen. Unsere Antwort lautet in der Regel wie folgt:
Aufgrund der Komplexität des Systems und der schier unglaublichen Möglichkeiten, bei der Implementierung Fehler zu begehen, können wir in diesem Stadium keinen Preis nennen, sondern müssen uns den Shop oder das, was bereits existiert, genauer ansehen. In weiteren Gesprächen kristallisiert sich oft heraus, dass entweder die Performance den Erwartungen des Kunden nicht gerecht wird, oder aber die Funktionalität nur zum Teil fertiggestellt ist obwohl der geplante Zeithorizont bereits bei weitem überschritten wurde.
Im Großen und Ganzen kann man die Probleme, die aus Sicht eines Kunden den Start des eigenen Webshops verhindern, in zwei Kategorien unterteilen: Probleme bei der Performance oder fehlerhafte bzw. unvollständig implementierte Funktionalitäten. Unsere Vorgehensweise für Fälle dieser Art möchte wir im Folgenden anhand eines Fallbeispiels kurz erläutern.
Problemanalyse
Im ersten Schritt werden die Quelltexte des Shops vom Webserver des Kunden heruntergeladen und analysiert. Die Datenbank wird gedumpt und ein lokales Testsystem eingerichtet. Bereits einfaches Durchklicken reicht in vielen Fällen aus, um die Ursache der häufigsten Probleme zu finden.
Im nächsten Schritt werden die einzelnen Bereiche des Shopsystems genauer untersucht. Bei der Analyse wird das System grundsätzlich in die Templates mit den Blocks, den Controllern, den Models und letztendlich der Hardware sowie der entsprechenden Systemkonfiguration unterteilt. Viele bekannte Probleme, auf die nachfolgend näher eingegangen wird, treten immer wieder auf und können relativ schnell eingegrenzt und behoben werden.
Fast immer reicht es in einem ersten Schritt aus, die größten Missstände zu beheben, die Systemkonfiguration zu optimieren und den Shop updatefähig zu machen. Der Kunde, der häufig schon eine relativ große Summe investiert hat, kann somit zeitnah mit einem überarbeiteten und performanten System starten. Zusätzliche Verbesserungen können anschließend bequem über Extensions in den Shop integriert werden.
Performance des Shopsystems
Ein zentrales, bereits vom Kunden genanntes Problem bestand in den sehr schlechten Ladezeiten der Start- und der Katalogseiten. Häufig liest man in einschlägigen Foren, dass Magento gerade bei einer größeren Anzahl an eingestellten Artikeln Performanceprobleme bekommen würden. Lösungsansätze wie schnellere Server oder die Installation von Caching-Extensions findet man häufig als Antwort. In diesem Fall ist, meist nicht das System an der schlechten Performance schuld, sondern die Art und Weise, wie der Entwickler die Anforderungen des Kunden umgesetzt hat.
Templates & Oberfläche
Eine häufig aufzufindende Unschönheit ist in beinahe allen Shops die direkte Initialisierung eines Models im Template. Im Fallbeispiel enthielt beispielsweise das Template frontend/default/default/template/catalog/navigation/top.phtml folgenden Quellcode:
<?php $_menu = ''?>
<?php foreach ($this->getStoreCategories() as $_category): ?>
<?php $_menu .= $this->drawItem($_category) ?>
<?php endforeach ?>
<div class="nav-container">
<div class="nav-container-close"></div>
<div class="nav-wrapper">
<?php echo $this->getChildHtml('topSearch') ?>
<?php if ($_menu): ?><ul id="nav">
<?php echo $_menu; ?>
<?php $_glas = Mage::getModel('catalog/product')->load(5) ?>
<?php
$_categories = $_glas->getCategoryIds();
if (isset($_categories) && array_key_exists('0',$_categories)) {
$_category = Mage::getModel('catalog/category')->load($_categories[0]);
$url = $this->getUrl(str_replace('.html','',$_category->getUrlPath())).$_glas->getUrlKey().'.html';
} else {
$url = $this->getUrl($_glas->getUrlKey());
}
?>
...
</ul><?php endif; ?>
</div>
</div>
Dieses Template wird bei nahezu jedem Seitenaufruf aufgerufen, um die Navigation zu rendern. Der mit Magento ausgelieferte Inhalt des Templates sieht hingegen so aus:
<?php $_menu = ''?>
<?php foreach ($this->getStoreCategories() as $_category): ?>
<?php $_menu .= $this->drawItem($_category) ?>
<?php endforeach ?>
<?php if ($_menu): ?>
<div class="nav-container">
<ul id="nav">
<?php echo $_menu; ?>
</ul>
</div>
<?php endif; ?>
Um die Navigationseinträge zu laden, lädt der Entwickler in der Navigation ein Produkt mit der ID 5. Dieses ist fest im Template hinterlegt und somit nur für die aktuelle Shopkonfiguration funktionsfähig. So kann der Entwickler die URL über eine diesem Produkt zugeordnete und im System nicht sichtbare Kategorie zusammenzubauen und diese dem Navigationspunkt zuweisen. Die Funktion ist nur z. T. aufgeführt und geht im selben Stil weiter. Würde der Shopbetreiber das Produkt löschen, würde an Stelle der Startseite eine Fehlermeldung erscheinen. Die Zuweisung eines anderen Produkts kann nur durch die manuelle Anpassung des Quellcodes vom Entwickler vorgenommen werden, was mit relativ hohe Kosten verbunden ist und den Shopbetreiber zu einem gewissen Maß vom Entwickler der Funktionalität abhängig macht.
Maßgeblich für dieses Fallbeispiel soll jedoch sein, dass die vom Entwickler gewählte Lösung, die an sich schon relativ unschön ist, sicherlich nicht zur Verbesserung der Performance beiträgt. Aufgrund der in Magento implementierten Funktionalität zum Cachen von Blöcken wird das Template allerdings nach dem ersten Aufruf zwischengespeichert, wodurch die Performance nur dann negativ beeinflusst wird, wenn die Seite nicht im Cache vorliegt bzw. wenn dieser abgelaufen ist. Dazu jedoch später mehr.
Abgesehen von der eher schlechten Performance und vom ungewöhnlichen Lösungsansatzes für das Anlegen eines Navigationspunktes, der in nahezu allen Seiten benötigt wird, sollte das Laden von Daten schon allein aus Gründen der Übersichtlichkeit immer in der zum Template gehörenden „Block-Klasse“ und niemals direkt im Template vorgenommen werden.
Block Cache-Tags
Ein Thema, das von vielen Entwicklern vernachlässigt wird, aber dennoch für die Performance von zentraler Bedeutung ist, ist die bereits zuvor angesprochene Magento Funktionalität zum Caching von Blöcken.
Das Cachen eines Blocks kann entweder im Konstruktor durch direktes Setzen der Cache_Konfiguration als Array
protected function _construct() {
$this->addData(
array(
‘cache_lifetime’ => 120,
‘cache_key’ => $this->getProduct()->getId()
‘cache_tags’ => array(Mage_Catalog_Model_Product::CACHE_TAG)
)
);
}
oder durch direktes Überschreiben der Methoden
getCacheLifeTime();
getCacheTags();
getCacheKey();
spezifiziert werden.
Das Überschreiben der Methoden erlaubt eine etwas übersichtlichere Implementierung, gerade dann, wenn das Caching von mehreren Faktoren abhängig ist.
Über die cache_lifetime wird - wie der Name schon sagt - festgelegt, für welche Dauer in Sekunden ein einmal gecachter Block und das entsprechende Template bei einem erneuten Aufruf nicht nochmal geladen werden, sondern die gecachte Datei verwendet wird. Wird die cache_lifetime auf FALSE gesetzt, bleibt der Block solange im Cache, bis die entsprechende Datei im Verzeichnis var/cache gelöscht oder aber - und das ist die empfohlene Methode - der Blockcache über den Administrationsbereich geleert wird.
Über den cache_key wird dem Block ein eindeutiger Schlüssel innerhalb des Blockcaches gegeben. Dies ermöglicht eine wesentlich granularere Möglichkeit für das Caching. So wird es durch das Setzen von cache_key auf die Produkt ID beispielsweise möglich, eine Produktdetailseite für jedes Produkt separat zu cachen.
Über cache_tags kann eine Gruppe spezifiziert werden, zu der der gecachte Block gehört. Es kann z. B. festgelegt werden, dass beim Speichern eines Produkts auch der Cache für unseren Block gelöscht werden soll.
Eine ausführlichere Beschreibung der Möglichkeiten, die das Block-Caching von Magento zur Optimierung der Performance bietet, kann aus Gründen der Komplexität und des Umfangs nicht Bestandteil dieses Fallbeispiels sein. Einen Einstieg erhält der interessierte Entwickler jedoch über die Magento-WIKI1.
In unserem Fallbeispiel hat der Entwickler die Möglichkeit zum Cachen von Blöcken vollständig ignoriert. Nach Integration des Blockcaches, wie oben beschrieben, konnte die Performance des Magento Shops in den Kategorieseiten, wie aus der Tabelle Tabelle 1: Übersicht Performance ersichtlich, erheblich gesteigert werden.
JS und CSS Minifying und Zusammenführung
Performance-Optimierungen sind immer unter zwei Gesichtspunkten zu betrachten. Der eine messbare Gesichtspunkt besteht häufig in der Optimierung von Datenbank, Skripten und dem Einsatz von Caching-Mechanismen. Der andere Gesichtspunkt ist mehr subjektiv, da sich die Gesamtzeit für das Laden der Seite nur unwesentlich ändert, der Benutzer jedoch den Eindruck bekommt, dass sich die Seite wesentlich schneller aufbaut.
Den ersten Gesichtspunkt haben wir bereits zu Beginn des Artikels etwas näher beleuchtet. Wir werden dies auch später nochmal tun. Hier spielen neben der bereits angesprochenen Optimierung des Shopsystems auch die Hardware und die Serverkonfiguration eine große Rolle.
Für viele Kunden ist jedoch der subjektive Eindruck der Schnelligkeit eines Webseiten-Aufbaus ein viel wichtigerer Punkt. Hier spielen im Gegensatz zu den zuvor angesprochenen Themen völlig andere Faktoren eine wichtige Rolle. Ein zentrales Thema ist und bleibt der Einsatz von JavaScript. Ansprechende Oberflächen und Features, die inzwischen jeder Benutzer als selbstverständlich wahrnimmt, lassen sich in den häufigsten Fällen nur auf Basis von JavaScript umsetzen und werden durch den Browser des Benutzers auf dessen Rechner ausgeführt.
Wenn ein Benutzer die Webseite im Browser aufruft, werden folglich im ersten Schritt die serverseitigen Skripte abgearbeitet. Hierbei handelt es sich im Fall eines Magento-Shops um PHP. Nachdem der Server die PHP-Skripte entsprechend durchgearbeitet hat, schickt er das Ergebnis in Form von HTML-Code an den Browser des Benutzers zurück. Wurden der HTML-Code und die JavaScript-Dateien durch den Browser geladen, beginnt dieser mit der Ausführung der JavaScript-Dateien.
Allein die Anzahl der JavaScript-Dateien, die an den Browser der Benutzers übertragen werden, können für das Surferlebnis eine gewichtige Rolle spielen. Da ein Browser nicht alle Dateien parallel lädt, sondern abhängig vom verwendeten Browser immer nur eine gewisse Zahl, führt das Zusammenführen der verwendeten JavaScript-Dateien zu einer Datei in vielen Fällen dazu, dass der Besucher den Eindruck hat, die Seite würde schneller angezeigt werden. Gleiches gilt für die CSS-Dateien, die für die Formatierung der Seite notwendig sind.
Magento bringt bereits seit geraumer Zeit die Möglichkeit mit, alle eingesetzten JavaScript-Dateien vor der Übermittlung an den Browser zu einer Datei zusammenzuführen und somit die Anzahl der an den Browser zu übertragenden Dateien erheblich zu reduzieren.
In unserem Fallbeispiel reduziert sich alleine durch die Aktivierung dieser Funktionalität die Anzahl der zu übertragenden JavaScript-Dateien von 23 auf 11, der CSS-Dateien von 5 auf 2. Bevor die Funktionalität aktiviert wird, ist in jedem Fall ein ausführlicher Test notwendig, da in manchen Fällen Probleme auftreten können.
Handelt es sich um aufwändigere JavaScript-Dateien, kann es bei einem schwächeren Rechner und rechenintensiveren Funktionalitäten dazu kommen, dass die Seite zwar angezeigt wird, der Browser jedoch nicht reagiert. Auch ist es möglich, dass diese nur relativ langsam abläuft. Im Allgemeinen spricht man dann davon, dass der Browser „hängt“. Diese Problematik hängt unter Umständen vom verwendeten JavaScript-Framework oder von einer schlechten Implementierung ab. Da sich der JavaScript-Code in den meisten Fällen jedoch in verschiedenen Templates, im verwendeten Framework oder in anderen, mitgelieferten Dateien versteckt, sind Probleme in diesem Bereich oft relativ schwer zu lokalisieren und zu beheben.
In unserem Fallbeispiel konnten keine gravierenden Probleme ausgemacht werden, die den Start des Shops verhindern würden. Eine weiterführende Behandlung des Themas ist somit nicht erforderlich.
Systemarchitektur
Die Updatefähigkeit spielt für viele Kunden eine zentrale Rolle. Um die Updatefähigkeit gewährleisten zu können, spielen mehrere Faktoren eine bedeutende Rolle. Magento bietet einen Plug-In Mechanismus, über den der Shopbetreiber Erweiterung des Shops einspielen kann, ohne am Quellcode des Shops selbst etwas zu verändern oder diesen zu ersetzten bzw. zu entfernen. Im Fallbeispiel gestaltete sich die Aktualisierung dahingehend etwas schwieriger, dass der Shop mit dem Quellcode des Herstellers ausschließlich als Gesamtes übergeben wurde.
Es ist somit sehr aufwändig, zu überprüfen, ob am Kern des Shopsystems Änderungen vorgenommen wurden oder nicht. Da der Anbieter, also Magento selbst, Updates in Form von neuen Versionen bereitstellt, ist es jedoch essentiell sicherzustellen, dass keine Änderungen an der Kernfunktionalität vorgenommen wurden, da diese bei einer Aktualisierung verloren wären und nur mit relativ großem Aufwand wieder hergestellt werden können. Über den Magento Connect-Manager im Administrationsbereichs besteht theoretisch die Möglichkeit, den Shop auf die aktuellste Version upzudaten. Ohne dies aber zuvor auf einem Testsystem zu testen und die Funktionalität zu überprüfen, sollte das Update auf keinen Fall durchgeführt werden.
In unserem Fallbeispiel wurden im ersten Schritt deshalb alle Erweiterungen (im Sprachgebrauch Magento Extensions genannt), die durch den vorherigen Dienstleister implementiert wurden, von den Quellcodes des Shops separiert. Im aktuellen Fall entstanden somit einschließlich der Oberfläche neun separate Extensions. Um sicherzustellen, dass keine Fehler bei der Separierung in Extensions entstanden sind, wurde eine leere Magento-Instanz mit der gleichen Versionsnummer 1.4.0.1 sowie den Extensions der Drittanbieter über den Magento Connect-Manager installiert. Anschließend wurde die zusätzliche Funktionalität in Form der neun Extensions per PEAR über die Kommandozeile integriert. Nach dem Einspielen des Datenbankdumps und dem Verlinken des Media-Verzeichnisses mit den Bildern war der Shop wieder vollständig funktionstüchtig.
Im nächsten Schritt wurde eine neue Instanz mit der aktuellsten Version von Magento installiert und wie zuvor die Extension der Drittanbieter sowie die durch den Dienstleister implementierte Funktionalität installiert. Nach dem Einspielen des Datenbankdumps konnte dann durch einen Entwickler mit der Behebung von Kompatibilitätsproblemen der Extensions begonnen werden.
Funktionalität
In unserem Fallbeispiel wurde bei der Implementierung der Funktionalität offensichtlich teilweise nicht berücksichtigt, dass zum Erreichen der vom Kunden gewünschten Funktionen die Magento Standardfunktionalität ausgereicht hätte.
So wurde beispielsweise auf der Startseite über einen relativ komplexen Mechanismus eine pflegbare Teaserleiste integriert. Bei der Integration wurde zum einen die bereits zuvor angesprochene Caching-Funktionalität nicht berücksichtigt, sodass die Anzeige mit erheblichen Performance-Einbußen verbunden war. Zum anderen wurde durch den Dienstleister - aus welchen Gründen auch immer - nicht berücksichtigt, dass sich die Funktionalität relativ einfach durch das mitgebrachte CMS hätte realisieren lassen. Somit wäre die Performance des Systems nicht beeinträchtigt worden und der Kunde hätte sich durch die Nicht-Umsetzung der Funktionalität eine Menge Geld sparen können.
Wie im Fallbeispiel treffen wir in fast jedem Projekt dieser Art auf Funktionalitäten, die zum Teil aufwändig und damit teuer auf Kosten des Kunden entwickelt wurden. Diese hätten sich allerdings häufig relativ einfach mit Bordmitteln oder durch den Einsatz einer kostenlosen Extension, die sich in vielen Fällen direkt im Shop über Magento-Connect2 installieren lässt, realisieren lassen. Mit inzwischen rund 3.000 Extension steht für nahezu jede Anforderung mittlerweile ein Magento Modul parat. Eine recht guten Überblick über verfügbare Module finden Sie im übrigen unter www.mag-module.de.
Leider sind manche Magento Dienstleister entweder nicht gewillt, sich die notwendigen Gedanken zu machen, oder sie können der Versuchung nicht widerstehen, auf Kosten des Kunden überproportional zu verdienen. Es gehört aus unserer Sicht zur Pflicht einer guten Magento Agentur, den Kunden bestmöglich zu beraten, sich zu seinen Problemen entsprechend Gedanken zu machen und, wenn möglich, im Interesse des Kunden auf Extensions zu setzen, die bereits am Markt etabliert sind und sich im Einsatz in der täglichen Praxis bereits bewährt haben. Eine langfristige stabile Kundenbeziehung basiert für uns immer auf gegenseitiger Offenheit und Fairness.
Hardware
Das System wurde dem Kunden als Serverhardware mit einer Intel i7 CPU, 2 Kernen à 2.67 GHz verkauft. Dem System sollten angeblich 3 GB Arbeitsspeicher, eine 50 GB Festplatte und eine 100 MBit Netzwerk-Anbindung zur Verfügung stehen.
Für den Live-Betrieb eines Shopsystems auf Basis von Magento ist dies eine reichlich knapp bemessene Hardware- Ausstattung. Nach Überprüfung des Systems stellte sich heraus, dass es sich nicht um einen dedizierten Server, sondern um ein virtualisiertes System auf Basis von XEN handelte, was je nach Konfiguration des Hostsystems unter Umständen zu zusätzlichen Performanceeinbußen führen kann.
In unserem Fallbeispiel wurde dem Kunden empfohlen, auf ein speziell für den Einsatz von Magento optimiertes System umzusteigen. Durch den aktuellen Vertrag mit dem ehemaligen Dienstleister ist der Kunde jedoch gezwungen, das aktuelle System bis Mitte 2010 einzusetzen. Ein Wechsel kommt somit erst ab diesem Zeitpunkt in Frage. Einen Überblick über mögliche Magento Hoster finden Sie in einem vorangegangen Blobeitrag zum Thema Magento Hosting.
Serverkonfiguration
Bei der Serverkonfiguration handelt es sich um ein Debian 5.0 Standardsystem ohne spezielle Optimierungen für den Einsatz von Magento.
Wie MySQL und Apache wurde auch PHP5 nicht optimiert. Die einfachste Möglichkeit, eine Performancegewinn zu erzielen, stellt die Möglichkeit dar, eine Bytcode-Cache wie z. B. APC zu installieren. Auf einem Debian-System, wie in unserem Fallbeispiel eingesetzt, erfolgt die Installation der entsprechenden Software über die Kommandozeile mit
server@xen2:~$ apt-get install php5-apc
Wie aus Tabelle 1: Übersicht Performance ersichtlich, bringt bereits die simple Installation einen erheblichen Performance-Zuwachs. Durch eine Konfiguration des in Magento integrierten Cachesystems auf Basis von APC, z. B. für das Caching der Systemkonfiguration, lässt sich ein zusätzlicher Performance-Zuwachs erreichen.
Fazit
Durch die Überarbeitung des Shops konnte die Performance allein durch die Integration von Magento-Bordmitteln teilweise erheblich verbessert werden. Zusätzlich zu den messbaren Verbesserungen wurde durch die Aktivierung der Funktionalität zur Verbindung von JavaScript und CSS-Dateien eine subjektive Performancesteigerung aus Benutzersicht erreicht.
Zusätzlich wurde die Updatefähigkeit des Shops durch die genannten Überarbeitungen wiederhergestellt. Die einzelnen Funktionalitäten liegen nun als Extensions vor und können voneinander getrennt und sicher über die Kommandozeile des Servers aktualisiert werden.
Durch die Aktivierung des APC-Caches erhält der Shop auf Basis der verfügbaren Hardware nochmals einen durch Programmierung nur schwer zu erreichenden Performancezuwachs.
Die Testdaten wurden auf einem internen virtualisierten Testsystem auf Basis eines VMWare 2 Servers ermittelt. Sie sollen nur zur Veranschaulichung beitragen und aufzeigen, welche Auswirkungen die oben genannten Optimierungen auf das Gesamtsystem haben.
Auf einem optimierten dedizierter Server würden die Zugriffszeiten aller Voraussicht nach erheblich besser ausfallen. Die in unserem Fallbeispiel genannten Arbeiten nahmen alles in allem in etwa drei Wochen in Anspruch.
Leider gibt im Bereich der Optimierung eines Magento Shops keine pauschalen Aussagen. Hier verhält es sich wie bei einer Hausrenovierung - es kommt immer darauf wie die vorhandene Basis aussieht und wie viele "Überraschungen" auf einen warten. Es kann hier jedoch auch durchaus vorkommen, dass nichts mehr zu retten ist und die einzig vernünftige Lösung eine komplette Neuentwicklung ist oder - um bei unserem Renovierungbeispiel zu bleiben - Abriss oder vollständiger Neuaufbau. Dies ist in dem Moment dann zwar häufig sehr bitter, kann aber mittel- und langfristig gesehen durchaus Sinn machen....


0 Kommentare:
Kommentar veröffentlichen