PHP Blogger

Startseite Schreib mir ne Mail! RSS Abo Webnews

Objektorientierung vs. Performance

So schnell können Wünsche in Erfüllung gehen Julius ;) Das mit dem Artikelwunsch ist eine prima Sache für Autoren. Ich gebe zu, in letzter Zeit bin ich wenig fantasievoll, was Artikelthemen angeht. Dann schreibt man halt über ein Thema, das einen selbst gerade beschäftigt und natürlich nutze ich meinen Blog auch dazu, Lösungswege für mich (und die Öffentlichkeit) festzuhalten.

Performance als Thema ist immer so eine Geschichte. Bei den meisten kleinen Projekten eher präventiv zu sehen, ist es bei Business-Projekten mit hohen Zugriffszahlen und/oder gigantischen Datenbankgrößen ein nicht unwesentlicher Aspekt bei der Webentwicklung.

Aber aus Spiel und Spass kann schnell ein großes Projekt werden, weil es das mehr oder minder breite Publikum begeistert und die Zugriffszahlen in die Höhe schießen lassen und die Entwicklung mit dem Tuning nicht mehr nachkommt. In diesem Fall (und allen anderen) rechnet sich dann eben eine sorgfältige leicht paranoide Planung der Entwicklung nach dem Motto, was wäre wenn…

…mein Projekt wirklich erfolgreich wird. Hehe. Die meisten Projekte werden es nämlich nicht. Um dem Grund allen Übels auf den Grund zu gehen, machen wir mal eine kleine Reise durch die Geschichte der Performance:

Ganz früher

Irgendwann mal waren Rechner und Server kleine poplige Maschinen, bei denen man stolz war, wenn sie 3 statische HTML Seiten gleichzeitig ausliefern konnten. Damals wurde der Performance Wust noch durch laaaaaaaaaaangsame Internetverbindungen gebremst. Bei einem 14000er Modem wurde die Datenübertragung noch mit Bit/Sekunde berechnet. Da war einfach nicht klar, warum eine Webseite nun 30 Sekunden für den Aufbau benötigt hat:

  1. War der Rechner einfach zu lahm?
  2. Die Verbindung zur Vermittlungsstelle so schlecht?
  3. Der Provider überlastet?
  4. Der Server überflutet mit Anfragen?
  5. Die Grafiken viel zu pompös?

Warten war da an der Tagesordnung: Für einen 10 MB Download hat man da schon mal eine Stunde oder länger gewartet. Das geht heute natürlich nicht mehr. Über zum Glück sind nicht nur die Datenleitungen gewachsen, die die Bits und Bytes der Anfragen schneller auf einen Server einprasseln lassen, sondern auch die Server sind leistungsfähiger geworden.

Alles nur Spass

Aber bei der Entwicklung und Programmierung ist es leider nicht anders als bei Spielen. Ich kann mich noch daran erinnern, das ich mal gesagt habe “Bald hab ich einen Pentium 1, dann läuft Indiana Jones endlich flüssiger als auf meinem 486er”. Der PC Triumph über Datasette mit 10 Minuten Ladezeit für ein Game wurde leider dadurch gedrückt, das mit den PCs auch die Games in Größe und Leistungshunger gewachsen sind.

Der Stammbaum

Wie gesagt: das gleiche Problem haben wir jeden Tag beim Entwickeln: Sobald die Leistung der Maschinen wächst, wächst auch der Anspruch des Entwickler-Menschen: Da sind Assembler und Kobol einfach nicht mehr genug. Da müssen Objekte und Schnittstellen her. Objekte kommen auch nicht aus dem nichts, sondern werden über Väter- und Mutter-Klassen, Großvater- und Urgroßvater-Klassen von einem Interface abgeleitet.

Globale Variablen? Bäh. Die wurden von ein paar fleissigen OOP-Spezialisten von Singleton-Mustern abgelöst und jetzt ist auch das zu unsauber entwickelt. Singleton ist pfui, es müssen Action-Controller und View-Generatoren her. Der Kampf von Objektorientierung gegen die Performance hat begonnen.

Was mit der Erkenntnis anfangen?

Das klingt jetzt so, als wäre der PHP Blogger ein OOP-Gegner. Hehe. Ach quatsch, so ist es auch nicht. Ich möchte nur über den Kompromiss berichten, den man als Entwickler von Web-Applikationen jeden Tag machen muss.

Muss jedes einzelne Website-Element dynamisch generiert und ausgeliefert werden? Statisch im Dateisystem abgelegte Elemente sind einfach immer schneller ausgeliefert, als zur Laufzeit aus der Datenbank exportierter oder serialisierter Objekt-Content.

Pro und Contra

Mal kurz innehalten und überlegen, was man alles statisch ablegen kann:

  • Grafiken, die im Tempplate und CSS abgelegt werden
  • Downloads, die für jeden abrufbar sind
  • Javascripts, die keine großen Geheimnisse beinhalten
  • Inhaltsseiten, die nur sehr selten geändert werden

Natürlich kann man diese Liste noch ein wenig fortführen. Die Tendenz zu Inhalten, die dynamisch verwaltet werden können, ist hoffentlich auch klar geworden:

  • Geschützte Inhalte, die auf einem komplexen Rechtesystem basieren
  • Personalisierte Inhalte, die häufig in Benutzerportalen verwendet werden
  • Login-Bereiche
  • Dynamische Seiten, die vom Benutzer verändert werden können (Wikis, Blogs, usw)

Auch diese kurze Liste ist sicherlich noch erweiterbar. Es gilt also ganz klar festzuhalten:

  1. Es gibt Inhalte, die auf Grund Ihrer Art dynamisch ausgeliefert werden müssen.
  2. Was dynamisch mit Hilfe einer Programmiersprache dynamisch generiert wird, sollte auf gutem und flexiblen Code basieren.
  3. Objektorientierung kann (richtig angewendet) die Wartung eines Codes beträchtlich vereinfachen.
  4. Möglichst fein gegliederte Objektstrukturen haben einen extrem hohen Wiederverwendungswert und so kann man meistens zentral Fehler beseitigen und trotzdem eine dezentrale Wirkung erreichen.

Eine schöne, logische Codebasis ist also essenziell. Ganz klar. Hat aber eben auch den Nachteil, das alles was der Entwickler so schön dezentralisiert und durch die Gegend vererbt hat, von einem armen Prozessor wieder zusammengepuzzelt werden muss. Das braucht Zeit, Speicher und damit eben auch Performance.

Wie jetzt was

Genau, wie geht man mit dem Dilemma jetzt am Besten um? Wir brauchen die Objektorientierung, wir brauchen Patterns, aber wir brauchen auch Performance.

Eine Lösung ist sicherlich ein ausgeklügeltes Cache-System. Mit einem sehr guten Cache, kann man alles cachen. Es gibt nichts, was man nicht cachen kann. Das Geheimnis, das einen Cache wirklich wirkungsvoll macht, ist sicherlich die Methode, die zum Aktualisieren des Caches führt. Denn Cache muss immer aktuell sein. Und gerade, wenn man mit personalisierten Inhalten arbeitet, die die Besucher am Ende selbst festlegen können, wird es spannend: Wie zum Kuckuck teilt man dem Cache mit, das er an einer bestimmten Stelle aktualisiert werden muss? Wie identifiziert man zu aktualisierende Cacheinhalte?

Fragen über Fragen. Die kann ich natürlich am Rande diesen Artikels nicht beantworten. Einen Cache zu bauen ist ein Thema für sich. Sehr anspruchsvoll. Denn auch Cachen sollte man nicht übertreiben - schließlich kann die Neuberechnung eines Caches länger dauern und mehr Performance kosten, als ein Generator, der alles zur Laufzeit zusammenbaut.

Ein Cache ist also sicherlich nur eine Teillösung, kein Allheilmittel. Aber es unterstützt die Objektorientierung, in dem es im besten Fall einer Maschine wieder Performance zurückgibt.

Wer gerne objektorientiert programmiert, sollte daran denken, es nicht zu übertreiben. Elemente, die er statisch ausliefert schenken dem Entwickler und seinem Code nämlich auch Performance. Und so wird ein entspannter und solider Webserver-Betrieb garantiert.

Nochmal Zusammenfassend

  1. So viel wie möglich mit statischen Elementen arbeiten
  2. Ein ausgeklügeltes Cache-System einsetzen
  3. Die gewonnene Performance für Objektorientierung und klar strukturierten Code verwenden

Ich muss weg.

Ähnliche Artikel:

  1. Linktipps: Performance und Produktivität
  2. Wo ist meine MySQL Performance?
  3. MySql Performance steigern
  4. Sei ein Objekt-Schwein!
  5. Performance durch PHP Benchmarks

Julius meint dazu:

5. Februar 2009 um 17:33

WOW! Ich bin baff!

Also erstmal Danke und natürlich Respekt für den literarischen Blitzschlag hier im Blog.

Mit dem Cachen hast du völlig recht, ich selbst sitze gerade mit einem Team von ein paar Leuten an einer neuen “Webapp.” und unser Framework wird auch ständig optimiert. Bei mir hat sich da ironischerweiße auch schon diese Paranioa breitgemacht … “was, das WAF braucht 0.012sec zum rendern der Seite, gestern waren es doch nur 0.006sec, was ist hier los” und schon wird will drauf rumoptimiert. Das muss nich immer der richtige Weg sein.

Ein bisschen vorrausschauen ist sicher nicht schlecht, wenn man die Regeln kennt, warum dann nicht von Anfang an anwenden? Jedoch wird eine Applikation in der Regel wirklich erst dann optimiert, wenn Grund dazu besteht. Ansonsten sollte man sich anderen Sachen widmen.

unset meint dazu:

6. Februar 2009 um 11:37

@Julius: Ein paar Millisekunden pro Seitenauruf sollten zumindest nicht dazu führen, dass der Code deswegen unübersichtlich wird.

Ich habe vor einiger Zeit einen Blogpost gelesen, wo die RAND()-Funktion von MySQL gegen ein mehrzeiliges Konstrukt abgelöst wurde, welches dann einen (IMHO nicht entscheidenden) Performancegewinn einbrachte. Ich denke aber, das ist am falschen Ende optimiert. Der Code war so gut wie unwartbar (ok, wie oft wird man da wohl noch ranmüssen) und kostet am Ende des Tages mehr als ein Riegel RAM mehr oder ein etwas besserer Prozessor.

Zum Artikel: Cachen ist in der Tat ein unglaublich komplexes Thema zu dem sich viele Schlaue Leute die Köpfe zerbrochen haben. Das schlimme ist: So wirkliche Best Practices gibt es hier nicht, denn so gut wie jede Applikation hat eine andere Struktur sowie einen anderen Codeflow - im Grunde muss man das jedesmal neu entscheiden und konzipieren.

Mario H. meint dazu:

15. Februar 2009 um 15:12

Und dann gibt es noch diverse Cache-Varianten, und dann werden auch noch mehrere Server benutzt, die den Cache abgleichen müssen… ;-)
Schon sehr komplex, das stimmt. Aber richtig angewandt, ist Caching schon super, insbesondere, wenn man diese lahmen PHP-Frameworks nutzt ;-)

WasDuSuchst meint dazu:

19. Februar 2009 um 22:06

Zum Thema Cache akualisierung finde ich den Ansatz von Microsoft nicht schlecht
es über CacheDependencies zu lösen.

http://jeffgermain.wordpress.com/2008/08/20/cache-dependency-in-aspnet/

WasDuSuchst meint dazu:

19. Februar 2009 um 22:08

Ups, falscher Link ;-)

http://msdn.microsoft.com/en-us/magazine/cc163955.aspx

Daniel meint dazu:

21. Februar 2009 um 11:53

Also der Wunsch war ja wirklich mal nicht schlecht. Erst war ich zwar noch etwas skeptisch, was man denn da schreiben könnte, aber ich glaube, dass das gar nicht mal so schlecht ist was hier steht. Vieles kann ich wirklich nachvollziehen und sehe ich auch so. Bei einigen Sachen hätte ich aber die Ausarbeitung etwas anders gemacht, Die Punkte sind vielleicht etwas zu oberflächlich behandelt aber ansonsten finde ich den Beitrag wirklich gut und der Tipp für so einen Artikel war nicht schlecht.

Christian meint dazu:

1. März 2009 um 17:39

Frage:
Ich kenne mich in diesem Bereich nicht so gut aus. Ich bin noch nicht lange auf diesem Gebiet unterwegs und mich würde ja echt einmal interessieren, was es mit diesem Cache auf sich hat. Was ist das denn genau und für was brauche ich das? Geht das vielleicht von alleine oder kann ich da irgendwas dafür oder dagegen machen? Ich kann mit dem Begriff wirklich nicht viel anfangen und bei Google kommen immer nur so komplexe Texte die kein Mensch mehr versteht. Ich würde mich freuen, wenn ich ein paar Antworten bekommen könnte.

timi meint dazu:

13. März 2009 um 14:01

Also eine Cache-Implementierung funktioniert leider nicht vollautomatisch. Da jede Webseite/Blog/Forum bzw. eine andere Webapplikation anders gebaut ist und sehr stark in Bezug auf die Architektur variieren, muss ein Cache immer selbst entwickelt oder angebunden werden.

Natürlich gibts fertige Cache-Engines, die haben allerdings immer nur einen generellen global gesehenen Ansatz und sind deshalb meist nicht so effizient, wie eine Individual-Lösung.

timi meint dazu:

13. März 2009 um 14:36

@WasDuSuchst: Danke für den Link!

Markus meint dazu:

15. März 2009 um 00:41

Habe ich kürlich bei einer Recherche gefunden: http://adventure-php-framework.org/Seite/103-Yii-vs-APF Klingt für mich wie die Symbiose aus gervorragender Performance und gutem Design. Meiner Meinung nach einen Test wert…

Bernhard H. meint dazu:

4. Oktober 2009 um 01:59

Zahlen? Hat jemals jemand geschaut wie lange es den Compiler braucht ein Objekt zusammenzustellen? Dazu kann man das sogar sehr einfach cachen (APC, Zend). Oft ist die Datenbank der “bottleneck”. Und der ist so eng, dass die Codeschönheit ohne Probleme beibehalten werden kann.

webdesigner meint dazu:

1. November 2009 um 16:26

Wie immer machts der Mix! Bei großen Projekten kommt man an der OOP nicht vorbei besonders wenn die Seite ständig gewartet werden muß. Na ja, zum glück gibt es gute Frameworks wie das von Zend :)

Robert meint dazu:

15. Januar 2010 um 02:46

Der Artikel ist schon ein paar Tage alt, aber ich möchte gern noch paar Worte über das Thema verlieren. Also zu allererst, wirklich gut geschrieben das Ganze. Man muss teilweise differenzieren, wo in einer Applikation die Probleme liegen, meistens sind Webseiten I/O-Bound, was schonmal ein wenig Grund gibt schlechteren Code für die Maschine (ich bezeichne OOP in PHP mal als solches) und besseren Code für den Menschen zu formulieren.

Irgendwo habe ich letztens einen Link gehabt, dass schlechter Code auch gut für die Entwicklung/Fortschritt ist - eine kleine Legitimierung für Wordpress also. Aber solche Scripte laufen meist nie unter starker concurrency und wenn wird es mit Geld abgefangen, was in Hardware gesteckt wird.

Ich kenne genug Leute, die sich lieber ein neues BladeCenter ins Rack krachen als sich mal einen Tag hinsetzen und das System bisschen optimieren. Zumal man mit neuer Hardware meist nur einen Faktor von 10-100 raus holen kann und ein richtig gesetzter Index eine 10.000fache Beschleunigung bedeuten kann.

Ich bin mir nicht sicher, aber ich glaube Amazon hat mal etwas darüber veröffentlicht, wenn die Seite nur 0,x Sekunden schneller läd wachsen proportional die Prozente der Verkäufe, was sicher ein Resultat geworden ist, dass der Großteil der Seiten die wir kennen (google, …) schnell sind und dieses Verwöhnte Performance-Feeling bei jeder Seite - egal welcher Komplexität - voraussetzen.

Noch ein paar Worte zum Thema caching. Je größer eine Applikation (ich möchte nicht von Webseiten sprechen, da ein solcher “dynamischer” Programmierstil eigentlich überall anwendung finden kann) desto mehr muss man sich von Echtzeit-Applikationen verabschieden. Die Kunst liegt dann lediglich daran es aussehen zu lassen, als wäre es alles dynamisch. Dafür benötigt man eine ausgeklügelte Cache-Strategie, die sicher genauso geplant sein sollte wie das Schema der Datenbank. Ich arbeite momentan daran einen Hook in MySQL zu prügeln um aus der Datenbank heraus caches zu invalidieren. Aber das ist wirklich ein anderes Thema :-)

Jastin meint dazu:

2. Februar 2010 um 12:38

Danke für die Links

RSS für Kommentare zu diesem Artikel · TrackBack URI

Schreib Deine Meinung