Hier war in den letzten Monaten mal wieder Beitrags-Flaute, was vor allem daran liegt, dass ich seit etwa vier Monaten an einem Zend-Framework-Projekt entwickle und nur noch sporadisch mit Magento zu tun habe. Deshalb geht es auch heute nicht um Magento direkt, sondern um die Cache-Komponente von Zend Framework. Magento-Entwickler müssen jetz nicht gleich aufhören zu lesen, denn Zend_Cache bildet auch die Basis für den Cache in Magento.
Ein Cache besteht im Zend Framework immer aus einem Front- und einem Backend. Über das Frontend spricht die Anwendung den Cache an, übergibt Daten an den Cache, fordert Daten an oder deren Löschung. Das Cache-Backend kümmert sich um die tatsächliche Verwaltung der Daten. Daher gibt es für (fast) jede Speichermöglichkeit ein passendes Cache-Backend: Dateien (File), Datenbank (SQLite), Memcached (Memcached oder seit ZF 1.11 Libmemcached), APC und XCache. Varien hat Magento zusätzlich ein Cache-Backend für MySQL und eAccelerator spendiert. Wie dem aufmerksamen Leser natürlich schon aufgefallen ist, lassen sich die Backends in persistente und nicht-persistente Speicher unterteilen. Doch es gibt noch ein weiteres, wichtiges Unterscheidungsmerkmal: die Cache-Tag-Unterstützung. Mit Cache-Tags lassen sich Cache-Einträge gruppieren und z.B. gemeinsam konfigurieren oder löschen (Was Tags halt eben so tun). Die Cache-Verwaltung im Adminhtml von Magento greift genau darauf zurück: Cache-Tag-basiertes Aktivieren, Deaktivieren oder Löschen des Caches.
Die Crux an der Sache ist nun, dass die schnellen, nicht-persistenten Backends zumeist keine Tags unterstützen, während die langsameren, persistenten Backends dies meistens anbieten. An dieser Stelle kommt das Meta-Backend „Two Levels“ zum Einsatz. Das Two-Levels-Backend kann selbst nichts speichern, sondern arbeitet als Proxy für zwei andere Backends, ein Langsames (Slow Backend) und ein Schnelles (Fast Backend). Als Slow Backend wählt man nun ein persistentes Backend mit Cache-Tag-Support und als Fast Backend einen flüchtigen Speicher, gerne auch ohne Cache-Tag-Support. Der Two-Level-Cache versucht nun das Beste aus beiden Welten zu vereinen. Die Daten werden immer in beiden Caches abgelegt, doch der Leseversuch geht immer zuerst an den schnellen Cache. Wird ein Cache-Eintrag im schnellen Cache nicht gefunden, wird versucht den Eintrag aus dem langsamen Cache zu lesen und in den schnellen Cache zu übernehmen. Dadurch geht der Cache auch nicht verloren, wenn das System neu gestartet wird, da der schnelle Cache dann automatisch aus dem langsamen persistenten Cache aufgebaut wird. Auch die Tag-Unterstützung kann nun für den schnellen Cache emuliert werden. Dazu liest der Two-Level-Cache die Cache-IDs für den Tag aus dem langsamen Cache und spricht dann die IDs einzeln auf den Backends an.
Persistent | Tags | Schreiben1 | Lesen1 | |
---|---|---|---|---|
File | Ja | Ja | 761 | 1672 |
SQLite | Ja | Ja | 92 | 2686 |
Memcached | Nein | Nein | 1399 | 3575 |
Libmemcached | Nein | Nein | 2034 | 4851 |
APC | Nein | Nein | 7999 | 14987 |
XCache | Nein | Nein | N/A2 | N/A2 |
ZendPlatform | ? | Ja | N/A3 | N/A3 |
TwoLevels | Ja | Ja | 5344 | 112014 |
3005 | 33825 | |||
ZendServer_Disk | Ja | Nein | N/A3 | N/A3 |
ZendServer_Shm | Nein | Nein | N/A3 | N/A3 |
- Lese-/Schreibvorgänge pro Sekunde; AMD Athlon(tm) XP 1800+, 768 MB RAM, Debian GNU/Linux 6.0, PHP 5.3.3-7 with Suhosin-Patch (cli)
- XCache wird auf der Kommandozeile nicht unterstützt
- Zend Platform und/oder Server zu installieren war mir dann für den kleinen Benchmark doch zu aufwändig
- File + APC
- File + Libmemcached
Wie man in der Tabelle sieht, braucht der Two-Level-Cache beim Schreiben länger als das langsame Backend, da er auch noch den schnellen Cache schreiben muss. Auch beim Lesen, da erreicht er durch den Overhead nicht ganz die Geschwindigkeit des schnellen Caches. Die geringe Schreibgeschwindigkeit sollte nicht so sehr ins Gewicht fallen, da ein Cache im Normalfall deutlich häufiger gelesen als geschrieben wird. Und obwohl er nicht die Lesegeschwindigkeit des Fast Backends erreicht ist er der schnellste Cache mit Tag-Unterstützung.
Zu beachten sind zwei Konfigurations-Optionen, die einem durchaus den Spaß verderben können. Die erste Spaßbremse ist der automatic_cleaning_factor
für das Frontend. Dieser sollte in Verbindung mit dem Two-Level-Cache unbedingt auf „0“ gesetzt werden. Ansonsten werden abgelaufene Einträge aus dem Slow Cache automatisch entfernt (klingt doch gut, oder?). Der Nachteil ist allerdings, dass mit dem Eintrag auch die Tag-Informationen verschwinden. Daraufhin werden die Einträge im Fast Cache bei der Suche nach Tags nicht mehr gefunden und lassen sich nicht mehr Tag-basiert löschen.
Die zweite Option, die mit Vorsicht zu genießen ist, ist auto_refresh_fast_cache
für das Two-Level-Backend. Wenn aktiviert, wird der Fast Cache regelmäßig neu geschrieben, was unnötig ist, wenn der Cache groß genug ist, in meinen Benchmarks massiv Performance gekostet hat und bei APC auch reihenweise Fehler verursacht.
Falls jemand die Benchmarks auf seinem System nachvollziehen will, kann er den Benchmark-Quellcode und die vollständigen Ergebnisse herunterladen. Erforderlich ist ein aktuelles ZF (minimal reicht aus, > 1.11 für Libmemcached) und PEAR_Benchmark für den Timer.
0 Kommentare