Manu: Chat mit wenig Traffic

Hallo zusammen,

vielleicht hat hier jemand eine Idee zu meiner Problemstellung:

Ich möchte einen Chat realisieren, aber irgendwie vermeiden, dass die DB-Queries von den Clients abgesetzt werden, da das bei vielen Usern recht hohen DB-Traffic verursacht. Stattdessen schwebt mir vor, bspw. über Soap die Daten zentral zu holen und sie für die Benutzer vorzuhalten. Dabei sollten sie einmal geholt werden und auf Anfrage der Clients zurückgeschickt werden.
Jetzt ist mir aber nicht wirklich klar, ob das realisierbar ist: wie würde ich an die Daten herankommen?
Beispiel: der Soap-Server holt die Daten einmal - sagen wir - minütlich. Kann ich dann nach 30 sek an ihn herantreten und mir die Daten holen?

Gruß,
Manu

  1. Hello,

    kommt darauf an, ob es ein P2P-Chat oder ein Pool-Chat werden soll.

    Die Clients können eine einfache Datei auslesen. Nur bei Änderungen, also wenn etwas gesendet wurde, wird dieser Datei der Absatz hinzugefügt.

    Somit erhält man für das Polling der Clients (z.B. per AJaX) eine relativ geringe Last, weil die Dateien nicht exclusiv, sondern nur shared gesperrt werden müssen.

    Für jeden eröffneten Chat-Slot benötigst Du dann nur eine Datei. Eine Datenbank ist doch nur angemessen, wenn die Daten permanent gespeichert bleiben sollen. Dies ist dann aber im Hintergrund mit einem Update delayed / Update Low Priority möglich.

    Das sollte die Datenbank dann schaffen bis zu einigen Tausend gleichzeitigen Chats.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hallo Tom,

      danke für Deine Antwort. Ich hatte mir auch schon überlegt, die Daten in einer Datei vorzuhalten, um die Datenbanklast zu verringern.
      Die DB würde somit nur benutzt, wenn jemand etwas schreibt (zum Loggen/Ausfallsicherheit).
      Was meinst Du genau mit "nicht exclusiv, sondern nur shared gesperrt werden"?

      Die eigentliche Frage ist aber ganz generell, ob es mit PHP möglich ist, dass verschiedene Clients auf ein- und dasselbe Objekt per Referenz oder wie-auch-immer zugreifen können (im obigen Fall die Daten, die ein Soap-Service liefern würde und die ja im RAM liegen).

      Gruß,
      Manu

      1. Hello Manu,

        danke für Deine Antwort. Ich hatte mir auch schon überlegt, die Daten in einer Datei vorzuhalten, um die Datenbanklast zu verringern.
        Die DB würde somit nur benutzt, wenn jemand etwas schreibt (zum Loggen/Ausfallsicherheit).
        Was meinst Du genau mit "nicht exclusiv, sondern nur shared gesperrt werden"?

        Exclusiv gesperrt werden muss die Datei nur zum Verändern, also "Auslesen - Verändern - Schreiben". Das geschieht genau dann, wenn eines der SchnatterInchen einen Beitrag zur Kommunikation sendet. Dann sollte der in die Datei eingetragen werden und bei dieser Gelgenheit ggf. auch der älteste herausgelöscht werden, wenn es denn genügend Absätze im Scope sind.

        Zum Abfragen, ob bereits wieder ein Beitrag gekommen ist, reicht dann ein Shared Lock. Der Client muss also zwei Methoden für AJaX vorhalten und der Server muss darauf reagieren können mit seinen Methoden/Funktionen.

        Wenn man stattdessen bei jeder einfachen Abfrage ein exclusives Lock verwendet, was durchaus ginge, wird der Fileserver damit doch erheblich belastet.

        Die eigentliche Frage ist aber ganz generell, ob es mit PHP möglich ist, dass verschiedene Clients auf ein- und dasselbe Objekt per Referenz oder wie-auch-immer zugreifen können (im obigen Fall die Daten, die ein Soap-Service liefern würde und die ja im RAM liegen).

        Du könntest Dich an den Shared-Memory-Funktionen von PHP versuchen.
        http://de.php.net/manual/de/ref.sem.php
        http://blog.taragana.com/index.php/archive/how-to-use-shared-memory-in-php/de/

        Ob das aber nun besonders geschickt ist, käme auf einen Versuch an.
        Platten-Speicherplatz ist i.d.R. erheblich mehr vorhanden, als RAM. Die Zugriffe (Requests) werden schlussendlich doch meistens serialisiert abgewickelt, sodass daselbe RAM allen Prozessen nacheinander zur Verfügung steht. Wenn Du aber die Daten persistent im Speicher halten willst, dürfen sie ja nicht freigegeben werden bis zum nächsten Request.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. Hi Tom,

          vielen Dank für die Infos zu Shared Memory!
          Das werde ich mir später einmal genau anschauen.
          Es geht halt darum, bei einer Browser-Anwendung per sekündlichem Ajax-Request Stati (zb. von anderen Benutzern) abzufragen; hier möchte ich eigentlich nur eine Query und nicht (Query*Anzahl Benutzer) benutzen.

          Zum Abfragen, ob bereits wieder ein Beitrag gekommen ist, reicht dann ein Shared Lock. Der Client muss also zwei Methoden für AJaX vorhalten und der Server muss darauf reagieren können mit seinen Methoden/Funktionen.

          Das sieht schwer nach fopen('r') bzw. fopen('a+') aus...
          Sollte ja zu schaffen sein...

          Gruß,
          Manu

          1. Hello,

            Das sieht schwer nach fopen('r') bzw. fopen('a+') aus...
            Sollte ja zu schaffen sein...

            Mit fopen(..., 'a+') musst Du noch nicht einmal sperren, da die Datei dann immer nur verlängert wird und die Schreiboperation vom Filesystem bereits "atomarisiert" wird.

            Das hat dann aber den Nachteil, dass Du nicht gleichzeitig den ältesten Eintrag (wenn es denn schon genug sind) aus der Datei entfernen kannst.

            Was für Stati willst Du denn abfragen?
              Keine Chats vorhanden: keine Chat-Dateien vorhanden
              User A bietet User D einen chat an:
                Chat-Datei wird im Verzeichnis A angelegt und Dummy-Datei im Verzeichnis D,
                wenn im Verzeichnis D noch keine der beiden vorhanden ist. Anderenfalls
                bekommt A eine "besetzt"-Anzeige.

            usw.

            Oder wie willst Du die Logik aufbauen?

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
            1. Hallo Tom,

              Das hat dann aber den Nachteil, dass Du nicht gleichzeitig den ältesten Eintrag (wenn es denn schon genug sind) aus der Datei entfernen kannst.

              Ich denke, dass ich schon hier aufpassen muss, dass ich nicht zuviele Daten über die Requests schicke - ich habe da neben dem Chat noch mehr vor - daher war auch die Frage, wie man die Datenbankabfragen möglichst gering hält bzw. wie man verhindert, dass jeder angemeldete Benutzer Queries initiiert.
              D.h. im Grunde genommen für den Chat, dass ich eigentlich nur die neuesten Meldungen schicken möchte - wird eine neue Seite betreten, ist das Chatfenster erst einmal leer (mal schauen, wie das nachher aussieht, ob ich eine Art Gespräch auch über mehrere Seiten aufrecht erhalte...- vll. mache ich es mir mit einem iframe leichter, aber ich mag die Dinger nicht besonders...:)).
              Für den Chat stelle ich mir noch ein paar Features vor wie Flüstern (und im gleichen Channel bleiben), aber darüber habe ich mir noch keine Gedanken gemacht, das wäre nice to have.

              Abgesehen vom Chat geht es darum, den Benutzern möglichst dynamisch und datenbankfreundlich alle möglichen Statusinformationen (über andere Benutzer und deren Aktionen) zu bieten. Da ich ohne Anfrage leiderleider nicht vom Server an den Client senden kann, dachte ich an Events, die vom Client aus laufend (alle 1-2s) ein Script befragen, ob sich was im shared memory getan hat und dann ggf. die Sicht updated. Wird eine Aktionausgeführt oder findet einen Statusänderung statt, ändern sich die Werte im shm.
              Wie oft ich nun die DB update ist mir noch nicht klar - natürlich möchte ich das so lange wie möglich hinauszögern, um möglichst effizient zu bleiben. Aber es wird sich zeigen müssen, ob das so nicht zu anderen Problemen führt, die mir jetzt noch nicht bewußt sind...

              Viele Grüße,
              Manu

          2. Hello Manu,

            wie lange kann man einen XMLHttp-Request überhaupt offen halten, bevor es ein Timeout gibt?
            Was belastet das Netz mehr? Ein offener Request, oder häufige kurze Requests?
            Was belastet den Server mehr? Wartenzeiten (sleep) in einer Schleife, oder häufige Requests?

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
            1. Hallo :)

              wie lange kann man einen XMLHttp-Request überhaupt offen halten, bevor es ein Timeout gibt?

              Gute Frage... Bei meinen bisherigen Requests auf relativ große Datenmengen habe ich bisher noch keine Timeouts bekommen (vll. sollte ich das auch mal die Backend-Nutzer fragen, ob die das auch so sehen :))

              Was belastet das Netz mehr? Ein offener Request, oder häufige kurze Requests?

              Ich vermute häufige kurze Requests belasten schon mehr als ein offener, wobei das ja mit der obigen Frage verwandt ist...Wie man einen Request offen hält, kann ich aber nicht sagen.
              Ich habe in vielen Projekten xajax in Betrieb, da geht nicht viel, wenn das Response-Objekt nicht zurück gegeben wird.

              Was belastet den Server mehr? Wartenzeiten (sleep) in einer Schleife, oder häufige Requests?

              Kann ich nur vermuten...

              Gruß,
              Manu

              1. Hello,

                Was belastet das Netz mehr? Ein offener Request, oder häufige kurze Requests?
                Ich vermute häufige kurze Requests belasten schon mehr als ein offener, wobei das ja mit der obigen Frage verwandt ist...Wie man einen Request offen hält, kann ich aber nicht sagen.
                Ich habe in vielen Projekten xajax in Betrieb, da geht nicht viel, wenn das Response-Objekt nicht zurück gegeben wird.

                Was belastet den Server mehr? Wartenzeiten (sleep) in einer Schleife, oder häufige Requests?
                Kann ich nur vermuten...

                Na, wenn man einen Request ewig lange offen halten kann (was ja eigentlich HTTP widerspricht), dann bräuchte man nicht ständig zu pollen, sondern eben nur einmal, und dann warten, bis das Script eine Antwort sendet. Das Script kann dann innerhalb einer Schleife prüfen, ob die angeforderte Antwort bereits vorliegt und antwortet erst dann, wenn sie zur Verfügung steht, oder klar ist, dass keine mehr kommt. Danach ist der Roundturn geschlossen. Die Sleep-Zeiten im Script sind für den Server i.d.R. billig.

                Liebe Grüße aus dem schönen Oberharz

                Tom vom Berg

                --
                Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
                1. Moin.

                  Na, wenn man einen Request ewig lange offen halten kann (was ja eigentlich HTTP widerspricht), dann bräuchte man nicht ständig zu pollen [...]

                  Das ist mWn möglich: Vor einiger Zeit habe ich so mal spaßeshalber einen PHP-Chat realisiert, der Dank Übertragung in chunks neue Nachrichten direkt über eine persistente TCP-Verbindung ausgibt.

                  Ob das aber tatsächlich ressourcenschonender ist, kann ich nicht sagen: DIe TCP-Verbindung aufrechtzuerhalten ist auch nicht kostenlos...

                  Christoph

                  1. Hello,

                    Na, wenn man einen Request ewig lange offen halten kann (was ja eigentlich HTTP widerspricht), dann bräuchte man nicht ständig zu pollen [...]

                    Das ist mWn möglich: Vor einiger Zeit habe ich so mal spaßeshalber einen PHP-Chat realisiert, der Dank Übertragung in chunks neue Nachrichten direkt über eine persistente TCP-Verbindung ausgibt.

                    Ob das aber tatsächlich ressourcenschonender ist, kann ich nicht sagen: DIe TCP-Verbindung aufrechtzuerhalten ist auch nicht kostenlos...

                    Das primäre Problem dabei könnte sein, dass Browser nur eine begrenzte Anzahl von gleichzeitigen Verbindungen zum selben Host zulassen. Wenn da nun eine der beiden (IE hat zeitweise nur 2 Verbindungen zugelassen) offen steht, kann die Seite ggf. nicht weiter abgearbeitet werden.

                    Aber das war auch eher eine theroetische Überlegung, denn in Verbindung mit AJaX habe ich das bisher auch noch nicht ausprobiert.

                    Liebe Grüße aus dem schönen Oberharz

                    Tom vom Berg

                    --
                    Nur selber lernen macht schlau
                    http://bergpost.annerschbarrich.de
                    1. Naja, ganz so weit bin ich noch nicht, aber ich werde hier mal posten, was ich für Ergebnisse erzielen konnte.

                      Danke jedenfalls für die hilfreichen Tipps/Anmerkungen...

                      Gruß,
                      Manu