mmofacts.com

Push Applied

gepostet vor 19 Jahre, 3 Monate von schokofreak
Guten Tag

Aus einer eher privateren Diskussion hab ich vor 3 Monaten schon versprochen endlich mal ein Push- Sample zu zeigen. Hier kommt es nun mit solch einer verspätung

http://ae87.s1.domainkunden.de/chatdemo.zip

Es würde mich freuen, wenn es jemand uploadet auf einem PHP server und die URL dazu hier postet!!!

Was ist das:
- Auszug aus einem grossen Framework (hat 1 h gedauert, das aus Framework zu extrahieren)
- teilweise precompilierter / generierter / zerhäckselter Code (HÄSSLICH)
- Demonstration eines Pushs

Wie funktioniert es:
- install.php aufrufen (ev. includes /inc_db.php anpassen)
- index.php aufrufen
- benutzer erstellen
- 2. benutzer erstellen
- beide einloggen
- auf chat gehen
- message eintippen - benutzername eingeben
- senden
- man sieht sich gegenseitig

WICHTIG:
- Das ganze ist für IE 6.0 / neuester FF empfohlen.
- Sourcecode ist schmutzig, ist mir klar (da extrahiert). Bei Fragen zur Funktion lieber mich fragen wenn ihr nicht durchblickt
- Das ganze ist ungewohnt instabil geworden (Javascript Fehler) da es aus Framework extrahiert wurde
- SEHR WICHTIG: Eine Instanz nur auf einem Browser laufen lassen. Also 2 Sessions in einem IE oder in einem FF oder so geben ärger
- 2 mal unter selbem User Einloggen nicht möglich

Danach würd ich mich über n Feedback freuen. Respektive wie ihr die Last seht. Vor allem im vergleich zu Ajax Pulls.

Ah ja zu guter Letzt: Stand des Kerns (Push in PHP) ca. 10 Monate. Stand des Javascripts ca. 2 Jahre. Davor ist das ganze auf anderen Platformen gelaufen -> fazit; das ist ganz und gar keine neue Technologie.

Gruss

Christian

EDIT: Ihr wollt kein Push? Pullen ist geiler?
-> Kein Problem: includes / inc_userSession.php / define('HASPUSH', FALSE);
Applikation funktioniert genauso wie zuvor; ohne Code änderung nix.

Ihr wollt das Push / Pull Timeout abändern? Kein Problem: sessionScripts.js hilft euch weiter (oberste definitionen). Kann auch zu Pull alla 1 sec vergewaltigt werden im Sinne von Ajax implementationen

Edit 2: Anforderungen (laut ersten Erfahrungen)
- SOCKETS (Primär UDP Sockets; Kann auch auf Unix Sockets umgestellt werden)
- Save Mode muss so schlau sein, dass Scripte nicht schon nach 30 Sekunden abgebrochen werden

Ah ja: Daran denken... auch wenn da nirgends was von lizenz steht...es gilt dennoch das Urheberrecht. Spielen = ok; Pröblem = ok; einsetzen = bitte rückfragen (aba wohl auch ok)
gepostet vor 19 Jahre, 3 Monate von Temruk
Ähm, auch wenn ich mich jetzt ggf oute aber was zur Hölle ist ein "push"?
gepostet vor 19 Jahre, 3 Monate von schokofreak
Original von schokofreak irgendwo hier im Forum

Heute solls um den beleibt- Berüchtigten Push gehen.

1. Was ist Push
Browsergames leben einerseitz von Aktionen, welche vom Benutzer im Browser vorgenommen werden, andererseitz aber auch von Aktionen, welche 3. Benutzer durchführen. Das Ziel jeden Games muss es sein, dass man möglichst rechtzeitig erfährt, wenn ein anderer Benutzer eine Aktion durchführt, welche wichtig sein könnte.
Was heist das? Push = Realtime Benachrichtigung eines Clients in einem Browsergame. JETZT wirsd du angegriffen.

2. Wo ist das Problem dabei
HTTP kennt leider keine Möglichkeit, dass der Server einen Client benachrichtigen kann. Das heist die naheliegendste Möglichkeit ist, dass der Client vortzu beim Server nachfragen geht, ob neue Daten vorhanden sind. In Games, wo die Interaktion sehr wichtig ist (beispiel freewar) verursacht dies pro 1, 2 Sekunden eine Serveranfrage (genannt Pull).
So viele Serveranfragen kosten Ressourcen, und sind unschön da der User immer wieder ein Reload- Click hört.
Es muss möglich sein, dass der Server direkt auf den client senden kann.

3. Wie kann man Push theoretisch implementieren.
Das ICQ2Go macht es vor. Man öffne eine HTTP- Verbindung, und lasse die permanent offen. Sprich, der server wird einfach nicht vertig, mit dem Senden von Daten. Der Client liest jederzeit die Daten aus, welche gerade empfangen werden. Er wartet daraufhin, bis neue Daten ankommen.
Fazit: Man hat einen neuen "Kommunikationskanal" geschaffen.

4. Wie implementiert man sowas im Client
Der Client hat nur die Aufgabe, eine Verbindung zu öffnen, diese offen zu halten, und immer wieder nachzusehen ob Daten empfangen wurden.
ICQ2Go geht hier über ein Java Applet. Eine weitere möglichkeit ist JavaScript und Frames.
Java / JavaScript öffnet Verbindung, liest solange die besteht die empfangenden Daten immer wieder aus, und gibt sie weiter an die Endverarbeitung.
Konsequenz daraus? der Client hat eine sehr grosse Verantwortung, was das Darstellen von Daten angeht. (Nimmt im Prinzip eine Controller funktionalität ein).

5. Serverimplementation.
Die Implementationen auf dem Server sind sehr unterschiedlich und abhängig von der genutzten Server- Software....
-> Vortsetzung folgt.


Über die Serverimplementation hab ich zwar noch nix geschrieben, da im Forum wenig los war...
Aber im Grossen und Ganzen gehts darum.

Gruss
gepostet vor 19 Jahre, 3 Monate von wusch
--- Ohne die Demo anzusehen (bin zu faul das zu installen) ---

naja ob das so viel resourcensparender ist?

Überleg mal: Wenn 1000 user online sind und alle eine Endlos-Verbindung zum Server haben? Kann mir net vorstellen, dass das so sehr stabil ist

Ich kenn das von meinem alten Chat - der war in Java geschrieben und er hatte schon Probleme, wenn 30 User gleichzeitig on waren. Der neue in C++ hat diese Probleme net so schnell

Ansonsten: Überzeug mich mal vom Gegenteil.
gepostet vor 19 Jahre, 3 Monate von TheUndeadable
Eine Demo ist auf
http://burn-alligator.dyndns.org:85/chatdemo/chatdemo installiert. (T-DSL-Anbindung bei 128 kBit/s Upload (davon immer etwas für diverse Dinge belegt) )

Es geht nicht darum, dass das resourcenschonender als kein Push ist, es geht hauptsächlich darum aktiv Inhalte an den Browser zu senden, auch wenn dieser keine direkt angefordert hatte.
gepostet vor 19 Jahre, 3 Monate von schokofreak
Original von wusch
--- Ohne die Demo anzusehen (bin zu faul das zu installen) ---
naja ob das so viel resourcensparender ist?


Bei obiger Implementation verhält es sich so:
- Jeder User hat eine permanente HTTP Verbindung. Diese wird alle 10 min oder so neu erstellt.
- Wenn der user keine Daten erhält, sind die Threads / Prozesse dieser Verbindung blokierend am warten -> benötigen 0 % Prozessorlast
- Aufbau / Abbau einer Verbindung benötigt etwa gleich viel Prozessorlast wie 2 normale PHP Requests

Die grosse Frage ist nur: Was ist das für ein WebServer.
Bei einem Apache 1 wäre das pro User ein Prozess. Merke: Ein Prozess braucht nix. Ram wird eh teilweise geshared (nicht auf Virtueller ebene aber absolut)... Da passen problemlos 1000 blokierte Prozesse drauf.
Bei Apache 2.0 entspricht das einem Thread. Und da macht es noch viel weniger aus.

Bei einem Webserver eigenbau bewirkten selbst 1000 schlafende Threads kein erhöhten Speicherbedarf / irgendwelche Prozessorlast.

Nun denken wir was anderes. Was macht denn AJAX?
Heutzutage ist es ein Muss, Keep- Alive eingeschaltet zu haben (jeder wird wohl wissen wieso). Bei AJAX bedeutet das aber (wenn man nicht aufpasst), dass so 5 bis 10 AJAX requests zusammen ebenfalls immer einen thread / Prozess belegen.
Nachdem ein Timer abgelaufen ist, wird der Prozess freigegeben... schon 2, 3 Sekunden später beim nächsten Pull wieder ein neuer Prozess reserviert für die nächsten 20, 30 Sekunden.

Ergibt viel Re-Scheduling, viel Netzwerklast, ...

Fazit: Es ist beides scheisse von wegen Leistung. ABER AJAX Pull ist einiges schlimmer.

Gruss
gepostet vor 19 Jahre, 1 Monat von schokofreak
*schieb*
gepostet vor 18 Jahre, 7 Monate von Temruk
*wiederrauszerr*

Hier an der Uni machen wir gerade an diesem Thema herum. Was bisher geht ist, dass man aus AJAX heraus einen SOAP-Pull auf einen Web-Service macht. Dazu hat man einfach einen Proxy vorgeschnallt, der den entsprechenden Request zusammenbaut. Wens genauer interessiert
hier ist das Paper dazu.

Wir versuchen das nun mal aufzubauen und dann umgekehrt einen Push zu realisieren. Wenn's noch jemanden interessiert schreib ich unsere Erfahrungen hier gerne auf.
gepostet vor 18 Jahre, 7 Monate von TheUndeadable
Insgesamt würde mich das Thema interessieren, nur habe ich momentan leider zuwenig Zeit dafür mich einzuarbeiten.

Genial wäre es, wenn es eine ASP.Net-Komponente gäbe, die man per einfach einbinden könnte und einem JS Informationen über neue Xml-Aktualisierungen übergeben könnte (am besten SOAP auf JS-Basis, so dass es auch von der Plattform (ASP.Net) unabhängig ist und man auch PHP oder Java nutzen kann).
gepostet vor 18 Jahre, 6 Monate von Flint
Hab mich gerade mal durch die Chatdemo gewühlt und find es Klasse. Hab diese Art der Umsetzung eines Server Push noch nicht gesehen und würde es mal eine gelungene Implementierung von "Comet" nennen.

Wenn ichs richtig verstanden habe machst du für jeden Streaming HTTP Request einen Socket auf und wartest dort bis eine Nachricht reinkommt die dann per Javascript an den Client geschickt wird.
Was mich interresieren würde ist, warum du von AF_UNIX auf UDP umgestellt hast und wo die Vor- und Nachteile liegen.
Und warum benutzt du socket_select statt socket_listen bzw. SOCK_DGRAM statt SOCK_STREAM.

Das einzige was mich an Streaming HTTP stört ist, das je nach Browser, eine Ladeanzeige ständig sichtbar ist und die Maus teilweise eine Sanduhr bekommt.

Das ganze ist auf alle Fälle Resourcen schonender als die Streaming HTTP Lösungen "Endlosschleife mit sleep" die ich bisher gesehen habe.
gepostet vor 18 Jahre, 6 Monate von schokofreak
Hallo Flint
Merci vielmals fuer die Fragen, gerne beantworte ich Dir diese.
Du hast korrekt erkannt, wie das ganze funktioniert. Alternativ zum Socket liesse sich auch UNIX Socket, Named Pipe oder Shared Memory mit Mutex einsetzen.

1. Das ganze ist im Moment auf Serverinterne UDP Sockets eingestellt, um allfaellige Inkompatibilitaeten zu vermeiden. Sprich das Sample laeuft auf Apache und IIS (sollt auf beliebigem WebServer laufen)
Einfach die kommentierten Zeilen auskommentieren, schon hast du UNIX Socket. Die Umstellung sollte sehr einfach realisierbar sein.

2. Die Ladebalken lassen sich in den meisten Browsern verstecken; so zumnindest unter IE, FF und Opera. Allerdings ist das Sample schon aelter, benoetigt ev. eine minimale Anpassung. Laesst sich sicher realisieren.
Wie du siehst, wenn du im Code gewuehlt hast, das Sample setzt auf chaotischem Code auf... eine Neuimplementierung macht allemal sinn. Machbar ist es, die Ladebalken und Sanduhren auszublenden (und ja, manche Teile des Codes sind mehr als 4 Jahre alt).

Vorausgesetzt man hat einen gut skalierenden Webserver mit Multithreading und Multitasking (sauber konfigurierter Apache2); so benoetigt eine einzelne Verbindung absolut keine Last... 0 Prozessorlast und ev. so 200 kByte ram.
1 Message versand ist 1 Name Pipe / Socket send intern und einer uebers netz... sprich auch absolut last minimiert.

Gerne beantworte ich weiter fragen, kann jedoch etwas dauern da ich im Moment in den "Ferien" weile.


Gruss

Christian
gepostet vor 17 Jahre, 8 Monate von Temruk
Leider ist die URL zum Demo inzwischen veraltet. Hat das zufällig noch jemand? Ich komme jetzt endlich mal dazu da was zu machen
gepostet vor 17 Jahre, 8 Monate von raufaser

3. Wie kann man Push theoretisch implementieren.
Das ICQ2Go macht es vor. Man öffne eine HTTP- Verbindung, und lasse die permanent offen. Sprich, der server wird einfach nicht vertig, mit dem Senden von Daten. Der Client liest jederzeit die Daten aus, welche gerade empfangen werden. Er wartet daraufhin, bis neue Daten ankommen.
Fazit: Man hat einen neuen "Kommunikationskanal" geschaffen.

Genau das hatte ich auch schonmal ausprobiert. Permanente HTTP Verbindung geöffnet, die dann JavaScript Befehle zurückgab, die evaluiert wurden.
Riesen Problem bei der Geschichte: Serverload. Das zwingt den Webserver (war ein Apache) ziemlich schnell in die Knie, wenn viele Clients verbunden sind.
Ein "Pull" über AsyncHTTP verbraucht hingegen kaum Resourcen.
Gruß,
Marc
gepostet vor 17 Jahre, 8 Monate von COrthbandt
Bin ich der einzige, der diese Technik für eine schlechte Idee hält?
Die offenen Verbindungen werden auf dem Server über sogenannte "ephemeral ports" realisiert und von denen hat man nur eine begrenzte Anzahl.
Je nach OS können das nur ein paar Tausend sein, oder auch über 60000. Aber auf keinen Fall mehr als 64511. Und da sehe ich ein Problem mit der Skalierbarkeit.
1. begrenzt man damit die Anzahl konkrurrenter User auf die Anzahl der verfügbaren ePorts.
2. kann das exzessive Offenhalten von Ports zu Problemen mit Databankverbindungen usw führen (keine Ports mehr dafür frei)
3. jeder offene Socket belegt Speicher. Unter Windows (bei Linux weiss ich es nicht genau) ist das locked mem, der NICHT geswapt werden kann. Ganz böse.
Unter W2k3 belegt jeder offene Socket eine Page (IIRC). Bei 50000 offenen Sockets sind das ca 200 MB Kernel-Memory. Aua.
Zum Thema "Port Exhaustion": Mir ist durchaus bekannt, dass _theoretisch_ auf einem ephemeral Port mehrere Verbindungen laufen dürfen, da beide Endpunkte die Verbindung identifizieren. Praktisch ist in allen OSes ein Socket aber eine einfache 16bit-ID, womit sich das wieder erledigt hat.
gepostet vor 17 Jahre, 8 Monate von Todi42
Original von COrthbandt
Bin ich der einzige, der diese Technik für eine schlechte Idee hält?

Ich halte das für eine ganz großartige Idee. Selbst wenn die Anzahl der offenen TCP/IP Verbindungen bei 32.000 begrenzt wäre, könnte man dann pro 32.000 Spieler eine andere IP-Adresse nehmen. Windows ist glaube ich das einzige Betriebssystem, das den für einen Socket benötigten Speicher im Kernel halt und damit nicht raus swapen kann (bei OpenVMS ist TCP/IP z.b. ein eigenständiges Produkt). Im schlimmsten Fall müste man den TCP layer selber implementieren. Das Problem ist z.Z. das es keine geeigneten Webserver gibt. Und jeder Workaround, der mit einer Verbindung gleichen einen Thread/Prozess belegt skaliert natürlich nicht besonders gut.
Die Möglichkeiten sind aber faszinierend. Endlich mal ein Orderbuch in einer Wirtschaftssimulation, bei der nicht ständig der refresh-Knopf gedrückt werden muß. Aktien-Charts, die sich mit jedem Kauf oder Verkauf aktualisieren. Chats, die ohne Pollen und deren Latenszeiten auskommen. Freundliche "Sie haben Post" Stimmen, wenn Post eingeht. Ach, ich komme aus dem Schwärmen gar nicht heraus ...
gepostet vor 17 Jahre, 8 Monate von exe
Die Frage ist nur, welcher Server wirklich zehntausende Verbindungen offen hat. Wenn ich 10.000 User online habe, dann hat das Spiel insgesamt vielleicht 100.000 Spieler, und dann habe ich dafür sowieso nicht mehr nur einen einzelnen Server.
Original von raufaser

Genau das hatte ich auch schonmal ausprobiert. Permanente HTTP Verbindung geöffnet, die dann JavaScript Befehle zurückgab, die evaluiert wurden.
Riesen Problem bei der Geschichte: Serverload. Das zwingt den Webserver (war ein Apache) ziemlich schnell in die Knie, wenn viele Clients verbunden sind.
Man kann da viel (zwar nicht unbedingt mit einem Apache) machen. In Jetty6 (ein Servletcontainer für Java), gibt es die sogenannten Continuations. Dabei kann einen Verbindung "suspendiert" werden, d.h. der Servletcontainer hält sich den Socket vor und gibt den Thread in seinen Threadpool zurück. Über Nonblocking-IO kann der Servletcontainer dann bestimmten auf welchem Socket wieder was reingekommen ist oder was rausgehen muss und dementsprechend für den Socket wieder einen Thread bereitstellen. Der enorme Vorteil an der Sache ist: man hat nicht einen haufen idle Threads, sondern kann mit einer niedrigen Anzahl von Threads eine große Anzahl von "HTTP Streams" bedienen. D.h. für 1000 "HTTP Streams" benötige ich vielleicht 10 Threads, denn Arbeit machen diese Streams ja nicht. Und ein paar tausend offene Sockets haben noch kein vernünftiges Betriebssystem in die Knie gezwungen ...
Ein "Pull" über AsyncHTTP verbraucht hingegen kaum Resourcen.

Dafür hast du für jeden Pull den Overhead eines Verbindungsaufbaus (der ist viel höher als das tatsächliche Senden über die Verbindung). Ausserdem kannst du kein Push vom Server aus machen. D.h. du musst ständig aus Verdacht raus Pullen, es könnte ja was Neues da sein ... Jetzt rechne mal, du hast 5.000 Clients, die alle 5 Sekunden Pullen. Macht 1.000 Verbindungen die pro Sekunde nur für dein Streaming aufgebaut und wieder geschlossen werden müssen ...
gepostet vor 17 Jahre, 8 Monate von schokofreak
Also bitte, wer sowas implementiert wird doch wohl auch in der lage sein, die Sessions zu begrenzen.
Rechnet mit maximal ca. 5000 aktiven Push Verbindungen auf dem Server. Somit ist der RAM Verbrauch nicht sonderlich gross, bei einer optimierten / gut konfigurierten Webserver konfiguration treten hier auch keine Probleme auf.
Für mehr als 5000 aktive User brauchts dann halt mehr Server. Aber mal ehrlich, schon mal überlegt was 5000 User bei einem Pull System (Ajax) anrichten? Mit Reloadzeiten alle 250 ms sind das 20'000 Anfragen pro Sekunde. Das steckt so gut wie kein Server einfach so weg.
Dummerweise hab ich selbst das Beispiel nciht mehr. Habe es vor kurzem gelöscht, da nicht weiterverfolgt (immer die selbe leier -> man kann mit BGs kein Geld machen).
gepostet vor 17 Jahre, 8 Monate von schokofreak
Original von Todi42
Das Problem ist z.Z. das es keine geeigneten Webserver gibt. Und jeder Workaround, der mit einer Verbindung gleichen einen Thread/Prozess belegt skaliert natürlich nicht besonders gut.

Nicht ganz, such mal in den uralten Themen. Hab mal 2 Sachen gemacht:
- Webserver marke Eigenbau, welcher pro 256 requests einen Thread benötigte. Plus im Inaktiven Fall genau 0 Prozessorlast.
Die Zahl von 256 lässt sich einersetz beinahe beliebig erhöhen. Bringt einfach Instabilitätsgefahren (wenn eine Clientverbindung ein Problem hat kann man nur alle 256 terminieren).
- Hab damals auch einen PHP Tauglichen Server gefunden, welcher n interessantes Threading modell hat. Somit auch kein Problem.
Der Server ist in meinen Augen absolut kein Problem. Die Serverskripte auch nicht (Lösungen sowohl in PHP, ASP.Net, ... whatever einfach lösbar). Das einzig schwierige ist die Clientside Implementation.
- Diese muss sowohl stabil sein (Ja, manche Clients machen tatsächlich Multi Threading obwohl sie meinen sie könnten es nicht).
- Man möcht keinen endlos Ladebalken
- Man möchte einzelne Records / Komplette Tabellen auf dem Client zwischenspeichern (Bandbreiten und Server Reduktion).
- Man möchte das ganze bei konstantem Memory load -> sprich ohne Memory leaks
Leider hab ich null sourcen mehr, aber die Machbarkeit garantier ich dir. Hab sogar mal n käufer gesucht für n Framework welches das beinhaltet; Plus ner Tabellensynchronisation und ner JavaScript Template engine.
Gruss
gepostet vor 17 Jahre, 8 Monate von Todi42
Original von schokofreak
Der Server ist in meinen Augen absolut kein Problem. Die Serverskripte auch nicht (Lösungen sowohl in PHP, ASP.Net, ... whatever einfach lösbar). Das einzig schwierige ist die Clientside Implementation.
Gruss

Das hört sich ja so an, als hätten wir eine Lösung, wenn wir unsere Sachen zusammenwerfen. Ich habe z.Z. eine Serverlösung, die in Ruby geschrieben ist, aber nicht besonders gut skalieren wird. Ich tippe aber mal, die Schnittstellen inkompatibel sind und auch nicht einfach angepast werden können.
Bei mir hat der Client zum Server eine Schnittstelle, bei dem er ein so genanntes "Subject" und Parameter angibt (z.B. subject="posteingang", parameter="spielereid:Todi"). Zusätlich gibt der Client eine Version der Daten an, die er zuvor vom Server erhalten hat (oder 0, wenn noch nie vom Server angefordert). Stimmt die Version des Clients mit der Version des Servers überein, antwortet der Server nicht. Stimmen die Versionen nicht überein, antwortet der Server mit den neuen Daten und der neuen Version.
Auf der anderen Seite gibt es eine Schnittstelle, bei der man angeben kann, das sich die Daten für ein bestimmtes subject und Parameter geändert haben. Da es im Persistenzlayer von Rails Callbacks gibt, läßt sich das recht einfach definieren, ohne das im Applikationskode explizit diese Änderungen bekannt gemacht werden müsten.
mfg Todi

Auf diese Diskussion antworten