"HTTP-Cache" für PHP-Applikation
Andreas Korthaus
- programmiertechnik
Hallo!
Also ich habe mir mal überlegt, wie ich mit dem Apachen User-spezifisches HTML-Output(durch PHP-Scripte erzeugt) cachen kann, ganz ohne überhaupt den PHP-Interpreter zu starten, da sich nur so ein wirklich deutlicher Caching-Effekt einstellt. Im Prinzip habe ich versucht, sowas wie PEAR::Cache per mod_rewrite zu implementieren. Das Problem dabei: woher kann der Apache wissen ob sich das HTML-Output eines PHP-Scriptes geändert hat?
Das versuche ich wie folgt zu erreichen: Ich verwende das Dateisystem, über das ich per RewriteCond testen kann, ob eine spezielle Cache-Datei existiert. Wenn ein Script welches gecached werden soll aufgerufen wird, speichere ich am Ende eine Datei im Dateisystem, im Verzeichnis /cache/.
$cache_dir = $_SERVER["DOCUMENT_ROOT"].'cache'.$_SERVER["SCRIPT_NAME"].'_'.$_SERVER["QUERY_STRING"].'/';
if(!is_dir($cache_dir))
mkdir($cache_dir);
touch ($cache_dir.session_id());
Das erzeugt eine leere Datei mit dem Namen der SessionID des Benutzers, im angegeben Verzeichnis. Ich speichere auch den Query-String im Verzeichnis Namen, so dass ich auch hierdurch dynamische Seiten cachen kann. (das mkdir muss ggfs. etwas komplexer ausfallen bei tieferen Verzeichnisstrukturen)
Wenn jetzt Änderungen vorgenommen werden, die die Ausgabe dieses Scriptes betreffen, lösche ich alle Dateien in diesem Verzeichnis. (das ist auch die Archillesverse dieser Idee, ich darf nicht irgendwo vergessen dass dieses Script von einer Änderung betroffen sein könnte)
So, jetzt verwende ich folgene RewriteRule:
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/src/.*
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{HTTP:If-Modified-Since} ^.+
RewriteCond %{HTTP_COOKIE} SID=([0-9a-z]{32}) [OR]
RewriteCond %{QUERY_STRING} SID=([0-9a-z]{32})
RewriteCond %{DOCUMENT_ROOT}/cache%{REQUEST_URI}_%{QUERY_STRING}/%1 -f
RewriteRule ^(.*)$ / [R=304,L]
Dies funktioniert wie folgt:
Erst werden alle Verzeichnisse/Dateien ausgeschlossen, die sowieso nicht gecached werden sollen, in diesem Fall nur /src.
Dann wird nur die Request-Methode GET akzeptiert (POST macht wenig Sinn zu cachen)
dann gucke ich nach ob der Browser einen "If-Modified-Since" Header sendet, denn in diesem Fall kann ich davon ausgehen dass er eine Version im Cache hat.
Als nächstes versuche ich die SessionID aus Query-String oder Cache zu extrahieren.
Als letztes setze ich die ganzen Informationen zusammen, zum selben Pfad unter dem ich im PHP-Script eine Datei hätte erzeugen müssen.
Wenn unter diesem Pfad eine Datei existiert, weiß ich dass sich an dem Inhalt nichs geändert hat, und sende dem Browser einen 304-Header, "Not Modified". Dann wird der Browser die Version aus seinem Cache verwenden. So wird bei dem Request kein PHP-Interpreter-Durchlauf notwendig, es müssen nicht zig Klassen geladen und instanziert werden, nicht zig Datenbank-Abfragen...
Es sind eigentlich nur ein paar weniger Muster-Vergleiche und ein File-System-Check nötig.
Und das ganze funktioniert auch bisher hervorragend. Mich würde interessieren was Ihr von der Idee haltet, und ob Ihr vielleicht Ideen habt, wie man es besser machen kann.
Vor allem überlege ich noch, wie ich sicherstellen kann, dass der Cache auch wirklch bei jeder Änderung zurückgesetzt wird.
Mal als Beispiel ein News-Ticker. Wenn jemand eine Bestimmte News läd:
GET /news.php?id=123
dann wird das beim ersten Zugriff gecached, will heißen es wird die Datei
/cache/news.php_id=123/3487as76sd9830498098sa8d0923
angelegt. Beim nächsten Aufruf bekommt der User dann nur noch einen 304 Header, wenn eben diese Datei existiert. So, jetzt sagen wir mal der Redakteur ändert die News in der DB, mit einem ganz anderen Script, dann muss die oben genannte Datei gelöscht werden, genauer der gesamte Verzeichisinhalt, eben weil sich hierdurch die HTML-Ausgabe von /news.php?id=123 ändern wird -> die lokal gecachte Datei ist nicht mehr aktuell. Das ist ja soweit auch kein problem, nur muss ich da immer dran denken, das ist das Problem, z.B. bei weniger offensichtlichen Änderungen.
Sagen wir mal, der User kann seine Seite Personalisieren, z.B. das Datumsformat anpassen. Wenn er dieses bei seinen Einstellungen ändert, dann ändert sich auch das output von /news.php?id=123.
Das heißt, wenn der User sowas ändert, müssen alle Cache-Files, die das betrifft gelöscht werden. Gut, bei globalen Einstellungen würde ich je nachdem am besten alle Cache-Files des Users löschen.
ODer meint Ihr da würde ich mit einigen Clients Probleme bekommen? Ich könnte das ja auch abhängig vom USer-Agent machen. Ich denke über 90% der User-Agents könnten davon aber profitieren. Zur Not kann ich Caching noch in den User-Einstellungen komplett deaktivierbar machen.
Aber diese Probleme habe ich ja auch bei PHP-basierten Caches, die sind ja eigentlich auch nur darauf ausgelegt HTML-Output zu cachen, wenn sich von einer anderen Seite her was dran ändert, muss ich die Cache-ID auch entsprechend löschen.
Ich weiß, dass so eine user-spezifische Anwendung nicht gerade optimal zum cachen ist, aber meine Scrite erzeugen teilweise richtig viel Last, da sie oft sehr große HTML-Tabellen erzeugen, on-the-fly aus verschiedenen Datenbank-Tabellen zusammengefügt. Wenn die DB, dann richtig voll ist wird das sehr lahm.
Viele Grüße
Andreas
Also ich habe mir mal überlegt, wie ich mit dem Apachen User-spezifisches HTML-Output(durch PHP-Scripte erzeugt) cachen kann, ganz ohne überhaupt den PHP-Interpreter zu starten, da sich nur so ein wirklich deutlicher Caching-Effekt einstellt.
Das halte ich so alleine für fraglich.
Das Problem dabei: woher kann der Apache wissen ob sich das HTML-Output eines PHP-Scriptes geändert hat?
Eben.
Ich weiß, dass so eine user-spezifische Anwendung nicht gerade optimal zum cachen ist, aber meine Scrite erzeugen teilweise richtig viel Last, da sie oft sehr große HTML-Tabellen erzeugen, on-the-fly aus verschiedenen Datenbank-Tabellen zusammengefügt. Wenn die DB, dann richtig voll ist wird das sehr lahm.
Dann solltest Du zuerst dort ansetzen und den Aufbau der Datenbanktabellen überdenken, sowie prüfen, ob die Indizes passen (dazu kann auch zählen, daß es nicht zu viele sind).
In diesen Zusammenhang solltest Du auch schauen, ob Deine Datenbank einen Spaltentyp kennt, der automatisch die letzte Änderungszeit des jeweiligen Datensatzes speichert (z.B. bei MySQL TIMESTAMP). Mit dessen Hilfe reicht ein einfacher Abgleich mit der vom Browser gesendeten Last-Modified-Angabe, um das Skript mit der Meldung "nicht geändert" sofort wieder abbrechen zu können.
Zum zweiten halte ich den Nutzen eines persönlich formatierten Datums (oder ähnlicher Kleinigkeiten) für äußerst fragwürdig. Nicht, daß es niemand benutzen würde, die Frage ist, ob es überhaupt jemanden interessieren würde, wenn diese Option nicht vorhanden wäre - sozusagen eine Sack-Reis-Option. Sowas belastet nicht nur unnötig den Server, es verkompliziert möglicherweise auch die Einstellungsseite. Lohnt sich das wirklich?
Wenn ja, besteht vielleicht die Möglichkeit, diese persönlichen Elemente per Javascript erst auf der Benutzerseite einzubauen. Die Seite enthält nur noch die Rohdaten, von PHP in einen Javascript-Bereich ausgegeben (etwa 'var datum = new Date(1,2,3);'), die Einstellungen stecken in einem Cookie im Browser, eine Javascript-Funktion bastelt dann daraus beim Benutzer die gewünschte Ausgabe. Trotzdem bitte nicht den <noscript>-Bereich mit den jeweiligen Daten in einem Standardformat vergessen!
Direkt daran anschließend ist dann das, was Du bereits praktizierst, zu nennen, allerdings in abgespeckter Form: Das Skript schreibt eine statische HTML-Seite auf die Platte, die dann entweder direkt per URL vom Server ausgeliefert wird oder über den Umweg des Skriptes (in jedem Fall ohne den ganzen mod_rewrite-Krams, das muß nicht unbedingt besser sein, als ein PHP-Skript zu laden). Diese Seite ist eine Standardversion, ohne jegliche persönlichen Schnörkel. Es würde mich nicht wundern, wenn ein Gutteil des Bedarfs bereits von dieser statischen Seite gedeckt wird.
Gruß,
soenk.e
Hallo!
Also ich habe mir mal überlegt, wie ich mit dem Apachen User-spezifisches HTML-Output(durch PHP-Scripte erzeugt) cachen kann, ganz ohne überhaupt den PHP-Interpreter zu starten, da sich nur so ein wirklich deutlicher Caching-Effekt einstellt.
Das halte ich so alleine für fraglich.
Die Idee habe ich hierdurch bekommen:
http://www.incremental.de/talks/phpconf-2003-caching/fehler_php_cache/durchsatz.html
http://www.incremental.de/talks/phpconf-2003-caching/lighttpd_cache/cml2.html
Wenn ich doch in der Lage bin noch in mod_rewrite eine entscheidung zu treffen ob gecached werden soll, wieso sollte ich das nicht tun?
mod_rewrite verwende ich sowieso, was dazu kommt sind lediglich 4 Mustervergleiche. Und wenn mod_rewrite eh geladen/verwendet wird, dann wird das doch _sehr_ wenig ausmachen, oder? Dazu kommt dass keine Datei geladen wird, sondern am besten der Firesystem-Check im RAM erfolgen kann, wenn ich die Cache-Dateien in den RAM lege, und da die alle keinen Inhalt haben, wird das auch sehr wenig Platz kosten.
Dazu kommt dass die Datei nicht mit übertragen werden muss, sondern nur der Header. Mir sind die bekannten Caching-Mechanismen durchaus bekannt. Ich dachte nur es wäre eine gute Idee wenn möglich das Caching noch aus PHP auszulagern.
Das Problem dabei: woher kann der Apache wissen ob sich das HTML-Output eines PHP-Scriptes geändert hat?
Eben.
Das lässt sich ja über das Dateisystem genauso gut lösen wie über irgendeinen PHP-Cache.
Dann solltest Du zuerst dort ansetzen und den Aufbau der Datenbanktabellen überdenken, sowie prüfen, ob die Indizes passen (dazu kann auch zählen, daß es nicht zu viele sind).
Klar. Aber bestimmte Dinge lassen sich nur sehr schlecht optimieren. Außerdem ist die Applikation recht komplex, was dazu fürhrt, bevor ich überhaupt irgendwelchen Code ausführe kommen zig DB-Agfragen, es werden zig Objekte erzeugt..., was ein Framework für eine größere Applikation eben so mit sich bringt.
In diesen Zusammenhang solltest Du auch schauen, ob Deine Datenbank einen Spaltentyp kennt, der automatisch die letzte Änderungszeit des jeweiligen Datensatzes speichert (z.B. bei MySQL TIMESTAMP). Mit dessen Hilfe reicht ein einfacher Abgleich mit der vom Browser gesendeten Last-Modified-Angabe, um das Skript mit der Meldung "nicht geändert" sofort wieder abbrechen zu können.
Ja, aber um das zu ermitteln muss ich eine Verbindung zur DB aufbauen, abfragen senden und Rückgabewerte analysieren...
Warum sollte ich das alles nicht vermeiden - wenn es doch geht? Es funktioniert in der Tat.
Zum zweiten halte ich den Nutzen eines persönlich formatierten Datums (oder ähnlicher Kleinigkeiten) für äußerst fragwürdig.
Das ist nunmal Pflicht. Man kann auch eine andere Sprache einstellen oder das allgemeine Zahlenformat ändern. Das ist eine "must-have" Feature.
Nicht, daß es niemand benutzen würde, die Frage ist, ob es überhaupt jemanden interessieren würde, wenn diese Option nicht vorhanden wäre - sozusagen eine Sack-Reis-Option.
Wenn der Kunde amerikaner ist und kein amerikanisches Datum hat sieht das nicht wirklich gut aus. Anders herum sicher nicht so schlimm.
Sowas belastet nicht nur unnötig den Server, es verkompliziert möglicherweise auch die Einstellungsseite. Lohnt sich das wirklich?
es ist Pflich, Punkt. ;-)
Direkt daran anschließend ist dann das, was Du bereits praktizierst, zu nennen, allerdings in abgespeckter Form: Das Skript schreibt eine statische HTML-Seite auf die Platte, die dann entweder direkt per URL vom Server ausgeliefert wird oder über den Umweg des Skriptes (in jedem Fall ohne den ganzen mod_rewrite-Krams, das muß nicht unbedingt besser sein, als ein PHP-Skript zu laden).
Wieso das? zum einen wird die Rewrite-Engine ohnehin geladen, und des weiteren ist das doch schon ein erheblicher Unterschied in der Komplexität. Was habe ich von statischen HTML-Seiten? Was ist daran besser die im Server-Cache zu lagern, als im Cache des Client?
Ich überlege nur HTML-Cache dazu zu verwenden für Teile die sich seltener ändern und die bei allen Usern gleich sind.
Diese Seite ist eine Standardversion, ohne jegliche persönlichen Schnörkel. Es würde mich nicht wundern, wenn ein Gutteil des Bedarfs bereits von dieser statischen Seite gedeckt wird.
es ist aber so.
Grüße
Andreas
In diesen Zusammenhang solltest Du auch schauen, ob Deine Datenbank einen Spaltentyp kennt, der automatisch die letzte Änderungszeit des jeweiligen Datensatzes speichert (z.B. bei MySQL TIMESTAMP).
Ja, aber um das zu ermitteln muss ich eine Verbindung zur DB aufbauen, abfragen senden und Rückgabewerte analysieren...
SQL> select unix_timestamp(max(änderung)) from tabelle;
PHP> if ($sql_änderung <= $browser_änderung)
not_modified();
Finde ich gegenüber dem Erstellen einer "komplexen HTML-Tabelle" ganz und gar nicht aufwendig. Aber genau da besteht vielleicht auch Dein Problem: Du wirfst alles in einen Pott, ist ein Teil des PHP-Skriptes nicht zu gebrauchen, muß gleich der ganze PHP-Interpreter über Bord (übertrieben ausgedrückt).
Warum sollte ich das alles nicht vermeiden - wenn es doch geht?
Siehst Du, "wenn es doch geht". Nur weil es geht, muß es ja noch lange nicht sinnvoll sein, oder?
Ich kenne die Killerapplikation nicht, an der Du werkelst, aber ich habe den Eindruck, daß Du versuchst, geradezu krampfhaft mit Kanonen auf Spatzen zu schießen, und zwar in zweierlei Hinsicht:
1. Du scheinst gar keine genaue Vorstellung davon zu haben, wie groß das Ziel ist und wie es sich bewegt und bestellst deshalb einfach mal das größte, modernste, austattungsreichste Waffensystem, das Du gerade kriegen kannst.
Warum? Hast Du überhaupt mal nachgemessen, wie lange es dauert, bis PHP Dein Skript ausführbar vorliegen hat? Das Problem an Deinem Skript ist das Zusammensuchen und Aufbereiten der Daten, nicht das Laden des Skriptes ansich. Das hast Du jedenfalls so mit der Aussage "je größer die Datenbank, desto langsamer die Ausgabe" behauptet.
Anstatt nun erstmal diesen aufwendigsten Teil zeitweise (also per Last-Modified) überflüssig zu machen, baust Du noch eine detailreiche Konstruktion obendrauf, um gleich das ganze Skript zu eliminieren. Damit schießt Du IHMO weit über das Ziel hinaus und baust Dir gleichzeitig haufenweise Fehlerquellen ein (wie Du ja selbst bemerkt hast).
Der Anteil an der gesamten Abwicklungsdauer, den PHP zum Laden des Skriptes beansprucht, mag beim Endbenutzer mit einigen hunderstel oder meinetwegen zehntel Sekunden vielleicht noch messbar sein, aber ich kann mir nicht vorstellen, daß er noch irgendwie _merk_bar ist. Von daher scheint mir der Aufwand, den Du betreibst, sinnlos. Größerer Aufwand, insbesondere wenn er sich auf verschiedenste Komponenten verteilt, bedeutet aber immer auch mehr Fehlerquellen - und da wird es dann nicht nur sinnlos, sondern arg problematisch. Aber das ist Geschmackssache, siehe ganz oben.
2. Du versuchst, mit eine bestimmte Aufgabe zu erledigen, bedienst Dich dabei aber eines für diesen Zweck unzureichenden Werkzeugs.
Warum? Deinen Ausführungen nach zu urteilen ist die ganze Angelegenheit fürchterlich komplex. Interpretersprachen waren noch nie für komplexe Aufgaben zu gebrauchen und werden es nie sein, egal wie c00l das Dingens gerade ist, insofern benutzt Du mit PHP möglicherweise schlichtweg das falsche Werkzeug. Oder, so würden es die SelfSpezialisten sehen, Dein Server ist zu lahm. Kommt im Endeffekt auf das gleiche raus.
Was habe ich von statischen HTML-Seiten? Was ist daran besser die im Server-Cache zu lagern, als im Cache des Client?
Das hat überhaupt nichts mit einem Server-Cache zu tun (der in den meisten Webservern eh nicht vorhanden ist), eine statische Seite muß schlichtweg nicht bei jedem Aufruf neu erstellt werden. Und der Webserver ist zudem in der Lage, den ganzen Tralala mit Last-Modified ganz von alleine zu handhaben.
Es mag Dir entsetzlich simpel vorkommen, aber das ist letztenendes genau das, was Du haben willst: keine Datenbankaufrufe, kein PHP, nicht einmal mod_rewrite. Daß auch solche statischen Seiten (in einem gewissen Rahmen) persönlich eingerichtet werden können, schrieb ich ja bereits.
Gruß,
soenk.e
Moin!
In diesen Zusammenhang solltest Du auch schauen, ob Deine Datenbank einen Spaltentyp kennt, der automatisch die letzte Änderungszeit des jeweiligen Datensatzes speichert (z.B. bei MySQL TIMESTAMP).
Ja, aber um das zu ermitteln muss ich eine Verbindung zur DB aufbauen, abfragen senden und Rückgabewerte analysieren...
SQL> select unix_timestamp(max(änderung)) from tabelle;
PHP> if ($sql_änderung <= $browser_änderung)
not_modified();Finde ich gegenüber dem Erstellen einer "komplexen HTML-Tabelle" ganz und gar nicht aufwendig. Aber genau da besteht vielleicht auch Dein Problem: Du wirfst alles in einen Pott, ist ein Teil des PHP-Skriptes nicht zu gebrauchen, muß gleich der ganze PHP-Interpreter über Bord (übertrieben ausgedrückt).
Das Problem ist doch aber: Wenn sich nicht nur eine Tabelle ändern kann, sondern mehrere an verschiedenen Stellen, und diese Tabellen auch noch über ein komplexeres Framework zusammengestrickt werden (was unbestreitbar sinnvoll ist, weil das nämlich auch so Sachen wie OOP, Abtraktion in Klassen etc. umfaßt), und insgesamt also nur durch eine ähnlich komplexe Konstruktion überhaupt erfaßt werden kann, welche der möglichen Änderungen erfolgt ist, dann bringt es nichts, PHP-Anfängermäßig Simpelcode an den Anfang zu stellen. Interpretiert werden muß dann trotzdem der gesamte Code.
Was Sinn machen könnte: Wenn sich Seiten quasistatisch verhalten und nur selten Änderungen unterworfen sind, dann könnte man darüber nachdenken, einmal manuell oder genau zum Zeitpunkt der ersten Anforderung die erzeugte Seite exakt abzuspeichern als statische Kopie. Sozusagen "generieren lassen" auf Vorrat.
Allerdings: Genau dies passiert ja mit dem mod_rewrite-System. Nur wird hierbei sogar noch das tatsächliche Speichern der Seite eingespart, da die ja dem Client ohnehin bekannt ist, sofern er If-Modified-Since sendet.
Mir gefällt das vorgestellte Beispiel jedenfalls sehr gut. Dass man manuell die Cache-Flag-Dateien wegräumen muß, ist dabei nicht zu vermeiden. Dass es möglicherweise nur bei bestimmten Aktionen notwendig ist, sei zu analysieren.
Volldynamische Daten lassen sich damit jedenfalls kaum cachen - wäre ja auch nicht sinnvoll. Aber Caching-Header zu senden und auch sinnvoll auszuwerten, spart dem Server CPU-Zyklen und dem Benutzer Übertragungszeit ein. Beide gewinnen.
Warum sollte ich das alles nicht vermeiden - wenn es doch geht?
Siehst Du, "wenn es doch geht". Nur weil es geht, muß es ja noch lange nicht sinnvoll sein, oder?
Gerade weil es im Standard vorgesehen ist: Warum nicht verwenden?
- Du versuchst, mit eine bestimmte Aufgabe zu erledigen, bedienst Dich dabei aber eines für diesen Zweck unzureichenden Werkzeugs.
Nein, das würde ich nicht sagen. Wenn die Feststellung seitens des Servers, ob die damals ausgelieferte Version noch aktuell ist, "teuer" ist, dann mag man sie sich zugunsten eines etwas zu aggressiven Cachings sparen. Immerhin erledigen sich mangelhafte Aktualisierungen durch ein forciertes Neuladen der jeweiligen Ressource von selbst: Kein If-Modified-Since - keine Cacheabfrage.
Warum? Deinen Ausführungen nach zu urteilen ist die ganze Angelegenheit fürchterlich komplex. Interpretersprachen waren noch nie für komplexe Aufgaben zu gebrauchen und werden es nie sein, egal wie c00l das Dingens gerade ist, insofern benutzt Du mit PHP möglicherweise schlichtweg das falsche Werkzeug. Oder, so würden es die SelfSpezialisten sehen, Dein Server ist zu lahm. Kommt im Endeffekt auf das gleiche raus.
Möchtest du den Interpretersprachen ihre Existenzberechtigung absprechen? Welche Sprachen würden denn deiner Meinung nach die Anforderungen für "komplexe Anwendungen" erfüllen?
Komplexität ist eine ziemlich komplexe Angelegenheit, würde ich meinen. Die läßt sich nicht einfach mit einem Schlagwort erschlagen.
Es mag Dir entsetzlich simpel vorkommen, aber das ist letztenendes genau das, was Du haben willst: keine Datenbankaufrufe, kein PHP, nicht einmal mod_rewrite. Daß auch solche statischen Seiten (in einem gewissen Rahmen) persönlich eingerichtet werden können, schrieb ich ja bereits.
Die Frage ist: Welche Informationen auf einer Seite sind dynamisch? Und _wie_ dynamisch sind sie? Ein Newsticker auf jeder Seite ist mit Sicherheit zu dynamisch, als dass man ihn mit statischen, immer wieder neu generierten Seiten abbilden könnte. Andererseits ließe er sich prima mittels SSI einbinden - und SSI kann natürlich auch PHP ausführen, mithin könnte eine Datenbank befragt werden.
Nur: Dann bin ich schon wieder fast genau dort, wo ich vorher war. Statische Seite startet PHP - Resultat ist dynamisch, kann nicht gecachet werden, und der kritische Teil, nämlich die Ermittlung der dynamischen Anteile, ist so oder so genauso Aufwendig. Einmal schreibt PHP die Seite komplett, ein anderes Mal nur einen Teil.
Wenn Andreas' Analyse ergeben hat, dass Cachen der Seiten sinnvoll ist, weil sich gewisse Aspekte einer Ausgabe nicht so häufig ändern, dann halte ich Caching-Header, die dies auf dem Client erlauben, sowie den frühestmöglichen Eingriff in die Request-Bearbeitung für absolut sinnvoll.
Die bekannten Nachteile sind dabei in Kauf zu nehmen und ließen sich eben nur durch komplett dynamisches Generieren lösen.
- Sven Rautenberg
Hi Sven!
Wenn Andreas' Analyse ergeben hat, dass Cachen der Seiten sinnvoll ist, weil sich gewisse Aspekte einer Ausgabe nicht so häufig ändern, dann halte ich Caching-Header, die dies auf dem Client erlauben, sowie den frühestmöglichen Eingriff in die Request-Bearbeitung für absolut sinnvoll.
Ich überlege auch, ob ich ob ich das ganze noch weiter ausbauen könnte. So wie es jetzt ist wird pro Session jedesmal eine neue Version erzeugt. Ich könnte das auch komplett user-basiert machen, also nicht die Session, sondern die User-ID als Identifikations-Merkmal verwenden. Dann könnte ich die Cache-Dateien ggfs. Session-Übergreifen verwenden. Dann muss ich nur in der RewriteCond irgendwie an die UserID kommen, das könnte ich entweder über REMOTE_USER erfahren, oder allgemeingültiger(also auch ohne HTTP_AUTH) über eine bei Logins dynamisch gepflegte RwriteMap. Erst dachte ich das sei sicherheitstechnisch nicht das wahre, aber das ist ja unbegründet, ein entscheidender Vorteil der 304-Methode liegt ja darin, dass der Client eine lokale Version haben muss, die er nur erhält wenn er einmal durch den normalen Authentifizierungs-Prozess gegangen ist.
Problematischer ist da schon, dass der User evtl. verschiedene Browser mit verschieden alten Versionen verwenden könnte. Das kann ich mit der aktuellen Version nicht abbilden. Hierzu müsste ich entweder If-Modified-Since oder Etag auswerten. Aber da weiß ich im Moment nicht, wie diese Information sinnvoll speichern kann. Oder woher ich die überhaupt bekomme!
Eine Möglichkeit wäre es, an der Stelle wo ich die Flag-Datei erzeuge, selber einen Last-Modified Header zu erzeugen, dessen String ich dann mit im Dateinamen speichern kann. Wobei mir das nicht so geeignet erscheint, aufgrund der ganzen Leerzeichen im String, da wüßte ich jetzt nicht wie ich das machen könnte. Aber dafür gibt es ja den Etag Header, den kann ich ja einfach senden. Und da kann ich ja einen entsprechend einfachen String nehmen, den ich an den Dateinamen hänge. Müsste da ggfs. noch die Protokoll-Version prüfen.
Soweit so gut. So könnte ich es also erreichen, dass wenn sich die Ausgabe eines Scriptes über die mehrere Sessions hinweg nicht ändert, dass immer die Version im Cache verwendet wird, und sollte dank Etag Header auch keine Probleme mit Usern haben, die verschiedenen Clients verwenden. Das halte ich durchaus für sinnvoll. Etwas weitergedacht könnte man bei einer zu cachenden Seite auch die HTML-Ausgabe per Output-Buffer Funktionen in der Datei mit dem genannten Namen speichern, dann könnte ich einem User, der einen anderen Client verwendet eben diese HTML-Seite ausliefern, ohne auf die Applikation zurückgreifen zu müssen. Das stellt zwar kein großes Problem da, nur wird das Cache-Verzeichnis hierdurch schnell erheblich größer. Und da ich davon ausgehe dass die User eher selten den Client wechseln, halte ich den Aufwand eher nicht wirklich für gerechtfertigt, oder?
Naja, habe viele Ideen, ich überlege auch ob ich in meiner Anwendung die normalen SessionIDs abschaffen soll, denn ich verwende sowieso durchgehend SSL, und da habe ich in PHP ja Zugriff auf die SSL_SESSION_ID, die könnte ich ja an die Funktion session_id($_SERVER['SSL_SESSION_ID']) übergeben, das hätte den Vorteil dass ich mir auf der einen Seite Cookies spare, auf der anderen Seite den Mehraufwand von TransSID, was ja durchaus einen gewissen aufwand darstellt, da die gesamte HTML-Ausgabe der PHP-Scripte ja durch einen Filter laufen muss.
btw., falls es Dich interessiert, ein paar Tipps zur Optimierung von PHP/Apache-Performance findest Du hier:
http://phplens.com/lens/php-book/optimizing-debugging-php.php
http://php.weblogs.com/tuning_apache_unix
Grüße
Andreas
Hallo!
Nur mal so nebenbei, ich spiele hier eigentlich nur rum, ich weiß weder ob ich das irgendwann mal einsetzen werden, noch weiß ich welchen Geschwindigkeits-Vorteil dieses Vorgehen genau bietet.
Hierzu sind ausgiebige Tests mit guten Testdaten in einer Testumgebung der tatsächlichen Applikation notwendig. Leider habe ich im Moment keine Möglichkeit eine entsprechende Umgebung zu schaffen in der ich den Testserver wirklich mit Anfragen auslasten kann. Ich werde es aber sicher demnächst so durchführen, sobald sich die Möglichkeit bietet. Und da werde ich auch einige andere Dinge testen wie Apache 1.3 vs 2.0, statische Inhalte auf einer Ramdisk...
Finde ich gegenüber dem Erstellen einer "komplexen HTML-Tabelle" ganz und gar nicht aufwendig. Aber genau da besteht vielleicht auch Dein Problem: Du wirfst alles in einen Pott, ist ein Teil des PHP-Skriptes nicht zu gebrauchen, muß gleich der ganze PHP-Interpreter über Bord (übertrieben ausgedrückt).
Ich versuche lediglich, so früh zu optimieren, wie eben möglich. Was habe ich davon erstmal zig Sachen zu laden, die Last verursachen, wenn ich dem Server diese Arbeit doch zum großen Teil ersparen kann?
Mir geht es nicht um ein spezielles Problem, sondern ich wollte mal ein paar allgemeine Meinungen zur Idee einholen.
Warum sollte ich das alles nicht vermeiden - wenn es doch geht?
Siehst Du, "wenn es doch geht". Nur weil es geht, muß es ja noch lange nicht sinnvoll sein, oder?
Ja, also am besten CGI verwenden...? Warum überhaupt Gedanken über Performance machen? Man kann doch mal ein bisschen rumspinnen, oder? ;-)
Ich kenne die Killerapplikation nicht, an der Du werkelst, aber ich habe den Eindruck, daß Du versuchst, geradezu krampfhaft mit Kanonen auf Spatzen zu schießen, und zwar in zweierlei Hinsicht:
Warum "Killerapplikation"? Wie gesagt, es sind Ideen. Es ist doch nichts schlechtes die Performance mit den gegebenen Mitteln best möglich auszureizen, oder?
Wenn ich doch genau weiß dass viele Seiten sehr oft aufgerufen werden, um zu sehen ob sich was geändert hat, ist es doch das einfachste dem Client so lange die im Cache gespeicherte Variante verwenden zu lassen, und nur bei Änderungen die eigentliche Applikation zu bemühen. Durch Verwendung der SessionID behalte ich darüber hinaus sämtliche Rechte-Strukturen der Applikation, ggfs. kann ich bestimmte Seiten auch global speichern, mal sehen wie ich das noch einbaue. Und das ließe sich auch mit einem HTML-Cache verbinden.
- Du scheinst gar keine genaue Vorstellung davon zu haben, wie groß das Ziel ist und wie es sich bewegt und bestellst deshalb einfach mal das größte, modernste, austattungsreichste Waffensystem, das Du gerade kriegen kannst.
Muss man das denn immer? Wenn ich sehe dass mit (IMHO) halbwegs vergleichbaren Maßnahmen Einsparungen um den Faktor 10-50 realisiert werden, ist das für mich durchaus ein Gebiet, wo es sich löhnt mal drüber nachzudenken, auch ohne eine konkrete Problemstellung. Wenn ich ein bisschen getestet habe kann ich später bei Problemen ggfs. hierauf zurückgreifen.
Warum? Hast Du überhaupt mal nachgemessen, wie lange es dauert, bis PHP Dein Skript ausführbar vorliegen hat? Das Problem an Deinem Skript ist das Zusammensuchen und Aufbereiten der Daten, nicht das Laden des Skriptes ansich. Das hast Du jedenfalls so mit der Aussage "je größer die Datenbank, desto langsamer die Ausgabe" behauptet.
In dem oben verlinkten Artikel wurde ein Faktor von 15 zwischen statischer Seite und einem Hello-World Script(!) gemessen. Und von solchen Größenordnungen habe ich schon mehrfach gehört. AFAIK sind die Unterschiede beim Apache ein wenig kleiner. Auf der anderen Seite verwende ich aber keine statische HTML-Seite, sondern nur einen File-System-Check und einen 304 Header, was sicher schneller ist als statisches HTML. Dazu kommt dass der Client die Daten meist aus dem eigenen RAM holen kann. Außerdem sind meine PHP-Scripte keine Hallo-Welt Scripte, und auch PHP-Scripte die den Cache-Status prüfen(per DB) brauchen sicher ne Ecke mehr Performance, auch durch das Framework...
Wie gesagt nicht selbst gemessen, das werde ich nachholen.
Anstatt nun erstmal diesen aufwendigsten Teil zeitweise (also per Last-Modified) überflüssig zu machen, baust Du noch eine detailreiche Konstruktion obendrauf, um gleich das ganze Skript zu eliminieren. Damit schießt Du IHMO weit über das Ziel hinaus und baust Dir gleichzeitig haufenweise Fehlerquellen ein (wie Du ja selbst bemerkt hast).
Die Fehlerquellen bei der von dir beschriebenen Methode sind dieselben. Es reicht meist nicht das prüfen eines Timestamps, es sind mehrere Prüfungen notwendig. Z.B. wird die genannte HTML-Tabelle aus ich glaube 5 Datenbank-Tabellen erzeugt. Das können unter Umständen 1000 Datensätze und mehr sein. Das heißt ich müsste die alle Datensätze prüfen, bei jedem Aufruf. Ja, das geht mit wenigen SQL-Statements, aber auf der anderen Seite, gibt es nur 2 Scripe die Änderungen an den entsprechenden Daten vornehmen können, also ist es IMHO effizienter hier anzusetzen.
Der Anteil an der gesamten Abwicklungsdauer, den PHP zum Laden des Skriptes beansprucht, mag beim Endbenutzer mit einigen hunderstel oder meinetwegen zehntel Sekunden vielleicht noch messbar sein, aber ich kann mir nicht vorstellen, daß er noch irgendwie _merk_bar ist.
Gut, es gibt 2 Probleme, das eine sind besonders Lastenintensive scripte wie das beschriebene, wenn es nur darum ginge dieses Problem zu lösen würde Deine Methode prinzipiell reichen. Das andere Problem ist ein insgesamt hohe Last des Webservers/DB-Servers. Und wenn ich hier Verbesserungen erzielen will muss ich mit den Optimierungen früher ansetzen. Aber wie gesagt, es ist erstmal nur eine Idee, die ich evtl. zu einem Framework ausbauen könnte. Ich könnte auch spezielles Apache-Modul programmieren, welches hierfür optimiert ist. Sowas haben die Leute aus den verlinkten Vorträgen gemacht, wenn auch nicht für den Apache, aber die Vorträge sind sehr interessant und lesenswert wie ich finde.
Von daher scheint mir der Aufwand, den Du betreibst, sinnlos.
mag sein.
- Du versuchst, mit eine bestimmte Aufgabe zu erledigen, bedienst Dich dabei aber eines für diesen Zweck unzureichenden Werkzeugs.
Ich versuche keine bestimmte Aufgabe zu erledigen, ich versuche eine Idee zu verwirklichen, bzw. ein Konzept von einem anderen (extrem auf Performance getrimmten) Webserver zu mit Apache-Bordmitteln zu realisieren.
Warum? Deinen Ausführungen nach zu urteilen ist die ganze Angelegenheit fürchterlich komplex.
Meinst Du meine Caching-Idee? So komplex ist das nicht, die Komplexität entsteht durch dei Komplexität der Applikation, und hier habe ich bei allen Caching-Mechanismen dieselbe oder zumindest ähnliche Probleme.
Interpretersprachen waren noch nie für komplexe Aufgaben zu gebrauchen und werden es nie sein,
Ja? Das sehe ich anders. Mit PHP lassen sich auch recht komplexe Anforderungen erfüllen, genauso wie man mit Sprachen wie Java oder C++ extremen Müll fabrizieren kann. PHP bietet eigentlich alles was man für komplexe Applikationen braucht, vielleicht bis auf einen brauchbaren Applikationsserver, aber auch hier kann man sich mit einem eigenen Framework viel erreichen. So bieten einige Opcode-Caches z.B. die Möglichkeit Datenstrukturen im SHM zu speichern, und das funktioniert sehr gut. Man muss nur wissen was man tut. Das Problem ist, dass sich sowas nicht so ohne weiteres auf mehrere Maschinen verteilen lässt, wie J2EE Application-Server, und hier kommen dann wieder die Performance-Optimierungen ins Spiel, mit dessen Hilfe man die Leistungsfähigkeit deutlich erweitern kann, und eben in der Richtung habe ich ein bisschen rumprobiert, bzw. bin ich noch dabei.
egal wie c00l das Dingens gerade ist, insofern benutzt Du mit PHP möglicherweise schlichtweg das falsche Werkzeug.
Wie kommst Du jetzt auf einmal auf eine "PHP ist doof" Diskussion? Mich würde ganz ehrlich sehr interessieren warum Du PHP in komplexen Web-Applikationen nicht für das geeignete Werkzeug hältst. Was wären denn entsprechend brauchbare Werkzeuge Deiner Meinung nach?
Ich höre andauernd "PHP ist für sowas doof", "Java ist sowieso doof", aber was verwenden solche Leute denn bitte?
Oder, so würden es die SelfSpezialisten sehen, Dein Server ist zu lahm. Kommt im Endeffekt auf das gleiche raus.
Hä? Was ist das denn jetzt für eine Anspielungen? Die Software des Self-Server lässt sich wohl kaum noch nennenswert optimieren. Oder sollte alles mit Assembler geschrieben werden?
Was habe ich von statischen HTML-Seiten? Was ist daran besser die im Server-Cache zu lagern, als im Cache des Client?
Das hat überhaupt nichts mit einem Server-Cache zu tun (der in den meisten Webservern eh nicht vorhanden ist), eine statische Seite muß schlichtweg nicht bei jedem Aufruf neu erstellt werden. Und der Webserver ist zudem in der Lage, den ganzen Tralala mit Last-Modified ganz von alleine zu handhaben.
Wenn Du aber die Entscheidung ob cachen oder nicht in ein PHP-Script verlagerst ist der Server eben nicht in der Lage irgendwelche Caching-Mechanismen zu handhaben, ganz im Gegenteil sendet der server aggressive anti-caching Header um eben solches zu verhindern(sobald man sessions einsetzt).
Und wenn Du aus PHP-Scripten HTML-Dateien erzeugst und zwischenspeicherst, dann ist das für mich auch eine Art des Caching.
Es mag Dir entsetzlich simpel vorkommen, aber das ist letztenendes genau das, was Du haben willst: keine Datenbankaufrufe, kein PHP, nicht einmal mod_rewrite. Daß auch solche statischen Seiten (in einem gewissen Rahmen) persönlich eingerichtet werden können, schrieb ich ja bereits.
Aber woher weiß der Webserver ob sich irgendwas an der Ausgabe der PHP-Scripte geändert hat?
Grüße
Andreas
Nur mal so nebenbei, ich spiele hier eigentlich nur rum, ich weiß weder ob ich das irgendwann mal einsetzen werden, noch weiß ich welchen Geschwindigkeits-Vorteil dieses Vorgehen genau bietet.
Naja, ein etwas merkwürdiges Vorgehen. Wenn ich an etwas bastel, dann möchte ich schon gerne wissen, warum ich das mache und vor allen Dingen ob ich meine Ziele erreiche.
Aber wenn es Dir Freude macht, einfach ziellos in der Gegend rumzubasteln, bitte ;)
Ich versuche lediglich, so früh zu optimieren, wie eben möglich. Was habe ich davon erstmal zig Sachen zu laden, die Last verursachen, wenn ich dem Server diese Arbeit doch zum großen Teil ersparen kann?
Gegenfrage: Was habe ich davon, zig Sachen zu programmieren, wenn ich am Ende nicht merke, überhaupt etwas gemacht zu haben?
Es ist eine Abwägung zwischen Komplexität und Geschwindigkeitsvorteil. Mir persönlich erscheint Deine Vorgehensweise viel zu aufwendig und -wichtiger- fehlerträchtig, relativ gesehen zum tatsächlichen, absoluten Geschwindigkeitsvorteil.
Man könnte die Geschichte auch noch auf die Spitze treiben und sagen, daß das, was Du an Personalkosten für Optimierungen verursachst, nie und nimmer auf der Hardwareseite eingespart werden kann.
Aber anscheinend reden wir auch etwas aneinander vorbei: Ich hatte angenommen, Du hast ein Problem mit einer realen Anwendung, Du hingegen probierst lediglich. Daß jemand, der ein Alltagsauto im Sinn hat, andere Entwicklungsmaßstäbe ansetzt als jemand, der eine Formel-1-Karre bastelt, ist natürlich klar.
Insofern sind Deine Ansätze natürlich vollkommen legitim, ich hinterfrage lediglich die Zweckmäßigkeit für den Alltag.
Mir geht es nicht um ein spezielles Problem, sondern ich wollte mal ein paar allgemeine Meinungen zur Idee einholen.
Wie gesagt: Zu aufwendig (im Sinne von umfangreich), daher auch zu fehlerträchtig, und das bei zu wenig realem (im Sinne von absolut) Geschwindigkeitsvorteil.
- Du scheinst gar keine genaue Vorstellung davon zu haben, wie groß das Ziel ist und wie es sich bewegt
Muss man das denn immer?
Nein, nicht immer, aber es ist im Allgemeinen schon sinnvoll, zu wissen, was man attakiert - selbst wenn man nur forscht.
Wenn ich sehe dass mit (IMHO) halbwegs vergleichbaren Maßnahmen Einsparungen um den Faktor 10-50 realisiert werden, ist das für mich durchaus ein Gebiet, wo es sich löhnt mal drüber nachzudenken,
Faktoren sind relativ. 10 bis 50 sieht für sich alleine gut aus, zugegeben, aber ist das auch noch der Fall, wenn es um kokrete Zahlen geht, beispielsweise die Entscheidung zwischen 0.1 oder 5 Tausendstel Sekunden? Und das insbesondere angesichts der Tatsache, daß das Programm nach dem 0.1 oder 5 Millisekunden-Start eine halbe Minute läuft, weil es soviele Daten verarbeiten muß?
Aber wie gesagt: Du hast einen anderen Blickwinkel angesetzt als ich.
verwende ich aber keine statische HTML-Seite, sondern nur einen File-System-Check und einen 304 Header, was sicher schneller ist als statisches HTML.
Nein, da befindest Du Dich nun wirklich auf dem Holzweg. Der Apache liest von ganz alleine die Dateiinfos und sendet dann gegebenenfalls ein Not Modified. Ausgelesen wird die Datei nur, wenn es wirklich sein muß.
Bei einer statischen Datei betreibst Du also einen noch größeren Aufwand: Beide Varianten (Apache alleine sowie Apache plus Deine mod_rewrite-Konstruktion) prüfen das Änderungsdatum der Datei, Du bringst hingegen auch noch mod_rewrite ins Spiel.
Dazu kommt dass der Client die Daten meist aus dem eigenen RAM holen kann.
Der Client hat damit nichts zu tun, ob er nun von mod_rewrite oder von PHP ein Not Modified geschickt bekommt, ist ihm vollkommen wurscht, er weiß es nicht einmal.
Warum? Deinen Ausführungen nach zu urteilen ist die ganze Angelegenheit fürchterlich komplex.
Meinst Du meine Caching-Idee?
Nein, die Anwendung, die die Daten sammelt und ausgibt.
Interpretersprachen waren noch nie für komplexe Aufgaben zu gebrauchen und werden es nie sein,
Ja? Das sehe ich anders. Mit PHP lassen sich auch recht komplexe Anforderungen erfüllen, genauso wie man mit Sprachen wie Java oder C++ extremen Müll fabrizieren kann.
Interpretersysteme haben grundsätzlich den Nachteil, daß sie bei jeder Ausführung neu interpretiert, also in entsprechende Anweisungsblöcke für den Prozessor übersetzt werden müssen. Das gilt auch, wenn der Programmcode vorverarbeitet in einem Cache zwischengespeichert wird, denn auch hier muß immer noch eine Anweisungsliste umgesetzt werden. Dazu kommt, daß durch die Vereinfachung, die den meisten Interpretersprachen zu eigen ist, auf die Hardware abgestimmte Optimierungen nur schwerlich möglich sind.
Liegt das Programm hingegen bereits in Maschinencode vor, also als ausführbare Binärdatei, wird dieser Arbeitsaufwand des Interpreters komplett gespart.
Das soll nun aber nicht automatisch bedeuten, auf eine CGI-Anwendung zu wechseln; da kann man vom Regen in die Traufe kommen. Ideal wäre hingegen ein eigenes, echtes Apache-Modul.
Mit "komplex" meine ich weiterhin nicht unbedingt "umfangreich", also viele Seiten und Funktionen umfassend, sondern vielmehr die reine Masse an Aufgaben, die hintereinander abgearbeitet werden muß, die reine Ausführungsgeschwindigkeit.
Versuche mal, mittels PHP eine Grafikdatei pixelweise zu bearbeiten, zum Beispiel ein Mosaik daraus zu machen. Das ist eine einzelne Aufgabe, also ganz und gar nicht umfangreich, aber sie erfordert doch die Berechnung einer großen Menge Daten. Während ein ausführbares Programm fröhlich die hunderttausendste Grafik verwurstet, wirst Du mit PHP (lies: einem Interpretersystem) schon an der ersten verzweifeln.
Nebenbei: Java ist von Haus aus auch eine Interpretersprache.
egal wie c00l das Dingens gerade ist, insofern benutzt Du mit PHP möglicherweise schlichtweg das falsche Werkzeug.
Wie kommst Du jetzt auf einmal auf eine "PHP ist doof" Diskussion?
Wo habe ich bitte geschrieben, daß PHP doof sei? Es gibt Anwendungsgebiete, auf denen ein System X einfach nicht mit einem System Y mithalten kann. Punkt, so ist das nunmal.
Mit meiner Anmerkung "egal wie c00l" wollte ich in gewisser Hinsicht genau auf Deine obige Reaktion abzielen: Anstatt die Grenzen von PHP anzuerkennen wird dieses System auf Teufel komm raus verteidigt. Damit fällt man aber früher oder später auf die Nase.
Das ist übrigens nicht auf PHP beschränkt, das gleiche ist den Leuten passiert, die vor Jahren mit Java ein komplettes Office-System geschrieben haben: War ganz fürchterlich c00l und modern, weil Java seinerzeit gerade ganz krass mega-in war - aber wer damit einen simplen Brief schreiben wollte, hat sich lieber die olle Schreibmaschine aus dem Schrank geholt.
Interpretersysteme, auch PHP, haben den großen Vorteil, daß man mit ihnen einfach und schnell bestimmte Aufgaben programmieren kann. Der Nachteil ist, daß diese Aufgaben bei weitem nicht so schnell erledigt werden können wie mit Maschinencode.
Und bevor Du Dich weiter auf irgendeine bestimmte Sprachform festlegst: Auch Assembler kann schneckenlangsam sein, wenn man es nicht wie üblich in Maschinencode übersetzt, sondern einen Assembler-Interpreter verwendet.
Und wenn Du aus PHP-Scripten HTML-Dateien erzeugst und zwischenspeicherst, dann ist das für mich auch eine Art des Caching.
Ja, richtig, und? Das habe ich doch eingangs als Alternative vorgeschlagen: Bei Änderung der Daten neue HTML-Dateien erstellen und die persönlichen Vorlieben (z.B. das Datumsformat) per Javascript außerhalb des Servers umsetzen.
Gruß,
soenk.e
Hallo!
Ich versuche lediglich, so früh zu optimieren, wie eben möglich. Was habe ich davon erstmal zig Sachen zu laden, die Last verursachen, wenn ich dem Server diese Arbeit doch zum großen Teil ersparen kann?
Gegenfrage: Was habe ich davon, zig Sachen zu programmieren, wenn ich am Ende nicht merke, überhaupt etwas gemacht zu haben?
Oh, das merkt man durchaus wenn nur genügend User die Applikation gleichzeitig verwenden und die Antwortzeiten im Rahmen bleiben - und davon kann ich ausgehen.
Es ist eine Abwägung zwischen Komplexität und Geschwindigkeitsvorteil. Mir persönlich erscheint Deine Vorgehensweise viel zu aufwendig und -wichtiger- fehlerträchtig, relativ gesehen zum tatsächlichen, absoluten Geschwindigkeitsvorteil.
Was ist daran denn komplex? Die RewriteRule schreibe ich so einmal in die httpd.conf, dann wird die direkt beim Serverstart geladen, und ich mache maximal einen Rewrite, genau das mache ich heute auch schon, es kommen nur 3-4 Mustervergleiche dazu. Ich würde es liebend gerne testen, habe auch schon ein nettes Tool hierfür(M$ Web Application Stress Tool), jetzt brache ich nur noch die Testumgebung, leider habe ich da keine Möglichkeit vor Weihnachten. Würde gerne ein bisschen testen.
Jedenfalls muss ich nur einmal die RewriteRule anpassen, und dann nur noch in der Applikation dafür sorgen, dass die Cache-Dateien entsprechend erzeugt und gelöscht werden. Und hierfür würde ich eine Klasse entwickeln, mit entsprechenden Methoden die die ganze Arbeit übernehmen.
Im Prinzip würde ich das dann so verwenden:
$cache = new Cache;
// um die aktuelle Seite cachen zu lassen:
$cache->createCache();
// um bei Änderungen die Cache-Files von 2 anderen Scripten zu löschen:
$cache->clearCache($dir,$script,$query_string);
$cache->clearCache($dir,$script2,$query_string2);
Nur ist vor allem letzters kein gutes Design, da muss ich nochmal ein bisschen nachdenken wie ich das sauberer machen kann. Vielleicht müsste ich alle Caching-Scripte irgendwo zentral verwalten, udn könnte dann IDs... verwenden... mal sehen.
Die Klasse jedenfalls kümmert sich um den ganzen Rest. Und besonders aufwendig ist auch das nicht. Wenn ich jetzt davon ausgehe dass ich ca. 20 Scripte habe, die was an Daten verändern, und das ist auch meistens nicht sonderlich komplex so dass es vielleicht im Schnitt 1-2 Seiten sind, die von Änderungen die über dieses Script eingegeben wurden, betroffen sind. Und dann muss ich auch nicht alle Seiten cachen, bei manchen macht es mehr Sinn, bei manchen weniger. Wenn ich eine Seite nicht cache, ist das Risiko eines Fehlers durch mein Caching-Framework exakt === 0.
Und die "read-only" Seiten, die deutlich überwiegen, kann ich mit der kleinen Zeile oben ganz einfach cachen. Ganz ohne Parameter, die hole ich mir woanders her oder übergebe sie vorher(nicht im eigentlichen Script) an die Konstruktor-Funktion.
Man könnte die Geschichte auch noch auf die Spitze treiben und sagen, daß das, was Du an Personalkosten für Optimierungen verursachst, nie und nimmer auf der Hardwareseite eingespart werden kann.
Da sei Dir mal nicht so sicher, die Software ist keine Einzel-Installation (Außerdem weißt Du nicht wie wenig ich verdiene ;-)).
Außerdem finde ich es einfach interessant und mache das größtenteils in meiner Freizeit.
Wenn ich sehe dass mit (IMHO) halbwegs vergleichbaren Maßnahmen Einsparungen um den Faktor 10-50 realisiert werden, ist das für mich durchaus ein Gebiet, wo es sich löhnt mal drüber nachzudenken,
Faktoren sind relativ. 10 bis 50 sieht für sich alleine gut aus, zugegeben, aber ist das auch noch der Fall, wenn es um kokrete Zahlen geht, beispielsweise die Entscheidung zwischen 0.1 oder 5 Tausendstel Sekunden?
Das Problem sind weniger Antwortzeiten einzelner Requests, sondern die Gesamtlast zu Lastspitzen.
Und das insbesondere angesichts der Tatsache, daß das Programm nach dem 0.1 oder 5 Millisekunden-Start eine halbe Minute läuft, weil es soviele Daten verarbeiten muß?
Das verstehe ich jetzt nicht?!
verwende ich aber keine statische HTML-Seite, sondern nur einen File-System-Check und einen 304 Header, was sicher schneller ist als statisches HTML.
Nein, da befindest Du Dich nun wirklich auf dem Holzweg. Der Apache liest von ganz alleine die Dateiinfos und sendet dann gegebenenfalls ein Not Modified. Ausgelesen wird die Datei nur, wenn es wirklich sein muß.
Aber woher zum Henker weiß Dein Apache dass ich was in der DB geändert hat, was sich auf die Ausgabe auswirkt? Und wie regelt es der Apache dass er die Datei ggfs. von PHP aktualisieren lässt?
Bei einer statischen Datei betreibst Du also einen noch größeren Aufwand: Beide Varianten (Apache alleine sowie Apache plus Deine mod_rewrite-Konstruktion) prüfen das Änderungsdatum der Datei, Du bringst hingegen auch noch mod_rewrite ins Spiel.
Nein, nein, die Cache-Datei die ich erzeuge sind leer. Sie dienen einzig und alein als Infgormationsträger um aus mod_rewrite heraus in der Lage zu sein zu entscheiden ob 304-Header oder Script-Ausführung.
Interpretersysteme haben grundsätzlich den Nachteil, daß sie bei jeder Ausführung neu interpretiert, also in entsprechende Anweisungsblöcke für den Prozessor übersetzt werden müssen. Das gilt auch, wenn der Programmcode vorverarbeitet in einem Cache zwischengespeichert wird, denn auch hier muß immer noch eine Anweisungsliste umgesetzt werden. Dazu kommt, daß durch die Vereinfachung, die den meisten Interpretersprachen zu eigen ist, auf die Hardware abgestimmte Optimierungen nur schwerlich möglich sind.
Daher versuche ich diese ineffektiven Prozesse so weit wie möglich zu eliminieren, indem ich schon in der Apache-Konfiguration kläre iob die Daten aktuell sind oder nicht. Für den Fall dass sie aktuell sind - cache-Flag Datei vorhenden - dann wird ein 304-Header gesendet, sonst muss ich wohl oder übel den Interpreter bitten mit die Seite neu ztuammenzusetzen. Diese wird dann an den Client ausgeliefert der diese dann cached. gleichzeitig wird eine Cache-Flag Datei erzeugt anhand der der Apche beim nächsten Request weiß "aha, die Datei hat der Client schon lokal", also kann er mit 304 antworten.
Wo habe ich bitte geschrieben, daß PHP doof sei? Es gibt Anwendungsgebiete, auf denen ein System X einfach nicht mit einem System Y mithalten kann. Punkt, so ist das nunmal.
Ganz klar, siehe Forum, was das gebracht hat (wenn ich auch gerne mal im Vergleich eine mod_perl Variante sehen würde).
Aber INterpreter-Sprachen haben auch entscheidende Vorteile. Die Entwicklungs-Zeit ist erheblich kürzer, und es gibt gerade bei PHP sehr viele Bibliotheken, die einen Entwickler in eben solchen komplexen Web-Applikationen sehr gut unterstützen. Ich wolt emeien Anwendung nicht in C schreiben müssen...
Mit meiner Anmerkung "egal wie c00l" wollte ich in gewisser Hinsicht genau auf Deine obige Reaktion abzielen: Anstatt die Grenzen von PHP anzuerkennen wird dieses System auf Teufel komm raus verteidigt. Damit fällt man aber früher oder später auf die Nase.
Vollkommen richtig, nur halte ich PHP nach wie vor für die beste Sprache für Web-Applikationen, so lange es nicht zu groß oder zu komplex wird.
Und wenn Du aus PHP-Scripten HTML-Dateien erzeugst und zwischenspeicherst, dann ist das für mich auch eine Art des Caching.
Ja, richtig, und? Das habe ich doch eingangs als Alternative vorgeschlagen: Bei Änderung der Daten neue HTML-Dateien erstellen und die persönlichen Vorlieben (z.B. das Datumsformat) per Javascript außerhalb des Servers umsetzen.
Und wie mache ich das mit den GET-Parametern? EIn großer Vorteil ist ja, dass ich im Prinzip so jeden Request cachen kann.
Grüße
Andreas