mmofacts.com

Hintergrundskripte

gepostet vor 17 Jahre, 11 Monate von TheUndeadable
Folgender Status:
Da der IIS ein Applicationserver ist, wird eine Website als eine Anwendung gesehen und als ganzes behandelt.
- Der IIS lädt beim ersten Aufruf einer Website dieser Anwendung die Anwendung ein und ruft die Funktion ApplicationStart global auf. Dort möchte ich nun einen Hintergrund-Thread starten, der sich um die gesamte Ereignisbehandlung kümmert.
- Nach einigen Stunden Nichtbenutzung ruft der IIS die Funktion ApplicationEnd auf und entlädt die Anwendung. Auch wenn ich den Thread in ApplicationEnd nicht beende, wird der Thread gekillt. Es kann also keinerlei Berechnungen mehr stattfinden.
Es gibt nun mehrere Möglichkeiten:
- Ich stelle den IIS so ein, dass Anwendungen nicht entladen werden (nicht empfohlen, da Anwendungen regelmäßig neugestartet werden sollten [auch der Apache startet seine Kinderchen regelmäßig neu]).
- Ich bau mir ein kleines Skript, dass in einem 1 Minutentakt eine Website aufruft und damit den Start der Applikation erzwingt.
- Ich lasse die Applikation beenden. Beim Start der Applikation werden zuerst alle Ereignisse abgearbeitet, bevor die eigentliche Website gestartet wird.
- Ich bau einen externen Arbeitsprozess, der auf Dienste (Daemon)-Ebene arbeitet. Damit verliere ich aber die Möglichkeit alles einfach in statischen Variablen (bzw Singletons) zu speichern und zu cachen.
Die Frage stellt sich halt: Ist ein Spiel länger inaktiv bzw ist es schlimm, wenn beim ersten Seitenaufruf die Seitenabfrage bis zu 30 Sekunden dauert, weil noch einige dicke Nachtschlachten nachberechnet werden müssen.
Was ist eure Meinung, bzw wie würdet ihr vorgehen?
gepostet vor 17 Jahre, 11 Monate von KoMtuR
Man könnte doch ein Cronjob von 22 Uhr - 07 Uhr machen, der dann immer die Seite aufruft. Somit wirste halt diese Nachtschlachten abhandeln können (weiß nicht, ob du bei dem Seitenaufruf nur die Ereignisse vom Spieler betrachtest, oder generell alle).
edit:
wenn du in diesem Seitenaufruf alle Ereignisse betrachtest, könnteste es ja so ändern, dass der immer nur die Ereignisse zuerst behandelt, welche zu dem Spieler gehören. Somit sollten ja nicht die große Rechenzeit entstehen (weiß ja nicht, ob man bei dir 100 angriffe oder so machen kann, ohne einmal online zu sein). Um die restlichen Ereignisse nicht zu weit in die Vergangenheit kommen zu lassen, könnteste ja eine maximale Anzahl an an Ereignissen festlegen, die ein Spieler pro Seitenaufruf abarbeiten kann.
Beispiel:
Spieler 1 ruft Seite A auf und hat 20 Ereignisse. maximale Annzahl 50 Ereignisse. Somit kann er noch 30 Ereignisse abarbeiten, welche nicht mit ihm selber zu tun haben.
Spieler 2 ruft nun auch ne Seite auf und hat 60 Ereignisse. Es werden natürlich alle 60 abgearbeitet, aber es werden keine Aussenstehende bearbeitet.
Da ein Spieler meistens nicht nur eine Seite klickt, sondern in nen klick-Wahn gerät, sollten deine anderen Ereignisse ziemlich schnell abgehandelt sein.
gepostet vor 17 Jahre, 11 Monate von None
Nimm den Daemon.
Greif dir Florian und bring das Thema zum nächsten Stammtisch mit.
Solche Jobs haben in einem Endlosprozess der im IIS läuft nichts zu suchen.
gepostet vor 17 Jahre, 11 Monate von TheUndeadable
Für das JFS habe ich einen Dienst, wie du vorgeschlagen hast, geschrieben. Dieser läuft soweit so gut durch (wäre ja auch schade, wenn ein Dienst nicht gut läuft ;-) )
Das Problem ist einfach der, dass ein Dienst ein eigener Prozess ist und ich dementsprechend nicht direkt auf gemeinsame Variablen zugreifen kann. Statische Variablen zur gemeinsamen Objektkontrolle (wie Caches oder gemeinsames Logging) sind dann nicht mehr möglich.
Man natürlich per Remoting auf den Prozess zugreifen und sich so eine Instanz besorgen. Allerdings ist Remoting immer langsamer als der direkte Speicherzugriff und erfordert kleinere Korrekturen im Code, da in .Net die Objekte ausdrücklich als Remote-Objekte gekennzeichnet werden müssen.
> Solche Jobs haben in einem Endlosprozess der im IIS läuft nichts zu suchen.
Ja, irgendwie behagt mir das auch nicht wirklich, allerdings habe ich noch kein größeres Problem gesehen, wenn ich es trotzdem tu.
@Komtur:
Bei mir soll der Seitenaufruf selbst keine Berechnung veranlassen, sondern er soll das Einladen der Applikation veranlassen. Die Berechnung selbst soll in einem separatem Thread ablaufen. Evtl habe ich dich auch falsch verstanden.
gepostet vor 17 Jahre, 11 Monate von KoMtuR
Original von TheUndeadable
@Komtur:
Bei mir soll der Seitenaufruf selbst keine Berechnung veranlassen, sondern er soll das Einladen der Applikation veranlassen. Die Berechnung selbst soll in einem separatem Thread ablaufen. Evtl habe ich dich auch falsch verstanden.

Oder ich hab dich falsch verstanden ^^
naja du könntest es ja dann um die nachtzeit halt mitn cron machen. einmal pro stunde prüfen, obs noch läuft, sonst neustarten. für die Tageszeit wirds ja nicht notwendig sein.
gepostet vor 17 Jahre, 11 Monate von None
Zum Thema SharedMemory... gab es da nicht was in C ?
Ok... Insider
gepostet vor 17 Jahre, 11 Monate von exe
Ich würde auch dringend empfehlen die Hintergrundprozesse nicht in dem Server laufen zu lassen. Nämlich genau aus dem Grund, dass du die Kontrolle über die Laufzeit verlierst. Wenn die Anwendung bei dir als Webapp im IIS läuft bleibt dir dabei wohl nichts anderes übrig als einen eigenen Daemon zu schreiben.
Ich habs bei mir so gelöst, dass der Webserver als Dienst in der Gameengine läuft, nicht umgekehrt. Dadurch kann ich nach Gutdünken zusätzliche Dienste wie Eventhandler laufen lassen. Aber das setzt natürlich vorraus, dass der Webserver in deiner Anwendung enthalten ist, nicht das umgekehrte Prinzip
gepostet vor 17 Jahre, 11 Monate von None
Was mich ein bissle Wundert... TheUndeadable hat die Möglichkeit einen eigenen Webserver zu verwenden den er Programmiert hat.
Wieso dem IIS was aufdrücken, wofür er nicht gedacht ist?
gepostet vor 17 Jahre, 11 Monate von Fornax
Den Burning Webserver will er erst für sein nächstes Projekt benutzen, ich denke wenn er den für sein aktuelles Jungfrauenspiel einsetzt muss er einiges am Code verändern.
gepostet vor 17 Jahre, 11 Monate von TheUndeadable
Es geht um das nächste Spiel.
Das Jungfrauenspiel ist solide und vom technischen Standpunkt her fertig. Es sind nur noch optische Korrekturen zu machen und das Hintergrundskript bleibt als separater Prozess bestehen.
Warum nicht meinen eigenen Webserver?
Der IIS ist ein zuverlässiger und sehr schneller Webserver. Ob ich diese Geschwindigkeit auch erreiche, weiß ich nicht, aber zumindest werde ich nicht die Komfortabilität von ASP.Net erreichen. In den letzten Tagen habe ich ein paar neue Technologien kennen gelernt (Authorisierung, Authentifizierung, Gruppen, Rollen, Themes, Skins) und ich muss sagen: Bis ich die so nachprogrammiert habe, dass sie so komfortabel wie ASP.Net zu nutzen sind, ist Weihnachten.
Aber ich werde mir auf jeden Fall mal Gedanken machen, ob es nicht sinnvoller ist meinen eigenen Webserver zu nutzen. Ein weiterer Vorteil wäre, dass man vom IIS unabhängig ist, wobei der Preis für diesen relativ moderat ist (Windows 2003 Web Edition).
Dies ist halt eine grundlegende Konzeptfrage. Daher möchte ich erstmal evaluieren, ob es die sinnvolle Möglichkeit gibt dem IIS einen Hintergrundthread einzubauen. Nicht umsonst ist er ein Applikationsserver. Aber dazu werde ich wahrscheinlich einen IIS-MVP befragen.
gepostet vor 17 Jahre, 11 Monate von Agmemon
Gibt es irgendwo eine kurze Beschreibung, wie die Architektur des IIS funktioniert? Mit kurz meine ich, dass ich mir jetzt nicht das Handbuch reinziehen will. Ich verstehe zwar das Problem als solches, tue mich aber schwer, das Problem auf Lösungen in anderen Architekturen zu übertragen. Es hließt sich nämlcih so, als würde das Spiel in einem einzigen Prozess laufen, der immer wieder neu gestartet wird. Und das ist irgendwie seltsam.
gepostet vor 17 Jahre, 11 Monate von TheUndeadable
Puuuh,
eine kurze Beschreibung des IIS.
Ich versuche es mal:
Ein Teil des IIS läuft als Kernelmodul und fängt alle HTTP-Requests ab. Über einen Dispatcher werden diese Requests an die einzelnen Arbeitsprozesse auf User-Ebene weitergegeben.
Damit können mehrere Prozesse als Http-Server dienen (Windows Communication Foundation nutzt dies, da jede Anwendung als Webservice dienen kann). Die Anwendungen registrieren sich beim Start bei diesem Kernelmodul und forden zum Beispiel alle Requests mit dem Host ABC.de auf dem Port 80 und dem 'Ordner' /application an.
Jetzt kommt das ASP.Net-Modul. Für den Anfang sei gesagt, dass jede ASP.Net-Anwendung als aspnetwp.exe (Worker Process) auf Dienste-Ebene (Ring 3) arbeitet. Diese registriert sich genauso wie obige Applikationen bei dem Kernel-Modul.
Dem IIS sag ich: Der Ordner /Game ist eine ASP.Net-Anwendung und soll gestartet werden. Über die web.config (entspricht der .htaccess und anderen .ht-Dateien) wird die ASP.Net-Anwendung konfiguriert. Beim Start dieser wird die globale Funktion 'Application_Start' aufgerufen. Wird der Prozess beendet, so wird die globale Funktion 'Application_End' aufgerufen. Das gleiche bei Session_Start und Session_End.
Da .Net-Anwendungen in einer 'sicheren' Umgebung laufen und sich nicht gegenseitig beeinflussen können, auch wenn sie im gleichen Prozess laufen, werden mehrere ASP.Net-Anwendungen in einem WP gestartet. Mann kann auch sagen, dass die ASP.Net-Anwendung im Haupt-IIS-Prozess (Ring 3) oder zwangsweise als separater Prozess gestartet werden soll.
Da arbeitende Prozesse mit langer Laufzeit an Performance verlieren können (Speicherlöcher, Fragmentierung des Speichers), startet der IIS als kontrollierende Instanz nach einem bestimmten Zeitraum diese Applikation neu (Application_End, Application_Start). Das gleiche gilt auch, wenn eine Anwendung über einen längeren Zeitraum nicht angesprochen wurde. Damit lässt sich Arbeitsspeicher sparen. Dies lässt sich aber deaktivieren.
Die Anwendung wird erst beim ersten Aufruf der Website eingeladen. Dies geht recht flott.
Ich versuche ein paar MSDN-Artikel zu finden und reiche sie dann nach.
EDIT:
Habe eine Kurzbeschreibung gefunden:
www.microsoft.com/germany/technet/datenbank/articles/600117.mspx
gepostet vor 17 Jahre, 11 Monate von None
Gut... dann gehen wir mal von anderer Seite an das Problem ran.
Du sagst du hättest gerne Zugriff auf die Daten im Daemon. Wieso schreibst du nicht einen Daemon, der für das Speicherhandling zuständig ist und greifst dann darauf zu?
Ok... Overhead ahoi, aber...
* Du hast eine Zentrale Datenhaltung
* Du kannst die geplante Minidatenbanklösung dort integrieren
* Du kannst das ganze z.B. auf einer anderen CPU laufen lassen
* ... fill in your ideas
gepostet vor 17 Jahre, 11 Monate von None
Im Prinzip brauchst du wie bisher ein get/set, welches über Sockets o.ä. angesprochen werden muß.
Ich meine mich zu erinnern das es unter C die Möglichkeit gab, SharedMemory mittels Semaphoren und Mutex zu verwenden.
gepostet vor 17 Jahre, 11 Monate von TheUndeadable
> Im Prinzip brauchst du wie bisher ein get/set, welches über Sockets o.ä. angesprochen werden muß.
Unter .Net gibt es fortschrittlichere Technologien als ein get/set über Sockets. Diese heißt Remoting.
Server-Seite:
TollesObjekt oObjekt = new TollesObjekt();
RemotingHelper.MacheÖffentlich ("/tollesObjekt" );
ClientSeite:
TollesObjekt oObjekt = RemotingHelper.HoleÖffentlich ( "/tollesObjekt" );
Player [] = oObjekt.GetPlayers();
Daher wäre dies weniger das Problem.
gepostet vor 17 Jahre, 11 Monate von schokofreak
TuD: Am besten erzähle ich dir mal, wie ich unter ASP gearbeitet habe... denke es sollte sich unter ASP.Net noch analog abbilden lassen.
Der erste User / Im application Start. Wird dein Hintergrundthread gestartet. Sprich diesesr Thread wird über sehr lange Zeit aktiv sein.
Dort drin erstellst du die Persistenz-Objekte usw. Lässt das ganze so lange leben, bis 1, 2 Minuten lang kein Request mehr ankommt.
Danach wird auch dieser Request terminiert / gibt dem Server zeit zur Ruhe und für interne Aufgaben.
Dummerweise heist das aber, dass der 1. Request des 1. Users sehr lange dauert ... ladebalken, den wir nciht wollen.
Deshalb: Der erste Userrequest beginnt damit, dass du MANUELL (nicht über builtin Funktionalität) einen Redirect auslöst. Dieser wird ausgeführt, befor die Seite komplett geladen wurde. Sprich der Thread läuft noch, der user ist mit Garantie entkoppelt.
Natürlich ists aus diversen Überlegungen interessanter, das ganze auf eine statische Seite zu redirecten... beispielsweise eine Login-Page wo man Username / Passswort eingibt. Oder einfach auf ein "Server ist am Aufstarten, sie werden in 5 Sekunden weitergeleitet"
Danach kannst du zur Kommunikation mit was uach immer arbeiten, wieso nicht mit remoting?
Wenn ich mich noch recht erinnere, gibt der IIS dem Thread sogar ein signal, dass er herunterfahren möchte... sprich du kannst das behandeln und ein überlanges Verweigern des Herunterfahrens (da 24/7 User) verhindern. Und ansonsten ist es auch nciht schwer, alle User um 3Uhr Morgens für 1 Minute auszusperren udn Threads neu zu starten. Respektive wenn der IIS die Threads einfach terminiert.
Gruss
Christian
gepostet vor 17 Jahre, 11 Monate von TheUndeadable
> Der erste User / Im application Start. Wird dein Hintergrundthread gestartet. Sprich diesesr Thread wird über sehr lange Zeit aktiv sein.
Ja, das war mein erster Gedanke.
> Wenn ich mich noch recht erinnere, gibt der IIS dem Thread sogar ein signal, dass er herunterfahren möchte
Ja, das Application_End.
> Dieser wird ausgeführt, befor die Seite komplett geladen wurde. Sprich der Thread läuft noch, der user ist mit Garantie entkoppelt.
Das wäre auch kein Problem, da Application_Start unabhängig vom eigentlichen Request gestartet wird und der Hintergrund-Thread unabhängig von diesem starten kann. Dies scheint ein Vorteil von ASP.Net gegenüber dem alten ASP zu sein.
Ich denke, dass ich eine duale Lösung fahren werde. Einmal starte ich den Hintergrund-Thread im IIS und öffne ihn für Remoting und einmal baue ich eine Lösung, dass ein Dienst-Prozess läuft und er öffnet sich für Remoting. Von der 'Client-Seite' greife ich dann immer per Remoting auf das Datenhalte-Objekte zu. .Net entscheidet selbst, ob dies In-Prozess geschehen kann oder ob das über ein Socket läuft. Dies werde ich dann konfigurabel gestalten (ob IIS oder ob als eigener Dienstprozess).
> Lässt das ganze so lange leben, bis 1, 2 Minuten lang kein Request mehr ankommt.
Remoting-Objekte kann man so gestalten, dass sie eine gewisse Lebenszeit haben. Wird danach nochmals drauf zugegriffen, so wird es wiedererstellt.
> Danach kannst du zur Kommunikation mit was uach immer arbeiten, wieso nicht mit remoting?
Ja, ich denke dass Remoting zwar nicht der einfachste, aber der flexibelste Weg ist.
Danke auch nochmal an MrMarco, der mich indirekt auf die Idee mit dem Remoting gebracht hatte.
@schokofreak:
Wie ist denn deine Erfahrung mit Hintergrundthreads im IIS? Kann er gut damit umgehen oder sind irgendwelche Probleme aufgetreten?
gepostet vor 17 Jahre, 11 Monate von TheUndeadable
Nach längerem Hin und Her habe ich mich für die Out-Of-Process-Lösung und der Verbindung von IIS über das Remoting entschieden.
Dabei läuft auf Dienste-Ebene ein Prozess, der den eigentlichen Spielkern per Remoting zur Verfügung stellt.
Der IIS verbindet sich beim Start mit diesem Spielkern und stellt diesen Spielkern zur Verfügung. Die eigentlichen Web-Applikation nutzt nun diesen Spielkern und kann nun mit diesem arbeiten, als wäre er direkt im Prozess.
Diese Lösung ist unabhängig vom IIS und sollte theoretisch auch unter Mono laufen. So habe ich nun eine Microsoft-Abhängigkeit reduziert und kann nun im Falle eines Falles den Dienst auch über den Apache oder gar über Java ansprechen (Remoting kann auch über standardisierte Protokolle funktionieren.)

Auf diese Diskussion antworten