hotti: Studie: MySQL vs. Datei

Hi,

meine komplette Website (ca. 400 Einzelseiten samt Body u. Attributen) liegt in einer Binärdatei, diese hat eine Größe von ca. 1,3 MB.

Heute habe ich mir mal die Zeit genommen um zu vergleichen, was schneller ist: Das Einlesen der Datei oder die Herstellung einer DB-Verbindung, hier ist das Ergebnis, getestet auf meinem lokalen PC:

Zeit 1: 0.022984 sec EAV (Hash of Hashes aus Binärdatei komplett einlesen)
Zeit 2: 0.017170 sec FastEAV (Hash of Hashes aus Binärdatei komplett einlesen)
Zeit 3: 0.071052 sec Nur das Herstellen einer DB-Verbindung (noch keine Daten)

(EAV bzw. FastEAV sind zwei verschiedene Serializer aus eigener Entwicklung)

Das Ergebnis ist eindeutig: Aus der Datei gelesen, stehen die Daten sehr kurzfristig zur Verfügung, innerhalb dieser Zeit ist noch nicht einmal eine DB-Verbindung hergestellt.

Ein alter Hut: Die Gratwanderung zwischen Performanze und Speicherbedarf. Nach dem Herstellen einer DB-Verbindung könnte ich unter der Verwendung gezielter Abfragen mit deutlich kleineren Datenstrukturen und weniger Hauptspeicher-Bedarf arbeiten.

Mit der Dateilösung hingegen habe ich einen riesen Hash im Hauptspeicher, bei jedem Request entsteht ein Burst. Kommt mir da die Hardware entgegen, ist da was zu Cachen? Frage an Betreiber von Webservern, was steht da so draußen rum und kann es das ab...

Schöne Grüße

--
Wenn der Kommentar nicht zum Code passt, kann auch der Code falsch sein.
  1. Hi,

    Das Ergebnis ist eindeutig: Aus der Datei gelesen, stehen die Daten sehr kurzfristig zur Verfügung, innerhalb dieser Zeit ist noch nicht einmal eine DB-Verbindung hergestellt.

    Na und?

    Eine DB hat doch ganz andere Vorteile ggü. einer Datei?!

    Luk

  2. Das Ergebnis ist eindeutig: Aus der Datei gelesen, stehen die Daten sehr kurzfristig zur Verfügung, innerhalb dieser Zeit ist noch nicht einmal eine DB-Verbindung hergestellt.

    70 ms für den Aufbau einer DB-Verbindung sind aber arg langsam. Welche Technologie nutzt du denn?

    Mit der Dateilösung hingegen habe ich einen riesen Hash im Hauptspeicher, bei jedem Request entsteht ein Burst. Kommt mir da die Hardware entgegen, ist da was zu Cachen? Frage an Betreiber von Webservern, was steht da so draußen rum und kann es das ab...

    Riesen Hash? Burst? Bitte beschreib das mal genauer.

    1. Das Ergebnis ist eindeutig: Aus der Datei gelesen, stehen die Daten sehr kurzfristig zur Verfügung, innerhalb dieser Zeit ist noch nicht einmal eine DB-Verbindung hergestellt.

      70 ms für den Aufbau einer DB-Verbindung sind aber arg langsam. Welche Technologie nutzt du denn?

      Perl/DBI/connect_cached, aber mein PC ist ja auch kein Maßstab. Auf dem produktiven Server geht das alles 10mal schneller.

      Riesen Hash? Burst? Bitte beschreib das mal genauer.

      Vergessen wir's. Das ist alles überarbeitungsbedüftig und ich bin da schon dran :)

      Danke und Grüße an Alle.

  3. Hallo,

    Mit der Dateilösung hingegen habe ich einen riesen Hash im Hauptspeicher, bei jedem Request entsteht ein Burst. Kommt mir da die Hardware entgegen, ist da was zu Cachen?

    Naja, im Prinzip hast Du ja schon so etwas wie einen Cache gebaut, in dem Du alle Daten zu Beginn in den Hauptspeicher lädst (ob von Platte oder Datenbank ist ja dann eigentlich schon egal).

    Eine Datenbank wird ja immer dann interessant, wenn Du genau das (also das Laden sämtlicher Daten in den Speicher) mangels genug Arbeitsspeicher eben nicht mehr bewerkstelligen kannst und gezeilt einzelne Daten abfragen musst. So lange Du aber alles in den Hauptspeicher lädst, wird ein Flatfile IMMER schneller sein als eine Datenbank.

    Den Overhead für das Aufbauen einer Verbindung kann man übrigens dadurch reduzieren, dass man die Datenbankverbindung offen lässt. In  einer klassischen CGI-Umgebung ist das natürlich Quatsch (denn  da werden nach jedem Request üblicherweise sämtliche File-Handle und somit auch Datenbankverbindungen geschlossen), aber mit FCGI z.b. kann man ja durchaus Mechanismen bauen, bei denen beim Server-Start eine Verbindung aufgebaut wird, die dann für alle Requests gehalten wird.

    Noch besser ist es, nicht nur eine DB-Verbindung einzusetzen, sondern einen Connection Pool, der dann gleich eine ganze Reihe von Datenbank-Verbindungen vorhält.

    Viele Grüße,
    Jörg

    1. Mit der Dateilösung hingegen habe ich einen riesen Hash im Hauptspeicher, bei jedem Request entsteht ein Burst. Kommt mir da die Hardware entgegen, ist da was zu Cachen?
      Naja, im Prinzip hast Du ja schon so etwas wie einen Cache gebaut, in dem Du alle Daten zu Beginn in den Hauptspeicher lädst (ob von Platte oder Datenbank ist ja dann eigentlich schon egal).

      Wenn das aber bei jedem Request passiert, obwohl nur das HTML von einer der 400 Seiten ausgeliefert werden soll, klingt das für mich naiv erst mal so, als würden 99,75 % der Daten unnötig geladen.

      Es wäre sicherlich sinnvoller, das nicht insgesamt „in den Hauptspeicher zu ‚cachen‘“, sondern zum Beispiel in der Binärdatei vorne einen Index einzufügen, welcher Inhalt an welchem Offset liegt, diesen Index auszulesen, dann direkt zum passenden Offset zu springen und noch mal das auszulesen, was benötigt wird.

      Eine Datenbank wird ja immer dann interessant, wenn Du genau das (also das Laden sämtlicher Daten in den Speicher) mangels genug Arbeitsspeicher eben nicht mehr bewerkstelligen kannst und gezeilt einzelne Daten abfragen musst.

      Das ist für meinen Geschmack dann aber doch einen Tick zu pauschal formuliert. Datenbanken werden doch nicht deshalb genutzt, weil einem sonst der Speicher ausgeht.

      So lange Du aber alles in den Hauptspeicher lädst, wird ein Flatfile IMMER schneller sein als eine Datenbank.

      Auch das möchte ich vorsichtig bezweifeln beziehungsweise um Klärung bitten, was du da im Detail vergleichst.

      Den Overhead für das Aufbauen einer Verbindung kann man übrigens dadurch reduzieren, dass man die Datenbankverbindung offen lässt.

      Das muss trotzdem auch erst mal keine 70 ms dauern. Mit PHP und mysqli bin ich für einen Verbindungsaufbau zeitlich zum Beispiel in einer Größenordnung, in der es schon fast keinen Sinn mehr ergibt, das überhaupt zu messen (3-7 ms).

      Gruß Marc

      1. Hallo,

        Es wäre sicherlich sinnvoller, das nicht insgesamt „in den Hauptspeicher zu ‚cachen‘“, sondern zum Beispiel in der Binärdatei vorne einen Index einzufügen, welcher Inhalt an welchem Offset liegt, diesen Index auszulesen, dann direkt zum passenden Offset zu springen und noch mal das auszulesen, was benötigt wird.

        ...womit man grundsätzlich wieder so etwas ähnliches wie eine Datenbank baut. Aber ich gebe Dir grundsätzlich recht. Man müsste sich zwar das Verhalten im Einzelnen anschauen (nachdem das Betriebssystem ja i.d.Regel nicht Bitweise sondern Blockweise liest, kann es ggf. sein, dass es ohnehin einen Großteil der Daten bereits "auf den ersten Rutsch" hin einliest, und es somit keinen Unterschied macht), aber ich würde auch erstmal vermuten, dass das effizienter ist.
        Wobei eine andere Möglichkeit eben auch wäre, beim Start des Servers EINMALIG sämtliche Daten in den Arbeitsspeicher zu laden und dort zu halten. Dann werden bei jedem Request die Daten immer direkt aus dem Arbeitsspeicher geladen, und man benötigt überhaupt keinen Plattenzugriff mehr. Je nach Anwendungsszenario kann ich mir das schon sinnvoll vorstellen.

        Eine Datenbank wird ja immer dann interessant, wenn Du genau das (also das Laden sämtlicher Daten in den Speicher) mangels genug Arbeitsspeicher eben nicht mehr bewerkstelligen kannst und gezeilt einzelne Daten abfragen musst.

        Das ist für meinen Geschmack dann aber doch einen Tick zu pauschal formuliert. Datenbanken werden doch nicht deshalb genutzt, weil einem sonst der Speicher ausgeht.

        Das habe ich auch nicht behauptet. Aber wenn es um Performance geht (und darum ging es hotti ja), ist der Arbeitsspeicher der Applikation grundsätzlich unschlagbar. Wenn die Daten erstmal alle im Speicher liegen, ist ja auch eine Arbeit auf diesen Daten ein Leichtes. Filtern, Sortieren, usw. - das ganze dauert im Arbeitsspeicher ein paar Zyklen, also Peanuts.

        So lange Du aber alles in den Hauptspeicher lädst, wird ein Flatfile IMMER schneller sein als eine Datenbank.

        Auch das möchte ich vorsichtig bezweifeln beziehungsweise um Klärung bitten, was du da im Detail vergleichst.

        Ich gehe von einer frisch gestarteten Datenbank aus.
        Wenn ich ALLE Daten aus einem Flatfile lese, dauert es so lange, wie eben das physische Einlesen von der Platte dauert.
        Wenn ich ALLE Daten aus einer Datenbank lese (SELECT * FROM... or whatever), so muss die Datenbank

        • Meinen Datenbank-User authentifizieren
        • Meine Abfrage ("SELECT * FROM...") parsen
        • Die Rechte für diese Abfrage prüfen
        • Einen Ausführungsplan erstellen (gut sollte in dem Fall trivial sein, also full-table-scan)
        • Die benötigten Datensegmente bestimmen und diese von der Platte in den Arbeitsspeicher laden
        • Eine Antwort zusammenbauen und diese wieder an meine Anwendung schicken.

        Das KANN also schonmal nicht so schnell sein, wie wenn ich es direkt aus einer Datei lade.
        Was anderes ist es natürlich, wenn ich dieselbe Abfrage MEHRFACH stelle. Hier kann man davon ausgehen, dass die Datenbank das Abfrageergebnis in irgendeiner Form cached, sprich, das Ergebnis bereits im Arbeitsspeicher vorliegen habe.
        Wenn ich aber beim Start der Applikation EINMALIG (also nicht bei jedem Request) ALLE Daten in den Arbeitsspeicher lade, so muss das Flatfile zwangsläufig schneller sein.

        Den Overhead für das Aufbauen einer Verbindung kann man übrigens dadurch reduzieren, dass man die Datenbankverbindung offen lässt.

        Das muss trotzdem auch erst mal keine 70 ms dauern. Mit PHP und mysqli bin ich für einen Verbindungsaufbau zeitlich zum Beispiel in einer Größenordnung, in der es schon fast keinen Sinn mehr ergibt, das überhaupt zu messen (3-7 ms).

        70ms kommt mir auch sehr viel vor, aber dazu müsste man mehr über das Setup wissen. Welche Datenbank, welcher Datenbank-Treiber (in Perl, was hotti verwendet, gibt es ja z.b. C und Perl-Implementierungen, letztere ist m.E. etwas langsamer), ob die Datenbank auf derselben Maschine liegt wie die Applikation, was auf der Kiste sonst noch alles läuft etc.

        Jedenfalls ist es in den größeren Plattformen, in denen ich mich berufsbedingt herumtreibe, üblich, Connection Pools zu verwenden, weil da der Overhead für den Verbindungsaufbau sehr wohl ins Gewicht fällt.

        Viele Grüße,
        Jörg

        1. Hallo,

          Wobei eine andere Möglichkeit eben auch wäre, beim Start des Servers EINMALIG sämtliche Daten in den Arbeitsspeicher zu laden und dort zu halten. Dann werden bei jedem Request die Daten immer direkt aus dem Arbeitsspeicher geladen, und man benötigt überhaupt keinen Plattenzugriff mehr. Je nach Anwendungsszenario kann ich mir das schon sinnvoll vorstellen.

          Es hat bei mod_perl den Nachteil, dass der Server neu gestartet werden muss, wenn es bei den Daten Veränderungen gibt. Bei meinem FW gehts hauptsächlich um die Routing-Table, bisher hatte ich einen statischen und einen dynamischen Anteil dafür. Mit meinem neuen Konzept ist die RT nur noch dynamisch (optional mit der Möglichkeit, per Konfiguration etwa für temporäre Zwecke, einen statischen Teil anzuhängen).

          Dynamisch: Die Tabelle wird minimal und bei jedem Request neu erstellt. Sie enthält nur noch das, was für eine Response tatsächlich gebraucht wird, das ist zunächst der Name der Subklasse, hinzukommen alle für die Response konfigurierten Attribute (title, descr, usw) und ein paar weitere Einträge (URLs mit Attributen fürs Menu und den virtuellen Ordner, in dem sich die Antwortseite befindet).

          Ein etwaiger MEM-Cache würde im Prinzip so nach und nach ein vollständiges Abbild der RT im Hauptspeicher erstellen.

          Ich gehe von einer frisch gestarteten Datenbank aus.
          Wenn ich ALLE Daten aus einem Flatfile lese, dauert es so lange, wie eben das physische Einlesen von der Platte dauert.
          Wenn ich ALLE Daten aus einer Datenbank lese (SELECT * FROM... or whatever), so muss die Datenbank

          • Meinen Datenbank-User authentifizieren
          • Meine Abfrage ("SELECT * FROM...") parsen
          • Die Rechte für diese Abfrage prüfen
          • Einen Ausführungsplan erstellen (gut sollte in dem Fall trivial sein, also full-table-scan)
          • Die benötigten Datensegmente bestimmen und diese von der Platte in den Arbeitsspeicher laden
          • Eine Antwort zusammenbauen und diese wieder an meine Anwendung schicken.

          Das KANN also schonmal nicht so schnell sein, wie wenn ich es direkt aus einer Datei lade.

          Bis zu eine bestimmten Größe der Datei, abhängig vom Algorithums, vom IO-Vermögen des Systems, ist das tatsächlich so. Auf meinem derzeitigen Server schätze ich diese Grenze auf ca. 5MB (ab da wäre MySQL schneller). Mit Indizierten Dateien habe ich auch schon experimentiert um den Hauptspeicherbedarf zu verringern, was jedoch keine Vorteile bringt; das läuft auf ein Neuerfinden einer DB-Engine hinaus ;)

          Was anderes ist es natürlich, wenn ich dieselbe Abfrage MEHRFACH stelle. Hier kann man davon ausgehen, dass die Datenbank das Abfrageergebnis in irgendeiner Form cached, sprich, das Ergebnis bereits im Arbeitsspeicher vorliegen habe.

          MEM-Cache in Verbindung mit mod_perl. Mit einer Möglichkeit zum Flush (ohne Serverneustart).

          Jedenfalls ist es in den größeren Plattformen, in denen ich mich berufsbedingt herumtreibe, üblich, Connection Pools zu verwenden, weil da der Overhead für den Verbindungsaufbau sehr wohl ins Gewicht fällt.

          Alternative hierzu wären DB-Klassen, deren Sourcen bereits beim Apache-Start kompiliert werden (mod_perl). Da sind auch die Statements sauber vom übrigen Code getrennt.

          Schöne Grüße.

    2. Hallo Jörg,

      Mit der Dateilösung hingegen habe ich einen riesen Hash im Hauptspeicher, bei jedem Request entsteht ein Burst. Kommt mir da die Hardware entgegen, ist da was zu Cachen?
      Naja, im Prinzip hast Du ja schon so etwas wie einen Cache gebaut, in dem Du alle Daten zu Beginn in den Hauptspeicher lädst (ob von Platte oder Datenbank ist ja dann eigentlich schon egal).

      Dateilösungen haben durchaus ihre Daseinsberechtigung. Es ist nur so, dass im reinen CGI-Betrieb (mod_cgi) jeder Request einen eigenständigen Prozess erzeugt und der jeweils seinen eigenen Hash in den Hauptspeicher legt, da kann sich Einiges zusammenläppern ;)

      Mod_perl, da sieht das schon ganz anders aus: Da habe ich den Hash nur einmal, auch dann, wenn der Apache mehrere Prozesse forkt. Ich werde eine Konfiguration und eine Routingtable jedoch NICHT beim Starten des Webservers laden (das erschwert eine etwaige Fehlersuche, Logdatei gucken und so..) und auch nicht bei jedem Request sondern nur einmal beim ERSTEN Request: In diesem Fall greift meine Fehlerbehandlung und ich sehe im Browser, wenn da was schiefgegangen ist.

      Nachdem der ERSTE Request auf eine beliebige Seite den MEMCache betankt hat, wird bei jedem weiteren Request nur noch in den Cache gegriffen.

      Über mein Flush-Konzept (MEMCache auffrischen) muss ich noch nachdenken, es gibt auch CPAN-Lösungen die mir evntl. ins Konzept passen.

      Den Overhead für das Aufbauen einer Verbindung kann man übrigens dadurch reduzieren, dass man die Datenbankverbindung offen lässt. In  einer klassischen CGI-Umgebung ist das natürlich Quatsch (denn  da werden nach jedem Request üblicherweise sämtliche File-Handle und somit auch Datenbankverbindungen geschlossen), aber mit FCGI z.b. kann man ja durchaus Mechanismen bauen, bei denen beim Server-Start eine Verbindung aufgebaut wird, die dann für alle Requests gehalten wird.

      Der Server-Start ist nicht unbedingt die beste Zeit für sowas, siehe weiter oben.

      Schöne Grüße,
      Flush!

    3. Hallo,

      Noch besser ist es, nicht nur eine DB-Verbindung einzusetzen, sondern einen Connection Pool, der dann gleich eine ganze Reihe von Datenbank-Verbindungen vorhält.

      Wie ich vor ein paar Tagen erwähnte, eröffnen mod_perl und mod_fastcgi auch andere Möglichkeiten: Datenbank-Verbindungen werden im eigenen Haptspeicher gecached.

      Beispiel Data Abstraction Layer für MySQL, Parameter zum Herstellen der Verbindung sind Name der Datenbank und Name der Tabelle:

        
      # Datei factory/dalmysql.pm  
      # Data Abstraction Layer MySQL  
        
      use strict;  
      use warnings;  
      use MySQLEAV;  
        
      # Cache MySQL Connections  
      # Zwei Schlüssel im Hash: tabn, base  
      my %CC_DAL = ();  
        
        
      sub dalmysql{  
          my $self = shift;  
          my %in = (  
              tabn => '',  
              base => '',  
          @_);  
        
          my $dal = $CC_DAL{$in{base}}{$in{tabn}} || do{  
              $CC_DAL{$in{base}}{$in{tabn}} = MySQLEAV->new(%in) or die $@;  
              $CC_DAL{$in{base}}{$in{tabn}};  
          };  
        
          return $dal;  
      }  
        
      1;  
      
      

      Beim ersten Aufruf der Methode wird die Verbindung hergestellt und verbleibt danach im Hauptspeicher, das ist der Hash %CC_DAL.
      Bei jedem weiteren Aufruf mit denselben Parametern (DB-Name, Tab-Name) wird keine neue Verbindung hergestellt, sondern die Instanz aus dem RAM geladen. Bei Aufrufen mit anderen Parametern passiert dasselbe.

      Das ist sozusagen ein Lazy-Load: Zu Beginn, beispielsweise beim Starten des Webservers gibt es faktisch gar keinen Pool, der wird dynamisch verwaltet.

      MfG

      1. Tach!

        Datenbank-Verbindungen werden im eigenen Haptspeicher gecached.
        Beim ersten Aufruf der Methode wird die Verbindung hergestellt und verbleibt danach im Hauptspeicher, das ist der Hash %CC_DAL.
        Bei jedem weiteren Aufruf mit denselben Parametern (DB-Name, Tab-Name) wird keine neue Verbindung hergestellt, sondern die Instanz aus dem RAM geladen.

        Und nun muss man nur noch sicherstellen, dass der nachfolgende Client an keine DB-Session-Daten des vorherigen Client rankommt, und sich dann die Frage stellen, ob Sicherheit und der Aufwand dafür nicht vielleicht die Kosten eines neuen Verbindungsaufbaus übersteigen.

        Der Verbindungsaufbau zu für das Web vorgesehenen Datenbanksystemen ist heutzutage meist ausreichend schnell, so dass sich ein Connection-Pool nur in solchen Fällen lohnt, wie zum Beispiel einem langsamen Netzwerk.

        dedlfix.

        1. Tach!

          Datenbank-Verbindungen werden im eigenen Haptspeicher gecached.
          Beim ersten Aufruf der Methode wird die Verbindung hergestellt und verbleibt danach im Hauptspeicher, das ist der Hash %CC_DAL.
          Bei jedem weiteren Aufruf mit denselben Parametern (DB-Name, Tab-Name) wird keine neue Verbindung hergestellt, sondern die Instanz aus dem RAM geladen.

          Und nun muss man nur noch sicherstellen, dass der nachfolgende Client an keine DB-Session-Daten des vorherigen Client rankommt, und sich dann die Frage stellen, ob Sicherheit und der Aufwand dafür nicht vielleicht die Kosten eines neuen Verbindungsaufbaus übersteigen.

          Ja. Shared-Connections bringen "Einiges ist zu beachten" so mit sich. Mein Beispiel ist im Prinzip eine Singleton-Factory: Alle zurückgegebenen Instanzen sind Singletons, die Methode verhält sich statisch, d.h., die Instanzen werden nur einmal erstellt.

          Es ist möglich, mit dem bischen Perl-Code das statische Verhalten weiter einzuschränken, z.B. so, dass eine DB-Connection-Instanz an einen bestimmten URL gebunden ist (Parameter wären dann DB_NAME, DB_TABLE, OWNER_URL).

          Der Verbindungsaufbau zu für das Web vorgesehenen Datenbanksystemen ist heutzutage meist ausreichend schnell, so dass sich ein Connection-Pool nur in solchen Fällen lohnt, wie zum Beispiel einem langsamen Netzwerk.

          In Perl ist das auch so. Die meiste Zeit geht drauf, wenn der DBI-Layer (use DBI;) kompiliert wird. Danach ist eine Verbindung sehr schnell hergestellt (liegt im MilliSec-Bereich, wenn WebserverHost == DBserverHost).

          Weiterhin schönen Sonntag ;)

          1. Moin;

            Es ist möglich, mit dem bischen Perl-Code das statische Verhalten weiter einzuschränken, z.B. so, dass eine DB-Connection-Instanz an einen bestimmten URL gebunden ist (Parameter wären dann DB_NAME, DB_TABLE, OWNER_URL).

            Im Prinzip ist das alles nichts umwerfend Neues: Funktions-Aufrufe werden gecached. Genauer gesagt, wird der Rückgabewert einer Funktion gecached. Auf CPAN gibt es dazu das Modul Memoize und ab Perl v5.10 steht state zur Verfügung, dieses Schlüsselwort (analog zu c/PHP static) nimmt Einfluss auf den Geltungsbereich einer Variable, dahingehend, dass die Funktion das Cachen selbst übernehmen kann:

              
            use feature 'state';  
            # oder  
            # use 5.010;  
            sub foo{  
               state %cache;  
            }  
            
            

            In PHP sieht das ganz ähnlich aus: static $cache; Bei jedem Funktionsaufruf wird zuerst in $cache geschaut, ob entsprechend der Funktions-Argumente, bereits ein "Ergebnis" (Object, Instanz einer Klasse, Scalar, blessed Reference...) vorliegt. Wenn nicht, wird der Return-Value erstellt, in den $cache geschrieben und zurückgegeben. Somit werden alle zurückzugebenden Instanzen nur einmal erstellt, nämlich nur beim ersten Aufruf der Funktion.

            Der Return-Value ist immer eine Referenz, die jedoch auf sehr umfangreiche Datenstrukturn verweisen kann: Instanzen von Klassen, Dateihandle, Datenbankhandle, Arrays, Hashes, Scalare usw.

            Noch ein praktisches Beispiel:

              
                $Address = $self->userdata()  
                    or $self->mesg("Kein Benutzer angemeldet");  
                # oder  
                $Vorname = $self->userdata->{Vorname};  
            
            

            Hier spielt vieles zusammen: In $self steckt $SESSION (als Attribut), darin der Benutzername und die übrigen Benutzer-Daten können sonstwo gespeichert sein, z.B. in MySQL. Die Methode userdata() cached sowohl ein prepared Statement, als auch die Benutzerdaten für den Return-Value.

            Der Entwickler ruft einfach nur die Methode auf, das kann er beliebig oft machen und muss sich keine weiteren Gedanken machen, woher die Daten eigentlich kommen. Sollte sich bezüglich der Datenhaltung was ändern, bleibt der Code davon unberührt, lediglich die Methode wäre zu ändern und die ist in einer externen Datei definiert (userdata.pm).

            Zurückgegeben wird eine Datenstruktur, die nach kontextgerechter Behandlung der Template-Engine übergeben werden kann, eine intelligente Template-Engine (z.B. HTML::Template) übernimmt die die kontextgerechte Behandlung selbst (Maskieren von spitzen Klammern usw.). $Address ist dann nur noch ein Platzhalter und was damit gemacht wird, muss nur noch derjenige wissen, der das Template bearbeitet.

            Tags: OOP, Teamarbeit, Kaffeepause, Mittagsschlaf :)

  4. meine komplette Website (ca. 400 Einzelseiten samt Body u. Attributen) liegt in einer Binärdatei, diese hat eine Größe von ca. 1,3 MB.

    Mit der Dateilösung hingegen habe ich einen riesen Hash im Hauptspeicher, bei jedem Request entsteht ein Burst.

    Du immer mit Deinen Wortschöpfungen ;-)

    1,3 MB sind IMHO zu vernachlässigen, die kannst Du auch in den RAM legen. Nur skaliert das Konzept nicht, für große Projekte also ungeeignet. Wenn Du das für dich noch weiter optimieren willst: nimm FastCGI oder mod_perl und lade Deinen Hash beim Start des Webservers.

    Frage an Betreiber von Webservern, was steht da so draußen rum

    Such es dir aus. Virtueller Server vom Ramschtisch mit 1G Ram und einem Kern, Dezidierter Server mit 64G Ram, 8 Kernen und SSD...

    und kann es das ab...

    1,3 MB  sind IMHO wirklich nichts, "ob es das abkann" hängt von sooo vielen Faktoren ab: den aufkommenden Requests, der Hardware dem ganzen Rest des Setups...

    1. meine komplette Website (ca. 400 Einzelseiten samt Body u. Attributen) liegt in einer Binärdatei, diese hat eine Größe von ca. 1,3 MB.

      Mit der Dateilösung hingegen habe ich einen riesen Hash im Hauptspeicher, bei jedem Request entsteht ein Burst.

      Du immer mit Deinen Wortschöpfungen ;-)

      Kann schon sein, dass der Begriff nicht passt. Klingt aber immer noch besser als Blast ;)

      1,3 MB sind IMHO zu vernachlässigen, die kannst Du auch in den RAM legen. Nur skaliert das Konzept nicht, für große Projekte also ungeeignet.

      Ja, das ist mir klar.

      Wenn Du das für dich noch weiter optimieren willst: nimm FastCGI oder mod_perl und lade Deinen Hash beim Start des Webservers.

      Ich würde mich für mod_perl entscheiden, dafür habe ich mein Perl-Framework entwickelt ;)

      Frage an Betreiber von Webservern, was steht da so draußen rum

      Such es dir aus. Virtueller Server vom Ramschtisch mit 1G Ram und einem Kern, Dezidierter Server mit 64G Ram, 8 Kernen und SSD...

      und kann es das ab...

      1,3 MB  sind IMHO wirklich nichts, "ob es das abkann" hängt von sooo vielen Faktoren ab: den aufkommenden Requests, der Hardware dem ganzen Rest des Setups...

      Meine Frage war eher ein Rücklick auf private Basteleien und ist hiermit beantwortet. Dein Sternchen hast Du ja schon gekriegt ;)

      Schöne Grüße.

  5. meine komplette Website (ca. 400 Einzelseiten samt Body u. Attributen) liegt in einer Binärdatei, diese hat eine Größe von ca. 1,3 MB.

    Hm. Das habe ich anders gelöst. Webseiten sind ja oft "quasistatisch", da macht es oft keinen Sinn diese wirklich bei jedem Abruf neu aus Dateien oder Datenbanken zu generieren. Man kann auch sagen, dass das Dateisystem dann "genug Datenbank" ist.

    Bei mir wird aus den Daten des Requests ein Hash gebildet (simplerweise md5). Dann wird nachgeschaut, ob es im Cache schon eine Datei mit dem Hash als Name gibt - genau genommen sind es immer zwei. Gibt es die Datei bzw. deren mit gzip gepackte Version, dann wird (je nach dem was der User-Agent als "willkommen" im Request meldet) entweder die gezippte oder die Flat-Version der Datei ausgeliefert.

    Gibt es die Datei nicht, dann wird die Webseite vom CMS gebaut und ausgeliefert aber zuvor auch in beiden Versionen (gezipp und ungezippt) im Cache verwahrt. Das geht schön einzeln, weil das nur beim Abruf stattfindet.

    Ändere ich im CMS was, dann lösche ich einfach den ganzen Cache. Das sollte auch bei 400 Seiten noch "superperformant" sein.

    Jörg Reinholz

    1. meine komplette Website (ca. 400 Einzelseiten samt Body u. Attributen) liegt in einer Binärdatei, diese hat eine Größe von ca. 1,3 MB.

      Hm. Das habe ich anders gelöst. Webseiten sind ja oft "quasistatisch", da macht es oft keinen Sinn diese wirklich bei jedem Abruf neu aus Dateien oder Datenbanken zu generieren. Man kann auch sagen, dass das Dateisystem dann "genug Datenbank" ist.

      Die Idee ist auch gut, danke Dir!

      Seit gestern bin ich dabei, mein Framework für mod_perl "ins Reine" zu schreiben :)
      Da wird es nur noch eine (sehr kleine) Konfigurationsdatei geben. Für Templates, welche aus dem Dateisystem geladen werden, nutze ich LazyLoad, was Perl::TieHash vorzüglich nutzt und damit wird der ganze Kram automatisch gekäschd (*). Vorzugsweise werden Templates jedoch aus MySQL geladen, dafür habe ich einen speziellen Layer entwickelt, der beim Apache-Start gleich mit kompiliert wird und somit eine persistente DB-Verbindung aufbaut.

      Weitere DB-Connections, sofern benötigt, werde ich über spezielle Klassen realisieren, diese Connections sind dann auch persistent, es wird aus dem Code heraus jedoch nicht auf den nackten DB-Handle gegriffen, sondern es werden nur noch Methoden aufgerufen.

      Ansonsten überlasse ich das Cachen dem Browser per Last-Modified ;)

      (*) Der Hash mit { Dateiname => Inhalt, ... => ... } liegt als Referenz (Attribut) im PerlResponseHandler (Apache) und wird somit im Hauptspeicher gehalten.

      mod_perl ist affengeil, ich bin begeistert!

      Schönes Wochenende :)

      1. Ansonsten überlasse ich das Cachen dem Browser per Last-Modified ;)

        Das mache ich zusätzlich.

        Jörg Reinholz

        1. Ansonsten überlasse ich das Cachen dem Browser per Last-Modified ;)

          Das mache ich zusätzlich.

          Darüber freuen sich die Suchmaschinen ;)

          Noch ein Beispiel, weil mod_perl so schön ist:

            
          # Lade die dem Realm entsprechende Config in den MEM-Cache  
          # in PerlResponseHandler::handler() Method  
          # Das Response-Objekt ist noch nicht verfügbar  
          # also nutzen wir eine Klassen-Methode zum Lesen der ini-Datei  
          my $cfg = $CC_CONFIG->{$realm} || do{  
              my $ref = __PACKAGE__->configini("$vars->{realmdir}/$vars->{cfgname}") or die $@;  
              $CC_CONFIG->{$realm} = $ref->{$realm};  
              $CC_CONFIG->{$realm};  
          };  
          # Realms bilden den Namen der Benutzergruppe ab  
          # public, admin, cms_user usw.  
          
          

          Weiterhin schönen Sonntag :)