PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


High Performance: Caching (reloaded) mit PHP

with 34 comments

Gastartikel von Oliver Sperke.

Ich bin 35 Jahre alt und seit 10 Jahren selbständiger Webentwickler. Mein Fokus liegt dabei auf der Erstellung, Beratung und Optimierung in den Bereichen High Performance, Usability und Sicherheit in den gängigsten Internetsprachen: PHP, HTML, Javascript und CSS.

Nach langem Arbeiten an einem Projekt fängt der ambitionierte Entwickler an, zu testen, wie sich seine dynamische Internetseite unter Last verhält. Da ja jeder von uns von Millionen Besuchern träumt, will man natürlich auch wissen, wie sich Millionen von Besucher anfühlen und ob unser „kleines Kunstwerk“ davon genau so begeistert wäre wie wir. Dynamische Webseiten sind toll, allerdings hat der gemeine Internetserver ein großes Problem damit. Die Erzeugung ist meist sehr aufwendig. Daten müssen aus Datenbanken geholt werden, Berechnungen wollen berechnet werden und Blogeinträge müssen wie Blogeinträge aussehen.

Seit Jahren hat sich eine simple Technik etabliert, die diese gequälten Webserver entlastet. Jeder fortgeschrittene Entwickler kennt und liebt sie, weil sie so schön einfach und universal einsetzbar ist: *trommelwirbel* Das Caching *tusch*. Da aber Caching an sich ein uralter Hut ist, will ich Euch zeigen, wie Ihr evtl. Eure Performance mit minimalen Änderungen mehr als verdoppeln könnt.

Am Anfang war der Benchmark

Nehmen wir als Beispiel eine ganz normale WordPress Installation mit dem üblichem Inhalt. WordPress ist umfangreich, es ist komfortabel, es ist leicht verständlich und es ist langsam. Da aber in den wenigstens Blogs sekündlich neue Beiträge und/oder Kommentare geschrieben werden, dafür aber häufige Aufrufe nicht unüblich sind, drängt sich uns hier das Caching geradezu auf. Natürlich gibt es einige gute Plugins dafür, die die verschiedenen Möglichkeiten des Cachings wunderbar abdecken. Aber um die soll es heute zur Abwechslung einmal nicht gehen. Ich will Euch ja nicht mit den „ollen Kamellen“ langweilen.

Um die Geschwindigkeit zu testen brauchen wir natürlich Hilfe in Form eines wunderbaren Programm Namens Apachebench. Dieses ist ein sehr einfach gehaltenes, aber mächtiges Kommandozeilenprogramm. Es macht im Prinzip nichts anderes als eine vorgegebene Seite immer wieder und wieder abzurufen. Dabei merkt es sich Start und Endzeitpunkt und berechnet daraus die Geschwindigkeit, mit der unsere Anfragen beantwortet wurden. Da wir immer noch mit dynamischen Daten arbeiten, starten wir einen ersten vorsichtigen Test. Wir rufen die index.php unserer WordPress Installation zunächst 1000 Mal (-n1000) auf mit je 4 parallelen Zugriffen (-c4). Ich habe 4 gewählt, weil mein Testsystem vier Prozessorkerne hat. So ist ständig jeder Prozessorkern beschäftigt. Die gesamten Daten des Testsystems findet Ihr am Ende des Artikels. Ich gebe bei der Ausgabe von Apachebench immer nur die wichtigen Daten an. Die gesamte Ausgabe ist natürlich umfangreicher.

ab -n1000 -c4 http://phpgangsta.x-blogs.org/
Server Software:        Cherokee
Server Hostname:        phpgangsta.x-blogs.org
Server Port:            80

Document Path:          /
Document Length:        18612 bytes

Concurrency Level:      4
Time taken for tests:   16.623 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      18990000 bytes
HTML transferred:       18612000 bytes
Requests per second:    60.16 [#/sec] (mean)
Time per request:       66.490 [ms] (mean)
Time per request:       16.623 [ms] (mean, across all concurrent requests)
Transfer rate:          1115.65 [Kbytes/sec] received

Was soll man da sagen? Glückwunsch, es ist langsam!

Machen wir es schneller

Wie es schon zu erwarten war, kommen wir mit unserem Standard WordPress nicht weit. Neben der lausigen Geschwindigkeit von 60 Zugriffen pro Sekunde waren während des gesamten Tests auch alle Prozessorkerne bis zum Anschlag ausgelastet. So macht also Bloggen für Millionen Leser keinen Spaß. Einfachste Lösungmöglichkeit – wir besorgen uns eines der o. g. Plugins, doch da lernen wir ja nichts draus, richtig? Wir wollen selber cachen und ausserdem können wir das bestimmt auch viel besser.

Als persistenten Speicher nehme ich APC. Dieses Zusatzmodul ist auf vielen PHP Webservern schon installiert, denn die Hauptaufgabe von APC ist es, PHP Code zu kompiliert und diesen im Arbeitsspeicher zu halten. So werden unsere PHP Scripte dramatisch beschleunigt. Alternativ funktionieren natürlich auch Memcache, alle Datenbanken oder einfache Dateien, in denen wir unsere Daten ablegen. Jede Variante hat seine Vor- und Nachteile. Memcache ist immer dann interessant, wenn man Daten auf mehrere Server verteilen muss, genau so wie Datenbanken, die aber überdimensioniert sind und einen hohen Overhead erzeugen. Dateien funktionieren auch ohne zusätzliche Installationen, sind aber recht langsam. APC ist von den genannten die schnellste Methode.

Da wir hier kein WordPress-Tutorial, sondern ein Performancetutorial machen, tun wir genau das, was man niemals tun sollte. Wir schreiben der Einfachheit halber in die Kerndateien von WordPress, in diesem Fall die index.php. Diese drängt sich geradezu auf, beschleunigt zu werden. Meine Modifizierung ist sehr einfach und stellt quasi ein Modell eines sehr sehr einfachen Caching dar. Keine Funktion, keine Klassen, Caching pur. Für die Praxis ist es damit natürlich nur eingeschränkt tauglich, denn es berücksichtigt ja in keinster Weise Änderungen durch neuen Beiträge oder Kommentare und unterscheidet auch nicht, ob ein Benutzer eingeloggt ist oder nicht. Das ganze System müsste um diese Abhängigkeiten erweitert werden. Trotzdem eignet es sich aber als Basis für Eure eigenen Experimente.

// CacheID
// Der Cache wird neu erstellt durch Änderung der vorstehenden Variable
$cacheid = 'cache' . md5($_SERVER['REQUEST_URI']);

// Sind Daten vorhanden?
if(apc_exists($cacheid) != false)
{
	// dann hole sie und zeige Sie auf der Seite und beende den Vorgang
	$output = apc_fetch($cacheid);
	echo $output;
	exit;
}

// Wir benötigen einen Ausgabepuffer
ob_start();

/** Loads the WordPress Environment and Template */
require('./wp-blog-header.php');

// Wir fangen die Ausgabe ab ...
$output = ob_get_contents();

// ... und vertrauen diese APC an
apc_store($cacheid, $output, 300);

Wiederholen wir den Test von oben. Die Performance sollte sich jetzt wesentlich verbessert haben. Die Daten werden einmal erzeugt und dann in den gemeinsamen Speicher von APC abgelegt. Weitere Aufrufe geben nur noch den Inhaltes des Caches wieder. Testen wir also noch einmal. Ab hier erhöhe ich die Anzahl der Abfragen (-n) auf 100.000, weil damit aussagekräftigere Werte entstehen.

ab -n100000 -c4 http://phpgangsta.x-blogs.org/
Concurrency Level:      4
Time taken for tests:   19.911 seconds
Complete requests:      100000
Requests per second:    5022.40 [#/sec] (mean)
Time per request:       0.796 [ms] (mean)
Time per request:       0.199 [ms] (mean, across all concurrent requests)

Okay, klarer Fall von Makro-Optimierung!

Machen wir es noch schneller

Bis hier hin dürften die meisten von uns schon einmal gekommen sein. Wir haben also die Geschwindigkeit unseres kleinen Blogs mit einfachsten Mitteln um den Faktor ~80 beschleunigt und könnten also Feierabend machen. Tun wir aber nicht, denn ein anderes großes Problem haben wir nämlich noch gar nicht bedacht. Eine Seite schnell zu generieren heißt nicht, dass sie auch schnell bei unserem Besucher ankommt. Dazu kommen noch mehr Faktoren. Eine der wichtigsten ist die Komprimierung des Textes vor der Ausgabe.

Wie man im ersten Test schon sah, ist unsere Startseite ungefähr 18 kb groß. Über GPRS oder unser gutes altes Kabelmodem wäre diese Seite satte 3 bis 4 Sekunden unterwegs. Das ist definitiv so lang, dass ein Benutzer genervt wegschalten könnte. Wenn wir Millionen Besucher haben möchten, dürfen wir aber auf dem Weg niemanden verlieren. Text-, bzw. html-Dateien sind gerade zu dafür erfunden worden, vor dem Versand komprimiert zu werden. Die Trafficersparnis beträgt meistens über 80%, da sich wiederholende Zeichen leicht zusammengepackt lassen. In PHP ist diese Funktion durch den ob_gzhandler auch sehr einfach umzusetzen. Also zurück zu unserer index.php und eine Zeile hinzufügen.

// Sind Daten vorhanden?
if(apc_exists($cacheid) != false)
{
	// Seiten vor der Ausgabe packen
	ob_start("ob_gzhandler");

	// dann hole sie und zeige Sie auf der Seite und beende den Vorgang
	$output = apc_fetch($cacheid);
	echo $output;
	exit;
}

Da Apachebench in der Standardkonfiguration dem Webserver nicht mitteilt, dass es auch mit der gepackten Version arbeiten kann, müssen wir unsere Befehlszeile etwas modifizieren. Mit dem Parameter -H können wir der abgefragten Internetseite zusätzliche Kopfdaten schicken und damit sagen, dass wir auch GZip sprechen und daher doch lieber das kleine Päckchen nehmen. Damit imitieren wir das Verhalten von richtigen Browsern. Diese sagen einer Internetseite mit jedem Aufruf, „Hallo, ich kann auch GZip“. Der ob_gzhandler erkennt dies und packt unsere Daten im Ausgabepuffer vor dem Versand. Die Größe der Datei sinkt – die Übertragung wird schneller. Doch was ist mit unserer Serverperformance?

ab -n 100000 -c 4 -H "Accept-Encoding: GZip" http://phpgangsta.x-blogs.org/
Document Length:        4844 bytes

Concurrency Level:      4
Time taken for tests:   41.272 seconds
Requests per second:    2422.94 [#/sec] (mean)
Time per request:       1.651 [ms] (mean)
Time per request:       0.413 [ms] (mean, across all concurrent requests)

Ein Testergebnis mit 8 Buchstaben: Resultat Verdammt! Positiv fällt uns natürlich sofort auf, dass die Seite auf ca. ein Viertel geschrumpft ist. Statt 3 bis 4 Sekunden würde ein Besucher mit kleiner Leitung nur noch weniger als 1 Sekunde warten. Eine wesentliche Verbesserung und kaum eine Chance, den Browser zu schliessen. Nur unsere wunderbare Performance hat sich dabei halbiert. Nichts mehr mit Millionen Besuchern, Frauen (oder Männern), Geld, Ruhm und noch mehr Frauen (oder Männern).

Die Reihenfolge macht’s

Preisfrage: Was würde passieren, wenn wir nicht die Ausgabe speichern und dann komprimieren, sondern erst komprimieren und dann speichern? An die Editoren! Zunächst einmal brauchen wir eine Funktion, die uns aus einer Textdatei eine GZip Datei macht. Mit der Funktion gzencode ist dies problemlos möglich. Unsere Datei muss dazu nur minimal geändert werden. Wir komprimieren die Ausgabe vor der Speicherung auf dem höchsten Faktor 9. Die Datei soll möglichst klein werden.

// und vertrauen diese APC an
apc_store($cacheid, gzencode($output, 9), 300);

Fehlt uns noch die Ausgabe. Diese bleibt an sich gleich, allerdings ersetzen wir unseren ob_gzhandler gegen den Content-Encoding header, den der Browser benötigt, um GZip Daten zu erkennen und entsprechend zu interpretieren. Ohne diese „Markierung“ würde er uns die Datei einfach im Fenster angezeigt werden, was bei komprimierten Dateien, sagen wir mal, schwierig zu lesen wäre. Wir wollen ja, dass unsere Millionen Leser auch wieder kommen. Denkt bitte auch daran die CacheID zu ändern oder 5 Minuten zu warten, sonst wird der alte Inhalt des Caches ausgegeben.

if(apc_exists($cacheid) != false)
{
	header('Content-Encoding: GZip');
	$output = apc_fetch($cacheid);
	echo $output;
	exit;
}
ob_start();

Alle Browser in freier Wildbahn unterstützen übrigens GZip-komprimierte Daten. Daher sollten auch standardmässig immer gepackte Daten ausgegeben werden. Für die wenigen Ausnahmen, bei denen dem nicht so ist, kann man folgenden Code verwenden. Dies erhöht zwar grundsätzlich die Serverauslastung, aber wie bereits erwähnt, dass ist die absolute Ausnahme.

if(!isset($_SERVER["HTTP_ACCEPT_ENCODING"]) || strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') === false)
{
	echo gzdecode($output);
	exit;
}

Unsere Daten werden nun komprimiert gespeichert und dann ohne weitere Bearbeitung, aber mit dem richtigen Kopfdaten an den Browser gereicht. Die Frage ist, wie verhält sich unser kleines Blog jetzt? Probieren wir es aus!

Concurrency Level:      4
Time taken for tests:   17.424 seconds
Complete requests:      100000
Requests per second:    5739.37 [#/sec] (mean)
Time per request:       0.697 [ms] (mean)
Time per request:       0.174 [ms] (mean, across all concurrent requests)
Concurrency Level:      10
Time taken for tests:   16.773 seconds
Complete requests:      100000
Requests per second:    5961.95 [#/sec] (mean)
Time per request:       1.677 [ms] (mean)
Time per request:       0.168 [ms] (mean, across all concurrent requests)
Concurrency Level:      100
Time taken for tests:   19.683 seconds
Complete requests:      100000
Requests per second:    5080.58 [#/sec] (mean)
Time per request:       19.683 [ms] (mean)
Time per request:       0.197 [ms] (mean, across all concurrent requests)
Concurrency Level:      1000
Time taken for tests:   24.064 seconds
Complete requests:      100000
Requests per second:    4155.55 [#/sec] (mean)
Time per request:       240.642 [ms] (mean)
Time per request:       0.241 [ms] (mean, across all concurrent requests)
Concurrency Level:      2000
Time taken for tests:   33.335 seconds
Complete requests:      100000
Requests per second:    2999.87 [#/sec] (mean)
Time per request:       666.696 [ms] (mean)
Time per request:       0.333 [ms] (mean, across all concurrent requests)

Wie man sieht, liegen die Anfragen pro Sekunde bei 2000 (!) parallelen Abfragen immer noch 20% über denen unserer ob_gzhandler Version. Im Normalbereich ca. 10 bis 20 % über denen ohne Komprimierung. Der Prozessor ist dabei übrigens noch weit weg von Totalauslastung. Dieses Verhalten ist auch vollkommen logisch. Kleineren Daten werden wesentlich schneller abgearbeitet. Sie werden schneller aus dem shared memory gelesen und verstopfen nicht unsere Netzwerkverbindung. Auch bei unrealistisch vielen parallelen Anfragen bricht die Performance messbar, aber nicht spürbar ein.

Fazit

Caching ist eine lohnenswerte Technik. Caching von komprimierten Daten ist eine noch viel lohnenswertere(re) Technik, vor allem im High Performancebereich oder auf Webservern, die eigentlich unterdimensioniert sind. Wenn Ihr diese Möglichkeit habt, nutzt sie und baut es in Euer bestehendes System ein.

Testsystem

Hardware:
- Intel Quad Core i5 CPU 750  @ 2.67GHz
- 6 GB Ram
- Software Raid 1

Software:
- Debian 6.0.3
- Cherokee Web Server 1.2.101
- PHP 5.3.8 (php-fpm)
- APC 3.1.9

Written by Oliver

Dezember 19th, 2011 at 9:46 am

34 Responses to 'High Performance: Caching (reloaded) mit PHP'

Subscribe to comments with RSS or TrackBack to 'High Performance: Caching (reloaded) mit PHP'.

  1. Mich würde ja interessieren ob es noch merklich was bringt wenn man den Cache nicht erst in den speicher schreibt?
    Also statt:
    $output = apc_fetch($cacheid);
    echo $output;

    So:
    echo apc_fetch($cacheid);

    Vielleicht dann aber eher beim Memory-Verbrauch?

    Aber allgemein natürlich schöner Ansatz. Und hat man keinen APC geht ja auch die „Variante für Arme“, die Daten in eine Datei zu schreiben.

    Florian Heinze

    19 Dez 11 at 10:07

  2. @Florian:

     Mit: Requests per second:    5475.90 [#/sec] (mean)
    Ohne: Requests per second:    5468.00 [#/sec] (mean)
    

    Nö. 🙂 Textdateien gehen natürlich auch, aber dabei erzeugt man jedesmal einen Zugriff auf die Festplatte, was es je nach Webserver recht lahm werden lassen kann.

    Oliver

    19 Dez 11 at 10:23

  3. @Oliver: Vielen Dank! Interessant. Vielleicht legt das APC das intern sowieso schon im PHP-Speicher ab und das ergibt dann nur ein copy-on-write (in diesem Fall als gar keinen write)?

    Florian Heinze

    19 Dez 11 at 10:35

  4. Schöner Artikel! Ein Jammer das APC nicht in jeder PHP-Standardinstallation dabei ist und nicht OO implementiert wurde.

    Daniel S

    19 Dez 11 at 10:38

  5. Oliver

    19 Dez 11 at 11:11

  6. @Oliver: Die Information mit PHP 5.4 und eingebautem APC ist falsch, es ist nicht mit drin. Es war zwar geplant in 2010 und als man PHP 6 erstmal zurückschob, aber in 5.4 wird es nicht enthalten sein.

    http://www.serverphorums.com/read.php?7,374842

    Michael Kliewe

    19 Dez 11 at 11:17

  7. @Michael
    Ok, war an mir vorbei gegangen die Info … 🙂

    Oliver

    19 Dez 11 at 11:20

  8. Bisher habe ich APC nicht im Einsatz. Birgt das eigentlich große Risiken das zu aktivieren?
    Und braucht die Kiste dann deutlich mehr Speicher?
    Bringt der viel Unterschied?

    Oder vielleicht anders: Hat wer ne schöne kurze Einführung? 😉

    Florian Heinze

    19 Dez 11 at 11:45

  9. @Florian
    Ich hab es auch verlinkt:
    http://2bits.com/articles/benchmarking-apc-vs-eaccelerator-using-drupal.html

    Die Prozessorbelastung sinkt gewaltig (Requests/second: 4.45 => 26.91). Da steht auch was zum Speicherverbrauch:
    http://2bits.com/articles/importance-tuning-apc-sites-high-number-drupal-modules.html

    Server memory usage dropped significantly too, because each Apache process just retrieves the op-code from APC’s cache rather than loading and parsing each Drupal module.

    Ich hab vor Jahren mal mit einer der ersten Versionen von eaccelerator mal Probleme gehabt, aber seitdem kein Problem mehr gehabt. Unter debian/ubuntu kannst Du es installieren mit apt-get install php5-apc. Da werden auch nicht gigabyteweise Daten in den Speicher geschaufelt, sondern nur die kompilierten Scripte. Selbst ein komplettes WordPress kommt da nur auf wenige MB. 🙂

    Oliver

    19 Dez 11 at 11:56

  10. Super Beitrag, ABER bitte nimm das EXIT raus und mach ein if/else Konstrukt daraus.

    Warum muss ich glaube ich nicht erklären….

    Martin Keckeis

    19 Dez 11 at 12:13

  11. @Oliver: Okay, danke noch mal. Sorry für den übersehenen Link.

    @Michael: Hast Du die Gründe parat warum sie den APC nun doch nicht mit rein nehmen? Irgendwelche Gründe muss es ja geben?

    @Martin: Ich denke das ist Geschmacksache. Sowas ist doch eigentlich ein Paradebeispiel wie man ein exit einsetzen kann?
    Aber ein if/else würde mir in diesem Fall, da der nachfolgende Code noch recht kurz ist, wohl auch nicht aufstoßen.

    Florian Heinze

    19 Dez 11 at 12:33

  12. Warum muss ich glaube ich nicht erklären….

    Erklär mal. Ich seh da nämlich keinen Vorteil drin. 🙂

    Oliver

    19 Dez 11 at 13:01

  13. @Florian: Ich glaube gelesen zu haben dass APC nicht sonderlich toll maintained wird, APC damit bevorteilt würde, und man den Core klein halten will. Ich glaube das sind die Hauptgründe, würde mich da aber gern berichtigen lassen von einem Core-Entwickler wie z.B. Pierre 😉

    Michael Kliewe

    19 Dez 11 at 16:18

  14. Danke, Artikel hat mir gut gefallen. Ein kleiner Test auf den eigenen Servern wird folgen 🙂

    Arne Riemann

    19 Dez 11 at 16:52

  15. Mich würde hier noch ein direkter Vergleich mit memcached (auf localhost) interessieren…

    Felix

    19 Dez 11 at 17:48

  16. @Felix
    Ungefähr halb so schnell:

    APC:
    Requests per second: 5980.40 [#/sec] (mean)

    Memcached
    Requests per second: 3001.30 [#/sec] (mean)

    Oliver

    19 Dez 11 at 18:18

  17. Danke für den Artikel. Jetzt weiß ich, wem ich Cachify mit APC-Support zusende zwecks Testing 😉

    Sergej Müller

    19 Dez 11 at 19:03

  18. @Sergej
    Ist mir gerade mal aufgefallen 🙂

    Version 1.2.1 vom 01.13.2011 !?
    http://playground.ebiene.de/cachify-wordpress-cache/

    Oliver

    19 Dez 11 at 21:31

  19. @Oliver:

    Da stimmt was nicht. 3000 Req/sec bei memcached auf localhost ist VIEL zu wenig.

    Felix

    20 Dez 11 at 01:01

  20. Hm, kann ich nix zu sagen. Das wareń jetzt die Standardeinstellungen von debian.

    -d
    logfile /var/log/memcached.log
    -m 128
    -p 11211
    -u nobody
    -l 127.0.0.1
    

    Oliver

    20 Dez 11 at 01:17

  21. Ich komme auf einem Hetzner EQ4 auf ca. 25.000 bis 30.000 Req/sec (localhost) und immernoch auf ca. 10.000 Req/sec übers Netzwerk.

    Wie groß sind denn die Keys im Schnitt?

    Felix

    20 Dez 11 at 10:15

  22. @Felix: nutzt du für deinen Test auch ein WordPress-Blog? Die Startseite dürfte ja einige KB groß sein, nehmen wir mal 3KB an. 10.000 Requests über das Netzwerk wären ja 30MB/s, also hast du Gigabit dort?

    Misst du auch mittels ab? Vom selben Server aus auf dem auch der Webserver läuft?

    Vielleicht wäre Logfile ausschalten bei Oliver noch gut um IO zu sparen?

    Michael Kliewe

    20 Dez 11 at 10:31

  23. @Oliver
    Stimmt, hab ich angepasst.

    Habe die Version mit APC rausgelegt: https://plus.google.com/110569673423509816572/posts/ajtUxTbsMfk

    Sergej Müller

    20 Dez 11 at 10:34

  24. @Michael Kliewe:
    Ja, Gigabit-Netzwerk.
    Aber eigentlich rede ich ja eh von memcached auf localhost (also auf dem selben Server auf dem auch die Anwendung läuft). Da sind einfach 3000 Req/sec zu wenig. Selbst bei größeren Key.

    Felix

    20 Dez 11 at 12:47

  25. @Felix:
    Du verwechselst da was.

    1. Die Seite in dem Beispiel da ist ca. 18 kb groß

    2. Kriege ich zwar mit memcache ~25.000 Requests pro Sekunde hin, aber das heißt ja nicht 25.000 Mal Webserver anfragen, PHP Interpreter aufrufen, memcache verbinden plus abfrage.

    Wenn ich sowas mache:

    <?php
    
    $memcache = new Memcache;
    $memcache->connect('localhost', 11211) or die ("Could not connect");
    
    $memcache->set('key', 'test', false, 3600);
    
    $start = microtime(true);
    for($i=0; $i<100000; $i++)
    {
    	$memcache->get('key');
    }
    
    echo round(100000/(microtime(true)-$start), 2);
    
    ?>
    

    dann hast Du natürlich recht, denn die Ausgabe sagt was von 25.184,98. Aber da ist ja auch null Overhead durch die anderen Programme drin. Wenn ich übrigens den gleichen Code mit APC mache, komme ich auf 1.712.680,84. Insgesamt komme ich also auf einen Faktor 65 bis 70 der APC schneller ist.

    @Sergej
    Ich schau mal

    Oliver

    20 Dez 11 at 14:01

  26. Oliver:
    Da hast du natürlich recht. Auch wenn die 1.712.680,84. von APC kaum realistisch sind… das Ergebnis wird statisch gecacht und APC wird nicht wirklich so oft abgefragt.

    Felix

    20 Dez 11 at 14:26

  27. <?php
    
    $start = microtime(true);
    
    for($i=0; $i<1000000; $i++)
    {
    	apc_store('key', $i);
    	apc_fetch('key');
    }
    echo 1000000/(microtime(true)-$start);
    
    ?>
    

    => 793.336,60

    Was soll da gecached werden? Die Daten werden doch im shared memory abgelegt. Das ist schon realistisch. Memcache ist wirklich gut, aber nur sinnig, wenn man mehrere Server braucht.

    Oliver

    20 Dez 11 at 14:33

  28. APC/PHP ist sicher so schlau und weiß, wann ein Key geändert wurde. Deshalb wird wohl kaum der richtige Inhalt nochmal geholt, sondern nur geprüft, ob der Key geändert wurde und der Inhalt nochmal geholt werden muss.

    Felix

    20 Dez 11 at 14:42

  29. @Felix
    Da würde ich aber nicht von ausgehen, denn theoretisch kann ja jede beliebige (andere) PHP Datei den Wert jederzeit ändern. Dementsprechend muss APC immer den neuen Wert holen.

    Zu prüfen, ob der anders ist, würde performancetechnisch keinen Sinn machen, weil dann müsste das PHP den aktuellen Wert zum Vergleich ja mitsenden.

    Oliver

    20 Dez 11 at 14:48

  30. Übrigens macht es keinen Sinn Daten vor dem Abspeichern in APC zu komprimieren, denn das Dekomprimieren dauert länger als das direkte Auslesen aus dem shared memory:

    apc_fetch auf komprimierte Daten mit gzuncompress
    472.997,51 #/sec

    apc_fetch auf unkomprimierte Daten
    1.539.994,36

    Das Verfahren ist nur bei direkter Ausgabe sinnvoll. Sonst nicht!

    Oliver

    20 Dez 11 at 18:12

  31. Ich muss zugeben, ich habe mich lange nicht wirklich getraut APC zu verwenden.
    Nachdem wir aber nun doch vor kurzem auf APC umgeschalten haben (im Backend setzen wir auf Symfony, damit funktioniert das auf OOP-Ebene spitze!), ist die Performance dramatisch erhöht worden. Und das obwohl wir bisher nur einzelne Komponenten cachen.

    Ich kann jedem nur raten, sich diesen Artikel genau durchzulesen oder zumindest ein Bookmark zu setzen, es zahlt sich aus 🙂

    Michael H.

    23 Dez 11 at 08:55

  32. Wenn man über Caching redet, dann sollte man auch immer kurz einen Reverse Proxy wie Squid oder Varnish erwähnen. Die machen nämlich was ganz ähnliches.

    Ansonsten danke für den Artikel und frohe Weihnachten.

    Nils

    26 Dez 11 at 12:34

  33. […] High Performance: Caching (reloaded) mit PHP | PHP Gangsta – Der PHP Blog mit Praxisbezug [Tags: performance caching php ] AKPC_IDS += "1087,"; Veröffentlicht: 3. Januar, 2012 Kategorie(n): casa.licous Tags: casa.licous « Previous Post […]

  34. Hi, sehr guter Artikel. Würde sich das caching auch bei einem forum script lohnen? Da hier ja die daten ständig aktuell sein müssen, wenn man also daten aus dem Speicher lädt wären diese ja veraltet.
    Mfg

    Andy

    7 Dez 12 at 08:22

Leave a Reply

You can add images to your comment by clicking here.