Eisbär: Session-Management und applikationsweit verfügbare Objekte

Hallo Leute

Ich arbeite aktuell an einem Web-Projekt in Perl, welches stark objektorientiert geprägt ist.
Das Ganze ist nach dem dreischichtigen Ansatz(Datenspeicherung, Businesslogik, Darstellung) aufgebaut.

Nun fehlt mir zu Darstellung in Perl allgemeine Mechanismen für applikationsweit verfügbare Objekte und ein Session-Management.

Mit den applikationsweit verfügbaren Objeketen ist folgendes gemeint:
Mit dem Start des Web-Servers (Apache 2.x und mod_perl) soll ein Initialisierungsskript aufgerufen werden, das eine Konfiguration einliest und einige "global" verfügbare Variablen, bzw. Objektreferenzen definiert.
Diese Objekte sollen während der gesamten Laufzeit des Web-Servers, bzw. meiner Applikation für andere definerte Skripts sichtbar und zugreifbar sein. Die gesamte Applikation wird am Ende aus bestimmt 50 oder mehr Skripts (hauptsächlich Darstellungskripts basierend auf Templates) bestehen.

Weiter benötige ich so etwas wie ein Session-Objekt, wo mit den Aufruf der Anmelde-Seite eine Session-ID generiert wird. Nach erfolgreicher Anmledung wird mit der Session-ID und zusätzlichen, benutzerbezogenen Informationen das Session-Objekt erzeugt. Dieses Session-Objekt soll auch wieder über mehrere Skripte hinweg als Objektreferenz global zur verfügung stehen.

Damit soll vermieden werden, das bei jedem Skriptaufruf die umfangreichen Konfigurationsdaten und Userdaten aus der Datenbank ausgelesen werden müssen (Performanceproblem). Darum sollen diese Objekte irgendwie einen globalen Scope über viele unterschiedliche Skriptaufrufe haben.

So in der Art:
   $application.getConfigfile();
oder
   $session.getUsername($sid);

Ist so etwas in Perl (zusammen mit Apache 2 und mod_perl) zu realisieren?

Bisher weiss ich von Perl nur, dass die Verfügbarkeit der Objekte durch den Scope des aufrufenden Skript beschränkt wird, da für jeden Skriptaufruf ein eigener Prozess gestartet wird.
Gibt es die Möglichkeit solche Objekte in den Speicherbereich des Apache-Prozesses zu verlagern?

Hat jemand Ideen, wie solche Anforderungen in Perl mit Apache umgesetzt werden können?
In Web-Application-Server stehen solche Mechanismen zur Verfügung (siehe WebObject, ASP, andere).
Grundsätzlich müsste dies doch auch mit Perl gehen.
Die Frage ist nur wie?

Ich freu mich schon auf Antworten ;-)

Grüsse
Eisbär

  1. Halihallo

    Nun fehlt mir zu Darstellung in Perl allgemeine Mechanismen für applikationsweit verfügbare Objekte und ein Session-Management.

    Serialisierung von Objekten, sei hier genannt. Wobei du ja eben genau das auslesen von Dateien verhindern willst. Aber du könntest die serialisierten Objekte in einem globalen Prozess speichern, mitdem du dann kommunizierst.

    Damit soll vermieden werden, das bei jedem Skriptaufruf die umfangreichen Konfigurationsdaten und Userdaten aus der Datenbank ausgelesen werden müssen (Performanceproblem). Darum sollen diese Objekte irgendwie einen globalen Scope über viele unterschiedliche Skriptaufrufe haben.

    Ich kenne leider keine bereits bestehenden Ansätze, hab mich jedoch auch nicht informiert.

    Ist so etwas in Perl (zusammen mit Apache 2 und mod_perl) zu realisieren?

    Bestimmt. Aber nicht so einfach, wie in ASP ;)
    Wenn du sicherstellen kannst, dass ein Script immer läuft, kannst du eine Socketkommunikation iniziieren und die Daten werden dann von diesem "global-scope-script" zur Verfügung gestellt. Christian ist glaub ich "im Moment" damit beschäftigt, das Forum etwa mit der gleichen "Technik" auszustatten.

    Hat jemand Ideen, wie solche Anforderungen in Perl mit Apache umgesetzt werden können?
    In Web-Application-Server stehen solche Mechanismen zur Verfügung (siehe WebObject, ASP, andere).
    Grundsätzlich müsste dies doch auch mit Perl gehen.

    Ja, das geht schon, aber wie du selber sagst: das ist eigentlich keine Eigenschaft einer Programmiersprache, sondern vielmehr eines Webservers.

    Viele Grüsse

    Philipp
       <-- hoffe, dass ich doch etwas helfen konnte.

    1. Hallo Philip

      Erstmal Danke für die Antworten.

      Serialisierung von Objekten, sei hier genannt. Wobei du ja eben genau das auslesen von Dateien verhindern willst. Aber du könntest die serialisierten Objekte in einem globalen Prozess speichern, mitdem du dann kommunizierst.

      Sorry, was versteht man unter "Serialisierung von Objekten"?

      Bestimmt. Aber nicht so einfach, wie in ASP ;)
      Wenn du sicherstellen kannst, dass ein Script immer läuft, kannst du eine Socketkommunikation iniziieren und die Daten werden dann von diesem "global-scope-script" zur Verfügung gestellt. Christian ist glaub ich "im Moment" damit beschäftigt, das Forum etwa mit der gleichen "Technik" auszustatten.

      Wie perfomant ist eine solche Sockketkommunikation zwischen zwei Prozessen (auf dem gleichen Server)?
      Lohnt sich der Aufwand im Vergleich zum Aufbau eines DBI-Connects zu einem SQL-Server?
      Wie aufwendig ist die programmiertechnische Umsetzung?
      Gibt es vergleichbar zu CGI und DBI bereits Module, die einem den Aufbau dieser Kommunikation zwischen Prozessen erleichtert?
      Was für Datenobjekte können zwischen zwei Prozessen übertragen werden?
      Ist dies nur ein selbstgestalteter Steram (z.B. XML) den man selsbt formatieren und am anderen Ende wieder parsen muss?
      Gibt es die Möglichkeit direkt Perl-Objekte wie SCALAR, ARRAY, HASH und eigene, durch Perl-Module definierte Objekte, über diese Socketkommunikation zu transportieren?

      Ich weiss, eine Menge Fragen, aber einige Anworten würden mir schon sehr helfen :-)

      Ja, das geht schon, aber wie du selber sagst: das ist eigentlich keine Eigenschaft einer Programmiersprache, sondern vielmehr eines Webservers.

      In diesem Fall suche ich einen Perl-basierten Applicationserver, bzw. einen Applicationserver mit Perl als eingebaute Programmiersprache ;-)

      Kennt jemand solche Perl-Module, bzw. Apache-Erweiterungen?

      Grüsse
      Eisbär

      1. Halihallo Eisbär

        Serialisierung von Objekten, sei hier genannt. Wobei du ja eben genau das auslesen von Dateien verhindern willst. Aber du könntest die serialisierten Objekte in einem globalen Prozess speichern, mitdem du dann kommunizierst.

        Sorry, was versteht man unter "Serialisierung von Objekten"?

        Objekte sind ja komplexe Strukturen; diese kann man nicht einfach in einer Datei oder in den Speicher abbilden. Dazu braucht man eine Art "Kodierung" oder Abbildungsvorschrift, wie man diese Darstellen kann. Das Umwandeln/Abbilden einer komplexen Datenstruktur nennt man Serialisierung.

        Beispiel:

        $db = new Database;

        dann hat $db vielleicht folgende Eigenschaften:

        $VAR1 = {
           dsn => 'hello',
           login => 'loginname',
           pwd => 'pwd',
           data => [$VAR2,$VAR3,$VAR4]
        }

        $VAR2 = {
           name => 'Hasenfratz',
           vorname => 'Philipp',
           email => 'philipp.hasenfratz@gmx.net',
        }

        $VAR3 = {...}

        Diese Struktur musst du irgendwie in ein gut leserliches Format in eine Datei schreiben können. Eine mögliche Serialisierung dieser Struktur ist z. B. XML.

        <Database>
           <var name="login">loginname</var>
           <var name="pwd">pwd</var>
           <data type="array">
              <item type="hash">
                 <var name="name">Hasenfratz</var>
                 ...
              </item>
              ...
           </data>
        </Database>

        Diese Struktur lässt sich dann "ziemlich" einfach einlesen und bearbeiten => dies ist eine mögliche Serialisierung des Objektes.

        Bestimmt. Aber nicht so einfach, wie in ASP ;)
        Wenn du sicherstellen kannst, dass ein Script immer läuft, kannst du eine Socketkommunikation iniziieren und die Daten werden dann von diesem "global-scope-script" zur Verfügung gestellt. Christian ist glaub ich "im Moment" damit beschäftigt, das Forum etwa mit der gleichen "Technik" auszustatten.

        Wie perfomant ist eine solche Sockketkommunikation zwischen zwei Prozessen (auf dem gleichen Server)?

        Nun, wenn das auf dem gleichen Computer geschieht (was bei dir ja so ist), sind sie ziemlich schnell (zur Erinnerung: HTTP, FTP, Gopher, ... alles Socketverbindungen). Aber ich kann dir keine Referenzwerte nennen. Was ich jedoch sagen kann, dass z. B. Datenbankschnittstellen (eg. mysql) auch darauf basieren und bekanntlich hat noch "fast" niemand über die Performance gesprochen und wenn überhaupt, dann über die Performance der Datenbank, nicht der Verbindung (zumindest bei grossen Datenbeständen). Also: Über die Performance brauchst du dir glaub ich nicht den Kopf zerbrechen. Wohl eher, ob du es schaffst, dass dein Script wirklich sauber und ohne Fehler arbeitet => Stabilität. Du _musst_ auf jeden Fall sicherstellen, das der Daten-Server _immer_ verfügbar ist und stabil läuft. Das ist keine sehr einfach Aufgabe! - Zudem habe ich etwas bedenken, wenn du nur einen Daten-Server nimmst. Ein Datenserver, mehrere clients? - Das bremst unnötig aus. Eine Möglichkeit wäre es, ca. 10 Datenserver zu preforken (also beim ersten Start gleich 10 Abbilder, die dann jeweis 10 Clients zur selben Zeit bedienen können), oder einfach forken, wenn ein neuer Client Daten braucht (du musst mit fork ja nicht gleich alle Dateien neu einlesen, das OS kopiert den ganzen Interpreter und die Daten für dich).

        Lohnt sich der Aufwand im Vergleich zum Aufbau eines DBI-Connects zu einem SQL-Server?

        Der ist etwa genau so schnell, wie eine Socketverbindung, IMO sogar das selbe ;)

        Wie aufwendig ist die programmiertechnische Umsetzung?

        Kommt darauf an. Wie komplex ist denn der Datenaustausch? - Wie komplex die Objekte.

        Gibt es vergleichbar zu CGI und DBI bereits Module, die einem den Aufbau dieser Kommunikation zwischen Prozessen erleichtert?

        Vielleicht SOAP (SimpleObjectAccessProtocol) oder RPC (RemoteProcedureCall). Beides geht auch über Socketverbindungen (mit einigen Tricks).

        Kannst ja mal die Doku zu SOAP::Lite anschauen.

        Was für Datenobjekte können zwischen zwei Prozessen übertragen werden?
        Ist dies nur ein selbstgestalteter Steram (z.B. XML) den man selsbt formatieren und am anderen Ende wieder parsen muss?
        Gibt es die Möglichkeit direkt Perl-Objekte wie SCALAR, ARRAY, HASH und eigene, durch Perl-Module definierte Objekte, über diese Socketkommunikation zu transportieren?

        Direkt nein. Indirekt über die genannte Serialisierung. SOAP und RPC verwenden z. B. Serializer. Du könntest auch ein eigenes Modul schreiben, was eine Datenstruktur in einen XML-Stream abbildet.

        Ja, das geht schon, aber wie du selber sagst: das ist eigentlich keine Eigenschaft einer Programmiersprache, sondern vielmehr eines Webservers.

        In diesem Fall suche ich einen Perl-basierten Applicationserver, bzw. einen Applicationserver mit Perl als eingebaute Programmiersprache ;-)

        au waya ;)

        Kennt jemand solche Perl-Module, bzw. Apache-Erweiterungen?

        Bin vielleicht etwas auf SOAP und RPC fixiert. Kann nur diese nennen. Vielleicht weiss sonst noch wer was.

        Viele Grüsse

        Philipp

        1. Halihallo Eisbär

          Hm. Bin glaub ich etwas über das Ziel hinausgeschossen. SOAP und RPC sind IHO etwas langsam, da du ja eben genau die Performance damit verbessern willst. Zudem ist die Verwendung von SOAP und RPC eigentlich auch anders.
          Du könntest dir natürlich Serialisierungsmöglichkeiten den Modulen entnehmen (zum Serialisieren wäre auch ein Blick in den Source von Data::Dumper nicht schlecht). Aber diese Module sind nich für TimeResistant-Programme gedacht, sondern eben dafür, dass die Objekt-Struktur auf über mehrere Scriptzugriffe hinaus gleich bleibt. Fakt ist, dass selber geschriebene SOAP-Module dennoch bei jedem Zugriff die Daten einlesen müssten => sprich, die Daten werden nicht im Speicher aufgewahrt, sondern auf der langsamen Platte.

          Also, zweiter Versuch:
          Einmaliges Serialisieren in eine XML-Struktur (Standard...), die erzeugte XML::DOM-Instanz (oder willst du einen anderen Parser verwenden?) im Speicher halten und dann ein Socket-Interface aufbauen, womit du mit einfachen Befehlen durch diese Struktur "browsen" kannst (kannst ja ein eigenes XPath-Interface basteln ;)). Wenn du STRING, ARRAY und HASH verwendest, dürfte das nicht allzuschwer sein.

          GET /Node1/test/[2]/{'test'}

          << RESULT successful

          oder

          GET /Node1/test/[1]

          << RESULT b

          GET /Node1/test/[0]

          << RESULT a

          <struct name="Node1" type="hash">
             <struct name="test" type="array">
                <struct name="Node2" type="array">
                   <var value="a" />
                   <var value="b" />
                   <struct name="Node3" type="hash">
                      <var name="test" value="successful">
                   </struct>
                </struct>
             </struct>
          </struct>

          oder so... Noch etwas kompliziert, aber das kann man wohl vereinfachen.

          Also irgendwie scheint mir das alles etwas zu Zeitaufwändig zu sein, nur um die Performance etwas zu verbessern. Müssten denn deine 50 Programme soviele Daten aus einer DB einlesen? - Könnte man das nicht etwas beschränken (z. B. nur Daten laden, wenn sie benötigt werden)? - Zudem glaube ich schon, dass die Performance einer reinen DB-Lösung nicht so schlecht wäre... Kannst du vielleicht noch etwas mehr über die Programme sagen? - Ich bin sicher, dass es noch eine bessere Lösung gibt.

          Viele Grüsse

          Philipp

          1. Hallo Philipp

            Danke für die Anworten, ich werde meine Fragen/Staements aus Deinen beiden letzten Postings hier zusammenfassen.

            <Database>
               <var name="login">loginname</var>
               <var name="pwd">pwd</var>
               <data type="array">
                  <item type="hash">
                     <var name="name">Hasenfratz</var>
                     ...
                  </item>
                  ...
               </data>
            </Database>

            Diese Struktur lässt sich dann "ziemlich" einfach einlesen und bearbeiten => dies ist eine mögliche Serialisierung des Objektes.

            Tatsächlich umfasst meine Applikation auch eine XML-Importschnittstelle, um komplexe Objekte von einem Fremdsystem zu übernehmen.
            Nur habe ich grosse Bedenken, wenn ich mir die Module XML-Parser und -DOM anschaue, dass die Lösung bei mehreren dutzend bis hunderten Concurrent-Usern wirklich performant ist. Bei jedem Skriptaufruf der Darstellungsschicht werden mehrere Dutzend Objekte aus rund 10 Objektklassen aufgerufen. Falls ich diese jedesmal durch den XML-Parser duchjagen muss, belaste ich die Performance des Gesamtsystems beträchtlich (Zumindest glaube ich das, wobei Glauben ist nicht Wissen).

            Ganz allgemein zielt mein Posting darauf ab, diese persistente Datenspeicherung zwar zu haben, die daraus abgeleiteten Objekte aber zur Laufzeit "global" im Arbeitsspeicher verfügbar zu haben, um bei vielen gleichzeitigen Zugriffen die Performance zu verbessern.

            Nun, wenn das auf dem gleichen Computer geschieht (was bei dir ja so ist), sind sie ziemlich schnell (zur Erinnerung: HTTP, FTP, Gopher, ... alles Socketverbindungen). Aber ich kann dir keine Referenzwerte nennen. Was ich jedoch sagen kann, dass z. B. Datenbankschnittstellen (eg. mysql) auch darauf basieren und bekanntlich hat noch "fast" niemand über die Performance gesprochen und wenn überhaupt, dann über die Performance der Datenbank, nicht der Verbindung (zumindest bei grossen Datenbeständen). Also: Über die Performance brauchst du dir glaub ich nicht den Kopf zerbrechen. Wohl eher, ob du es schaffst, dass dein Script wirklich sauber und ohne Fehler arbeitet => Stabilität. Du _musst_ auf jeden Fall sicherstellen, das der Daten-Server _immer_ verfügbar ist und stabil läuft. Das ist keine sehr einfach Aufgabe! - Zudem habe ich etwas bedenken, wenn du nur einen Daten-Server nimmst. Ein Datenserver, mehrere clients? - Das bremst unnötig aus. Eine Möglichkeit wäre es, ca. 10 Datenserver zu preforken (also beim ersten Start gleich 10 Abbilder, die dann jeweis 10 Clients zur selben Zeit bedienen können), oder einfach forken, wenn ein neuer Client Daten braucht (du musst mit fork ja nicht gleich alle Dateien neu einlesen, das OS kopiert den ganzen Interpreter und die Daten für dich).

            Die Anforderung nach Stabilität steht bei meiner Lösung auch vor der Forderung nach Performance.
            Von der Umsetzung her denke ich jedoch, dass ich bei jedem Skriptaufruf der Darstellungsschicht die Existenz des übergelagerten Prozesses prüfen kann und falls dieser nicht antwortet, wird er neu initalisiert (da die Daten trotz allem persistent gespeichert werden). In diesen (hoffentlich selteren) Fällen wartet der User halt 1-2 Sekunden länger.

            Nochmals ein Sorry, was bedeuted fork genau?
            Wird dabei ein Prozess mitsammt seinem Speicher "geklont"?
            Und noch viel schlimmer, würde das unter WinNT/Win2000 auch funktionieren?
            (Eine der Kernanforderungen meiner Lösung ist, dass sie sowohl unter Linux, WinNT/Win2000 und FreeBSD laufähig sein muss).

            Hm. Bin glaub ich etwas über das Ziel hinausgeschossen. SOAP und RPC sind IHO etwas langsam, da du ja eben genau die Performance damit verbessern willst. Zudem ist die Verwendung von SOAP und RPC eigentlich auch anders.
            Du könntest dir natürlich Serialisierungsmöglichkeiten den Modulen entnehmen (zum Serialisieren wäre auch ein Blick in den Source von Data::Dumper nicht schlecht). Aber diese Module sind nich für TimeResistant-Programme gedacht, sondern eben dafür, dass die Objekt-Struktur auf über mehrere Scriptzugriffe hinaus gleich bleibt. Fakt ist, dass selber geschriebene SOAP-Module dennoch bei jedem Zugriff die Daten einlesen müssten => sprich, die Daten werden nicht im Speicher aufgewahrt, sondern auf der langsamen Platte.

            Grundsätzlich könnte ich mir für diese Applikation durchaus ein SOAP-Interface vorstellen, da dies eh später als weitere Schnittstelle für externe Systeme angedacht ist. Zum Datenaustauch von Objekten innerhalb der Applikation möchte ich aber davon Abstand nehmen.

            Direkt nein. Indirekt über die genannte Serialisierung. SOAP und RPC verwenden z. B. Serializer. Du könntest auch ein eigenes Modul schreiben, was eine Datenstruktur in einen XML-Stream abbildet.

            Soweit ich das verstehe, ist SOAP und RPC vergleichbar zu dem, was wir uns oben zusammengedacht haben: Serialisierung der Objekte und Datenaustausch über eine Socketverbindung. Der einzige Unterschied ist, das dies standardisiert erfolgt.
            Somit verringert es mein Performanceproblem eher nicht.

            Also, zweiter Versuch:
            Einmaliges Serialisieren in eine XML-Struktur (Standard...), die erzeugte XML::DOM-Instanz (oder willst du einen anderen Parser verwenden?) im Speicher halten und dann ein Socket-Interface aufbauen, womit du mit einfachen Befehlen durch diese Struktur "browsen" kannst (kannst ja ein eigenes XPath-Interface basteln ;)). Wenn du STRING, ARRAY und HASH verwendest, dürfte das nicht allzuschwer sein.

            GET /Node1/test/[2]/{'test'}
            << RESULT successful

            oder

            GET /Node1/test/[1]
            << RESULT b

            GET /Node1/test/[0]
            << RESULT a

            <struct name="Node1" type="hash">
               <struct name="test" type="array">
                  <struct name="Node2" type="array">
                     <var value="a" />
                     <var value="b" />
                     <struct name="Node3" type="hash">
                        <var name="test" value="successful">
                     </struct>
                  </struct>
               </struct>
            </struct>

            oder so... Noch etwas kompliziert, aber das kann man wohl vereinfachen.

            So was in der Art könnte ich mir vorstellen. Für die oben genannte XML-Schnittstelle habe ich mir schon ein XPath-ähnliches Interface geschrieben, werde nun aber auf das Modul XPath wechseln. Damit sollte sich so was grundsätzlich lösen lassen, aber wie gesagt, dazu muss jedes einzelne Objekt bei jedem Skriptaufruf nochmals durch den XML-Parser ... :-(

            Also irgendwie scheint mir das alles etwas zu Zeitaufwändig zu sein, nur um die Performance etwas zu verbessern. Müssten denn deine 50 Programme soviele Daten aus einer DB einlesen? - Könnte man das nicht etwas beschränken (z. B. nur Daten laden, wenn sie benötigt werden)? - Zudem glaube ich schon, dass die Performance einer reinen DB-Lösung nicht so schlecht wäre...

            Danke für Deine reflektierenden Antworten, ich werde wohl eher bei der persistenten Datenspeicherung in einer Datenbank bleiben und die Objekte bei jedem Skriptaufruf neu aus der Datenbank generieren. Tatsächlich kann ich die Objektklassen so ausgestalten, dass der DB-Zugriff nur auf konkrete Anforderung erfolgt.

            Dies wird zumindest vorläufig ausreichen. Später könnten aber Anforderungen folgen, wo ich enteder einen fetten Server hinstellen muss oder das Ganze gescheit in einer Applicationserver-Umgebung (WebObject, ASP oder andere) neu programmiere.

            Danke nochmals für Dein konstruktives Feedback und gute Nacht ;-)

            Grüsse
            Eisbär

            1. Halihallo Eisbär

              Diese Struktur lässt sich dann "ziemlich" einfach einlesen und bearbeiten => dies ist eine mögliche Serialisierung des Objektes.

              Tatsächlich umfasst meine Applikation auch eine XML-Importschnittstelle, um komplexe Objekte von einem Fremdsystem zu übernehmen.
              Nur habe ich grosse Bedenken, wenn ich mir die Module XML-Parser und -DOM anschaue, dass die Lösung bei mehreren dutzend bis hunderten Concurrent-Usern wirklich performant ist. Bei jedem Skriptaufruf der Darstellungsschicht werden mehrere Dutzend Objekte aus rund 10 Objektklassen aufgerufen. Falls ich diese jedesmal durch den XML-Parser duchjagen muss, belaste ich die Performance des Gesamtsystems beträchtlich (Zumindest glaube ich das, wobei Glauben ist nicht Wissen).

              Dies hatte ich bei meinem zweiten Postings fälschlicherweise geschrieben, ja. Aber es gibt die Möglichkeit, die XML-Config _einmal_ zu parsen und den ParseTree von XML::DOM im Speicher zu halten. Dann kannst du über das Socket durch diesen ParseTree "browsen", aber es werden gar keine XML-Files mehr geparsed. Übrigens: XML::DOM ist auch ziemlich lahm. XML::SAX wäre da viel, viel schneller, aber das "browsing" wird etwas mühsamer, wie ich denke. Aber wie gesagt, die Datei muss nur einmal geparsed werden (OK, das Traversieren/Durchlaufen des ParseTree ist bei XML::DOM auch etwas unperformant).

              Ganz allgemein zielt mein Posting darauf ab, diese persistente Datenspeicherung zwar zu haben, die daraus abgeleiteten Objekte aber zur Laufzeit "global" im Arbeitsspeicher verfügbar zu haben, um bei vielen gleichzeitigen Zugriffen die Performance zu verbessern.

              s. oben.

              Die Anforderung nach Stabilität steht bei meiner Lösung auch vor der Forderung nach Performance.

              IMO ist das auch sehr sinnvoll ;-)

              Von der Umsetzung her denke ich jedoch, dass ich bei jedem Skriptaufruf der Darstellungsschicht die Existenz des übergelagerten Prozesses prüfen kann und falls dieser nicht antwortet, wird er neu initalisiert (da die Daten trotz allem persistent gespeichert werden). In diesen (hoffentlich selteren) Fällen wartet der User halt 1-2 Sekunden länger.

              Genau.

              Nochmals ein Sorry, was bedeuted fork genau?

              Brauchst dich net zu entschuldigen. Ich schreibe oft "komprimiert", wenn dann jemand etwas nicht versteht soll er nachfragen. Aber es bringt nix, wenn ich hier gleich eine ganze Doku zu fork verfasst hätte, schliesslich könntest du das ja schon wissen => deshalb frag nur immer nach.
              Also, fork startet einen neuen Prozess => also eine neue Instanz des Programmes.

              Wird dabei ein Prozess mitsammt seinem Speicher "geklont"?

              Genau, sogar alle Filehandles... Es ist ein "perfektes" Abbild seines Vaters.

              Und noch viel schlimmer, würde das unter WinNT/Win2000 auch funktionieren?

              Ei, da muss ich dich enttäuschen. Bei der StandardDistribution von ActivePerl wird fork nicht unterstützt (vielleicht gibt's ne andere Lösung, denke aber nicht). Aber für Win gibt's Alternativen Win32::Process, Win32, jedoch wird dort der "Vater" nicht geklont, sondern du kannst lediglich ein neues Programm starten => XML müsste neu geparsed werden => wohl nicht so geeignet für dein Vorhaben.

              (Eine der Kernanforderungen meiner Lösung ist, dass sie sowohl unter Linux, WinNT/Win2000 und FreeBSD laufähig sein muss).

              Nun, fork läuft auf allen Unix-Derivaten. Bekanntlich gehört Win leider nicht dazu... *sorry*

              Hm. Bin glaub ich etwas über das Ziel hinausgeschossen. SOAP und RPC sind IHO etwas langsam, da du ja eben genau die Performance damit verbessern willst. Zudem ist die Verwendung von SOAP und RPC eigentlich auch anders.
              Du könntest dir natürlich Serialisierungsmöglichkeiten den Modulen entnehmen (zum Serialisieren wäre auch ein Blick in den Source von Data::Dumper nicht schlecht). Aber diese Module sind nich für TimeResistant-Programme gedacht, sondern eben dafür, dass die Objekt-Struktur auf über mehrere Scriptzugriffe hinaus gleich bleibt. Fakt ist, dass selber geschriebene SOAP-Module dennoch bei jedem Zugriff die Daten einlesen müssten => sprich, die Daten werden nicht im Speicher aufgewahrt, sondern auf der langsamen Platte.

              Grundsätzlich könnte ich mir für diese Applikation durchaus ein SOAP-Interface vorstellen, da dies eh später als weitere Schnittstelle für externe Systeme angedacht ist. Zum Datenaustauch von Objekten innerhalb der Applikation möchte ich aber davon Abstand nehmen.

              Stimmt. Also für externe Systeme kann ich SOAP nur empfehlen ;-))
              Mir ist jedoch klar, dass es für den internen Gebrauch nicht einmal eine "Verschlimmbesserung" ist ;)

              Direkt nein. Indirekt über die genannte Serialisierung. SOAP und RPC verwenden z. B. Serializer. Du könntest auch ein eigenes Modul schreiben, was eine Datenstruktur in einen XML-Stream abbildet.

              Soweit ich das verstehe, ist SOAP und RPC vergleichbar zu dem, was wir uns oben zusammengedacht haben: Serialisierung der Objekte und Datenaustausch über eine Socketverbindung. Der einzige Unterschied ist, das dies standardisiert erfolgt.

              Nun, das Serialisieren von Objekten ist nur ein "notwendiges Übel", es geht darum eine plattformunabhängige, systemübergreifende Schnittstelle zu realisieren, um Methoden, Prozeduren und Funktionen auf einem entfernten Rechner zu starten. Übrigens kann man wohl SOAP für Socketverbindungen benutzen, aber das "Standard-Transport-Medium" ist HTTP.

              Somit verringert es mein Performanceproblem eher nicht.

              Ja.

              [...]

              So was in der Art könnte ich mir vorstellen. Für die oben genannte XML-Schnittstelle habe ich mir schon ein XPath-ähnliches Interface geschrieben, werde nun aber auf das Modul XPath wechseln. Damit sollte sich so was grundsätzlich lösen lassen, aber wie gesagt, dazu muss jedes einzelne Objekt bei jedem Skriptaufruf nochmals durch den XML-Parser ... :-(

              Mit einigen Anpassungen nicht. Der ParseTree liegt ja im Speicher des Daten-Scripts. Du musst dein XPath-Modul nur so abändern, dass es durch das Socket kommuniziert und ein anderes XPath-Modul im Daten-Script aufruft, der den Node zurückliefert (ohne das XML neu zu parsen => das XPath Modul muss auf den Memory-ParseTree von XML::DOM zugreifen).

              Also irgendwie scheint mir das alles etwas zu Zeitaufwändig zu sein, nur um die Performance etwas zu verbessern. Müssten denn deine 50 Programme soviele Daten aus einer DB einlesen? - Könnte man das nicht etwas beschränken (z. B. nur Daten laden, wenn sie benötigt werden)? - Zudem glaube ich schon, dass die Performance einer reinen DB-Lösung nicht so schlecht wäre...

              Danke für Deine reflektierenden Antworten, ich werde wohl eher bei der persistenten Datenspeicherung in einer Datenbank bleiben und die Objekte bei jedem Skriptaufruf neu aus der Datenbank generieren. Tatsächlich kann ich die Objektklassen so ausgestalten, dass der DB-Zugriff nur auf konkrete Anforderung erfolgt.

              Es ist übrigens nicht schwer, ganze Objekte in der Datenbank abzubilden. Dazu brauchst du nur einen Mapper, der das Objekt in eine relationale Form bringt... Oder vielleicht hast du ja gar eine OODBMS ;)
              Hab ich auch schon gemacht und funktioniert prima.

              Dies wird zumindest vorläufig ausreichen. Später könnten aber Anforderungen folgen, wo ich enteder einen fetten Server hinstellen muss oder das Ganze gescheit in einer Applicationserver-Umgebung (WebObject, ASP oder andere) neu programmiere.

              Musst dir jedoch im klaren sein, dass z. B. der IIS (eg. für ASP) die Objekte auch nicht immer im Speicher lässt!

              Danke nochmals für Dein konstruktives Feedback und gute Nacht ;-)

              bitte und guten Morgen ;-)

              Viele Grüsse

              Philipp

              1. Guten Tag Philip ;-)

                Nochmals einzele Antworten zusammengefasst und nachgefragt:

                ... Aber es gibt die Möglichkeit, die XML-Config _einmal_ zu parsen und den ParseTree von XML::DOM im Speicher zu halten. Dann kannst du über das Socket durch diesen ParseTree "browsen", aber es werden gar keine XML-Files mehr geparsed. Übrigens: XML::DOM ist auch ziemlich lahm. XML::SAX wäre da viel, viel schneller, aber das "browsing" wird etwas mühsamer, wie ich denke. Aber wie gesagt, die Datei muss nur einmal geparsed werden (OK, das Traversieren/Durchlaufen des ParseTree ist bei XML::DOM auch etwas unperformant).

                [...]

                So was in der Art könnte ich mir vorstellen. Für die oben genannte XML-Schnittstelle habe ich mir schon ein XPath-ähnliches Interface geschrieben, werde nun aber auf das Modul XPath wechseln. Damit sollte sich so was grundsätzlich lösen lassen, aber wie gesagt, dazu muss jedes einzelne Objekt bei jedem Skriptaufruf nochmals durch den XML-Parser ... :-(

                Mit einigen Anpassungen nicht. Der ParseTree liegt ja im Speicher des Daten-Scripts. Du musst dein XPath-Modul nur so abändern, dass es durch das Socket kommuniziert und ein anderes XPath-Modul im Daten-Script aufruft, der den Node zurückliefert (ohne das XML neu zu parsen => das XPath Modul muss auf den Memory-ParseTree von XML::DOM zugreifen).

                Aktuell setze ich das Modul XML::Parser mit Style=Object ein, das ein etwas merkwürdiger Objektbaum zurückliefert.
                Darüber habe ich eine eigene XML-Klasse gestrickt, welche eine Zugriff auf die XML-Elemenet mit Methoden wie getNodeByID(),  getNodesByElement(), etc. zurückliefert.
                Zufällig bin ich nun aber über das Modul XML::XPath gestolpert, das noch viel umfangreicher Funktionalität bietet und vor allem schon fertig ist. Dieses Modul verwendet aber einen eigenen Parser (XML::XPath::Parser). Wie schnell dieser ist, weiss ich aktuell noch nicht, aber er basiert ebenso wie XML::Parser auf dem Expat-Parser.

                Wo bekomme ich eigentlich das Modul XML::SAX her? Auf CPAN habe ich es nicht gefunden.

                Zurück zum Problem.
                Die XML-Daten werden durch den übergelagerten Daten-Server geparst der resultierende Tree im Speicher gehalten.
                Nun kommuniziere ich von den Darstellungsskripts mit XPath-Anweisungen (sind ja relativ kurze einfache Befehle, bzw. Strings)
                zum Datenserver.
                Falls ich alle Anfragen zum Datenserver so formuliere, dass er mir nur Attributwerte oder Elementinhalte (Text) zurückliefern muss, dann kann ich mir die Seriealisierung tatsächlich sparen. Sollte ich aber Auflistungen von Objekten (als Hashes oder Arrays) benötigen, so komme ich um die Serialisierung nicht herum und dies kostet wieder Performance.
                Darüber werde ich noch nachdenken müssen.
                Danke aber erst mal für die konzeptionelle Idee.

                [...]

                Nun, fork läuft auf allen Unix-Derivaten. Bekanntlich gehört Win leider nicht dazu... *sorry*

                Mal sehen, ob ich hierfür eine eigene Win32-Variante entwickle oder die Win32-Lösung nur bei kleinen Installationen in Frage kommt, bei denen ein Datenserver ausreicht.

                Es ist übrigens nicht schwer, ganze Objekte in der Datenbank abzubilden. Dazu brauchst du nur einen Mapper, der das Objekt in eine relationale Form bringt... Oder vielleicht hast du ja gar eine OODBMS ;)
                Hab ich auch schon gemacht und funktioniert prima.

                Eine RDBMS setze ich auch als persistener Datenspeicher ein. XML ist nur die Import-/Export-Schnittstelle zu Fremdsystemen.
                Im ersten Schritt werde ich alle Objekte bei jedem Skriptaufruf aus der Datenbank laden.
                Die Lösung mit dem Datenserver und der Socketkommunikation hebe ich mir für Installationen mit höheren Anforderungen auf.
                Trotzdem vielen Dank für die Anregungen.

                Grüsse
                Eisbär

                1. Halihallo Eisbär

                  Mit einigen Anpassungen nicht. Der ParseTree liegt ja im Speicher des Daten-Scripts. Du musst dein XPath-Modul nur so abändern, dass es durch das Socket kommuniziert und ein anderes XPath-Modul im Daten-Script aufruft, der den Node zurückliefert (ohne das XML neu zu parsen => das XPath Modul muss auf den Memory-ParseTree von XML::DOM zugreifen).

                  Aktuell setze ich das Modul XML::Parser mit Style=Object ein, das ein etwas merkwürdiger Objektbaum zurückliefert.
                  Darüber habe ich eine eigene XML-Klasse gestrickt, welche eine Zugriff auf die XML-Elemenet mit Methoden wie getNodeByID(),  getNodesByElement(), etc. zurückliefert.
                  Zufällig bin ich nun aber über das Modul XML::XPath gestolpert, das noch viel umfangreicher Funktionalität bietet und vor allem schon fertig ist. Dieses Modul verwendet aber einen eigenen Parser (XML::XPath::Parser). Wie schnell dieser ist, weiss ich aktuell noch nicht, aber er basiert ebenso wie XML::Parser auf dem Expat-Parser.

                  Also an Expat kann die Performance nicht scheitern, da dieser mit C programmiert ist. Das Problem der Performance ist, wie die geparsten Daten abgebildet werden und wie effizient darauf zugegriffen werden kann.

                  Wo bekomme ich eigentlich das Modul XML::SAX her? Auf CPAN habe ich es nicht gefunden.

                  Was? - Dort muss es aber sein ;)
                  http://www.cpan.org/authors/id/M/MS/MSERGEANT/

                  Die XML-Daten werden durch den übergelagerten Daten-Server geparst der resultierende Tree im Speicher gehalten.
                  Nun kommuniziere ich von den Darstellungsskripts mit XPath-Anweisungen (sind ja relativ kurze einfache Befehle, bzw. Strings)
                  zum Datenserver.
                  Falls ich alle Anfragen zum Datenserver so formuliere, dass er mir nur Attributwerte oder Elementinhalte (Text) zurückliefern muss, dann kann ich mir die Seriealisierung tatsächlich sparen. Sollte ich aber Auflistungen von Objekten (als Hashes oder Arrays) benötigen, so komme ich um die Serialisierung nicht herum und dies kostet wieder Performance.

                  Nun, eine gewisse Serialisierung musst du wohl oder übel machen (wenn du auf Arrays oder Hashes zugreifst), aber wenn keine Rekursiven Strukturen dabei sind, ist die Serialisierung denkbar einfach:

                  %test = ( 'philipp' => 'hasenfratz', 'du' => 'dunachnahme');

                  => philipp;hasenfratz;du;dunachname

                  genau gleich bei arrays. Auch rekursive Datenstrukturen wären denkbar, wenn du die "untergeordneten" ';' kodierst. Das wäre etwas performanter, als einen XML-Parser einzusetzen (ungetestet).

                  Es ist übrigens nicht schwer, ganze Objekte in der Datenbank abzubilden. Dazu brauchst du nur einen Mapper, der das Objekt in eine relationale Form bringt... Oder vielleicht hast du ja gar eine OODBMS ;)
                  Hab ich auch schon gemacht und funktioniert prima.

                  Eine RDBMS setze ich auch als persistener Datenspeicher ein. XML ist nur die Import-/Export-Schnittstelle zu Fremdsystemen.
                  Im ersten Schritt werde ich alle Objekte bei jedem Skriptaufruf aus der Datenbank laden.
                  Die Lösung mit dem Datenserver und der Socketkommunikation hebe ich mir für Installationen mit höheren Anforderungen auf.
                  Trotzdem vielen Dank für die Anregungen.

                  Aber bitte.

                  Viele Grüsse

                  Philipp

                  1. Hallo Philip

                    Wo bekomme ich eigentlich das Modul XML::SAX her? Auf CPAN habe ich es nicht gefunden.

                    Was? - Dort muss es aber sein ;)
                    http://www.cpan.org/authors/id/M/MS/MSERGEANT/

                    Wo habe ich nur gesucht, dass ich es nicht gefunden hab. *kopfschüttel*

                    Ist nun installiert und liest sich vielversprechend.
                    Werde mich aber erst später auf das Redesign meiner XML-Klasse stürzen.

                    Nun, eine gewisse Serialisierung musst du wohl oder übel machen (wenn du auf Arrays oder Hashes zugreifst), aber wenn keine Rekursiven Strukturen dabei sind, ist die Serialisierung denkbar einfach:

                    %test = ( 'philipp' => 'hasenfratz', 'du' => 'dunachnahme');

                    => philipp;hasenfratz;du;dunachname

                    genau gleich bei arrays. Auch rekursive Datenstrukturen wären denkbar, wenn du die "untergeordneten" ';' kodierst. Das wäre etwas performanter, als einen XML-Parser einzusetzen (ungetestet).

                    Da wirst Du sicherlich recht haben.

                    Aber bitte.

                    Danke fürs erste, ich werde mich bei Gelegenheit wieder melden.

                    Grüsse
                    Eisbär

                    1. Halihallo Eisbär

                      Wo bekomme ich eigentlich das Modul XML::SAX her? Auf CPAN habe ich es nicht gefunden.

                      Was? - Dort muss es aber sein ;)
                      http://www.cpan.org/authors/id/M/MS/MSERGEANT/

                      Wo habe ich nur gesucht, dass ich es nicht gefunden hab. *kopfschüttel*

                      *frage-zeichen-auf-meiner-stirn*, weiss nicht ;-)
                      Du kriegst eigentlich alle Module unter

                      http://www.cpan.org/modules/01modules.index.html

                      Ist nun installiert und liest sich vielversprechend.
                      Werde mich aber erst später auf das Redesign meiner XML-Klasse stürzen.

                      Okidoki ;-)

                      Nun, eine gewisse Serialisierung musst du wohl oder übel machen (wenn du auf Arrays oder Hashes zugreifst), aber wenn keine Rekursiven Strukturen dabei sind, ist die Serialisierung denkbar einfach:

                      %test = ( 'philipp' => 'hasenfratz', 'du' => 'dunachnahme');

                      => philipp;hasenfratz;du;dunachname

                      genau gleich bei arrays. Auch rekursive Datenstrukturen wären denkbar, wenn du die "untergeordneten" ';' kodierst. Das wäre etwas performanter, als einen XML-Parser einzusetzen (ungetestet).

                      Da wirst Du sicherlich recht haben.

                      Ich denke auch, wobei sich das ganze dann auf das langsamere Perl stützt. Oder willst du einen eigenen C-Parser dafür schreiben? ;-)
                      Naja, aber es dürfte wohl etwas schneller sein, ja.

                      Danke fürs erste, ich werde mich bei Gelegenheit wieder melden.

                      *freu* ;-)

                      Sorry, dass ich dir bei mod_perl nicht helfen kann, aber da fällt mir auf die schnelle nix ein (sollte mich auch mal damit beschäftigen, aber die Zeit, wo ist die Zeit...) :-((

                      Viele Grüsse

                      Philipp

                      1. Hallo Philip

                        Ich denke auch, wobei sich das ganze dann auf das langsamere Perl stützt. Oder willst du einen eigenen C-Parser dafür schreiben? ;-)
                        Naja, aber es dürfte wohl etwas schneller sein, ja.

                        Mit C gehen meine Erfahrungen nicht viel weiter als ein paar Hallo-Welt-Programme etc. (C für Schüler oder ähnliches).
                        Falls es mich irgendwann packt, weiss ich ja wohin ich mich wenden kann ;-))

                        Danke fürs erste, ich werde mich bei Gelegenheit wieder melden.

                        *freu* ;-)

                        :-))

                        Grüsse
                        Eisbär

                        1. Halihallo Eisbär

                          Ich denke auch, wobei sich das ganze dann auf das langsamere Perl stützt. Oder willst du einen eigenen C-Parser dafür schreiben? ;-)
                          Naja, aber es dürfte wohl etwas schneller sein, ja.

                          Mit C gehen meine Erfahrungen nicht viel weiter als ein paar Hallo-Welt-Programme etc. (C für Schüler oder ähnliches).
                          Falls es mich irgendwann packt, weiss ich ja wohin ich mich wenden kann ;-))

                          Naja, über dieses Stadium bin ich auch noch nicht hinweg :-(( :-)
                          Aber was noch nicht ist, kann noch werden... C zu lernen steht auf jeden Fall auf meiner Liste für's Christkind ;)

                          Viele Grüsse

                          Philipp

  2. Hallo Leute

    Ich habe nun mal in der Dokumentation von mod_perl gestöbert. Dabei fiel mir auf, dass von mod_perl Mechanismen angeboten werden, um Datenobjekte über die Laufzeit des Apacheservers im Speicher zu halten. Bestes Beispiel dazu ist der DBI-Handler im Modul Apache::DBI, der über mehrere Skriptaufrufe persisten im Speicher gehalten werden soll.

    Ausserdem gibt es die Möglichkeit bei verschiedenen Ereignissen wie Start des Apaches Perl-Skripte auszuführen.
    Können in solchen Skripten, bzw. Modulen auch Datenobjekte (HASHes, ARRAYs, etc.) definiert werden?
    Welchen Scope haben diese Objekte?

    Hat jemand Erfahrung mit der Programmierung grösserer Applikation unter mod_perl?

    Wie müsste ein Datenobjekt im Start-Skript definert werden und mit welcher Syntax kann man aus den normalen request-Skripts auf diese Datenobjekte zurückgreifen?

    Um jede Hilfestellung wäre ich dankbar.

    Grüsse
    Eisbär