Türchen 12: Magento Performance

Wichtig bei großen Projekten die eine hohe Besucherzahl erwarten und einen großen Artikelstamm besitzen ist, dass die zuständigen Entwickler das Model komplett kennen.
Das bedeutet auch das man sich mit dem Block-Cache-Model [1] beschäftigen sollte. Als Beispiel kann man die Artikel auf der Startseite nennen, diese sind oft die gleichen und können daher aus dem Cache geladen werden.

Als Beispiel kann man die Artikel auf der Startseite nennen, diese sind oft die gleichen und können daher aus dem Cache geladen werden.
Ebenfalls sollten FlatTables aktiviert werden und die Rewrite-URLs erstellen lassen ohne Kategorie Pfad.

Key-Facts

  1. 1. Magento 1.8.0.0, vorher 1.7.0.2
  2. 2. 1.5 Mio Artikel insgesamt
  3. 3. 50.000 Artikel Änderungen pro Tag

Nun zum eigentlichen Problem

Wir standen vor der Aufgabe einen Shop auf Basis von Magento zu erstellen mit einem Artikelstamm von 1.5 Mio. Artikeln, hinzukommen aber ca. 50.000 Artikel Updates pro Tag.

Als Import-Basis hatte sich meine Kollege Volker Thiel dazu entschieden das Modul AvS_FastSimpleImport zu verwendet, welches auf Mage_ImportExport aufbaut.
Das Parsen der Daten (XML) des ERP vom Kunden dauert im Schnitt 30 Minuten, der Import ohne Indexing dauert ca. 10 Minuten.

Wie die meisten schon vermuten, lag das Hauptproblem beim Indexer. Dieser lief jeden Tag
mehr als 6 Stunden und hat dazu geführt, dass Kunden im Shop nicht kaufen konnten („Lock wait timeout exceeded; try restarting transaction“).

Die Lösung dazu wurde im Issue-Tracker diskutiert und direkt über das Indexer Module gelöst. [3]
Durch diese Änderung läuft der Indexer nun maximal 1 Stunde (ab 3 Uhr), da der Shop auf den deutschen Markt ausgelegt ist, stellt dieses kein Problem da.

Nachdem die Probleme mit dem Indexer behoben wurden standen wir vor dem Problem, dass die Seiten beim ersten Aufruf ca. 10 Minuten gebraucht hat. Schnell ließ sich hier durch die Datenbank herausfinden, dass das Problem an der Navigation von Magento lag („MySQL: SHOW PROCESSLIST“). In einem Query für die Kategorien wird ein JOIN auf die REWRITE Tabelle gemacht (die core_url_rewrite-Tabelle enthält ca. 1.4 Mio Zeilen). Dadurch, dass in der Nacht immer Änderungen vorgenommen werden, musste der Index neu aufgebaut werden. Allerdings ist ein wichtiger Index ab Magento Version 1.5 nicht mehr enthalten ('category_id', 'is_system', 'product_id', 'store_id', 'id_path' ). Dieser Index brachte zwar eine deutliche Verbesserung, aber immer noch in einem inakzeptablen-Bereich ~3 Minuten.

Meine Lösung ist hierfür realtiv simple, es werden die Einträge der Kategorie URL-Rewrites in eine andere Tabelle kopiert und im JOIN statt auf die core_url_rewrite Tabelle auf meine neue Tabelle zugegriffen (Referenz: Mage_Catalog_Helper_Category_Url_Rewrite). Die Aufrufe liegen jetzt in einem so kleinen Bereich auf diese Tabelle, abfrage, dass selbst wenn die Daten nicht auf dem Cache kommen direkt geliefert werden.
Hier zu habe ich ein Modul geschrieben welches ebenfalls, die Kategorie Pfade für Artikel nicht mit Indexiert [3].

Zum Caching, anfangs hatten wir auch auf Redis [4] gesetzt, später und nach einigen Tests sind wir umgestiegen auf MongoDB [5] als Cache. Hier stißen wir auch auf ein kleines Problem, dass die veralteten Cache Daten nicht direkt gelöscht wurden. Dafür haben ich ein kleines Script geschrieben, welches dieses übernimmt.[6]

Zum Server

Es handelt sich um einen Dedicated Server mit Debian Wheezy amd64.
Als Webserver verwenden wir nginx und php-fpm.
PHP in der Version 5.3.27.
Als Opcache nutzen wir statt APC, Zend Opcache (ehemals ZendOptimizer+) [7].
Dieser war in unserem Test deutlich schneller als APC, wenn man trotzdem APC UserCache benötigt kann man sich APCu [8] anschauen.
Das MemoryLimit liegt default bei 128 M, im Checkout auf 512 M und im Backend bei 756 M.
Dieses sind jeweils eigene Prozessbereiche über PHP-FPM.
Als MySQL Server wurde MariaDB 5.5 verwendet.

Dedicated Server Hardware:

  1. Hexacore mit Hyper-Threading – 3,2 GHz
  2. 2x 2 Terabyte SW-RAID1
  3. 64 GB ECC-RAM
[1] http://www.webguys.de/magento/turchen-22-magento-block-caching/ [2] https://github.com/avstudnitz/AvS_FastSimpleImport/pull/63 [3] https://github.com/mklooss/Loewenstark_UrlIndexer [4] https://github.com/colinmollenhour/Cm_Cache_Backend_Redis [5] https://github.com/colinmollenhour/Cm_Cache_Backend_Mongo [6] https://gist.github.com/mklooss/7626105 [7] https://github.com/zendtech/ZendOptimizerPlus [8] https://github.com/krakjoe/apcu


Ein Beitrag von Mathis Klooß
Mathis's avatar

Mathis Klooss - In Kontakt mit Magento seit Anfang 2011 - Senior Entwickler bei der Löwenstark Web-Solutions GmbH. eCommerce Erfahrung/Berührung seit 2008; seit dem Oktober dieses Jahr Certificated Magento Developer.

Alle Beiträge von Mathis

Kommentare
Mathis am

@Vinai es war der Twitter eintrag von Collin, der uns dazu bewegt hat das ganze einmal zu testen: http://screencast.com/t/fAYiQIz0aj und auch unserer Tests trotz anpassung auch am Redis Server war im selben Bereich, was man natürlich erwähnen muss, ist, dass die MongoDB etwas mehr RAM verbraucht als REDIS, weshalb das nicht auf jedem Setup möglich ist.

@Rokko Varianten haben wir nur wenige, daher kann ich dazu nichts sagen, es wurden aber fast alle Module in dem Shop selber erstellt, dadurch haben wir einen besseren Überblick und unnötigen Overhead gekillt. Generell sollten bei großen Shops definitiv von Verschlüsselten Modulen abgeraten werden, da man einerseits nicht weiss was das Modul genau macht, andererseits OpCache aushebeln kann.

Rokko am

Hallo!

Vielen Dank für diesen Post! Es war wirklich mal interessant, einen Komplettüberblick von Performance-Strategien zu bekommen.

Ich hätte eine Anmerkung zu dem riesigen Artikelstamm von 1,5 Mio Produkten: Wir hatten einen ähnlichen Shop, bei dem die Artikel samt aller Varianten aus einer Schnittstelle kamen, und stießen wegen der Artikelstruktur (konfigurierbare Artikel mit teilweise tausenden Kindernartikeln) auf Performanceprobleme. Der Indizierungsprozess lief auch unvorstellbar lange und Artikeldetailseiten waren ungecachet unaktzeptabel.

Clustering, Memcached, Redis, Indizierungsplugins... Dies alles half, um die Ladezeiten erträglicher zu machen, aber meiner Meinung verschleiern diese Strategien nur die eigentlichen Probleme.

Was letztendlich half, war Bugfixing von eigenen und Drittmodulen (Beseitigen von performancelastigen Aktionen in Kategorie- und Produktseiten) und Aufräumen der Artikelstruktur. Die Schnittstelle wurde fallen gelassen, der Shop verkauft nun nur noch die Topseller und einige Konfigurationen wurden auf Custom-Option-Ebene realisiert oder gar als Konfigurator-Produkte umgesetzt.

Desweiteren kommt natürlich der bekannte Indexbug von Magento hinzu, der die core_url_rewrite-Tabelle ins unendliche wachsen lässt.

Dies sind meine Erfahrungen mit riesigen Katalogen. Der erste Schritt ist für mich immer, den Inhalt kunden- und Magentofreundlich aufzubereiten und anschließend in die Performance-Optimierung zu gehen.

Viele Grüße und schöne Weihnachten! Rokko

Vinai Kopp am

Vielen Dank für den spannenden Post! Kannst du noch ein paar der Sachen nennen, die Euch bewegt haben vom REDIS zum Mongo Cache Backend zu wechseln?

Dein Kommentar