Wir haben es mit einem interessanten Problem bei StackOverflow zu tun.
Wir haben eine ganze Reihe kleiner Aufgaben, die bald erledigt werden müssen. Ein Beispiel ist das Aktualisieren von Listen mit verwandten Fragen. In der Vergangenheit haben wir diese Aufgaben auf die Seitenladevorgänge einiger Benutzer übertragen.
Das war nie ideal, aber es war nicht wirklich auffällig. Jetzt, da SO das 1.000.000-Fragezeichen überschritten hat, spüren es die unglücklichen Benutzer.
Die natürliche Lösung besteht darin, diese Aufgaben tatsächlich in den Hintergrund zu rücken. Ich habe zwei Möglichkeiten, dies zu tun.
1. In IIS als benutzerdefinierter Thread-Pool / Work-Queue
Grundsätzlich drehen wir einige Threads (nicht ThreadPool , um IIS nicht zu beeinträchtigen) und lassen sie einige Sammlungen bedienen, in die wir Funcs schieben .
Der große Vorteil hier ist die Einfachheit. Wir müssen uns nicht darum kümmern, etwas zu organisieren, und wir müssen auch nicht sicherstellen, dass ein externer Dienst verfügbar ist und reagiert.
Wir erhalten auch Zugriff auf alle unsere gemeinsamen Codes.
Der Nachteil ist, dass wir keine Hintergrund-Threads verwenden sollten. Die Einwände, die ich kenne, beziehen sich alle auf das Verhungern von IIS (wenn Sie ThreadPool verwenden) und auf das zufällige Absterben der Threads (aufgrund des AppPool-Recyclings).
Wir haben eine vorhandene Infrastruktur, um den zufälligen Thread-Tod zu einem Nicht-Problem zu machen (es ist im Grunde genommen möglich, einen abgebrochenen Task zu erkennen), und die Anzahl der Threads zu begrenzen (und Threads zu verwenden, die keine ThreadPool-Threads sind) ist ebenfalls nicht schwierig.
In StackOverflow verschoben , da es hier nicht wirklich angesprochen wurde.
2. Als Dienstleistung
Entweder eine Lösung von Drittanbietern oder eine benutzerdefinierte.
Grundsätzlich würden wir eine Aufgabe über die Prozessgrenzen hinweg auf einen Dienst verlagern und dies einfach vergessen. Vermutlich verknüpfen wir Code oder beschränken uns auf unformatiertes SQL + eine Verbindungszeichenfolge.
Der Profi ist, dass es der "richtige Weg" ist, dies zu tun.
Die Nachteile sind, dass wir entweder sehr eingeschränkte Möglichkeiten haben oder ein System ausarbeiten müssen, um diesen Service mit unserer Codebasis synchron zu halten. Wir müssen auch alle unsere Überwachungs- und Fehlerprotokollierungen irgendwie einbinden, die wir mit der Option "In IIS" kostenlos erhalten.
Gibt es weitere Vorteile oder Probleme mit dem Serviceansatz?
Kurz gesagt, gibt es unvorhergesehene und unüberwindbare Probleme, die Ansatz 1 unbrauchbar machen, und wenn ja, gibt es gute Dienste von Drittanbietern, die wir nach Ansatz 2 suchen sollten?
quelle
Antworten:
Vor ein paar Wochen habe ich eine ähnliche Frage zu SO gestellt. Kurz gesagt, besteht mein Ansatz seit einiger Zeit darin, einen Windows-Dienst zu entwickeln. Ich würde NServiceBus (im Wesentlichen MSMQ unter dem Deckmantel) verwenden, um Anforderungen von meiner Web-App an meinen Dienst zu senden. Früher habe ich WCF verwendet, aber eine verteilte Transaktion über WCF richtig funktionieren zu lassen, schien mir immer ein Nervenkitzel zu sein. NServiceBus hat den Trick gemacht, ich konnte Daten festschreiben und Aufgaben in einer Transaktion erstellen und mir keine Sorgen machen, ob mein Dienst zu diesem Zeitpunkt aktiv war. Als einfaches Beispiel: Wenn ich jemals eine E-Mail senden müsste (zum Beispiel eine Registrierungs-E-Mail), würde ich das Benutzerkonto erstellen und in einer Transaktion ein Signal an meinen Windows-Dienst auslösen (um die E-Mail zu senden). Der Message-Handler auf der Serviceseite würde die Nachricht abholen und entsprechend verarbeiten.
Seit der Veröffentlichung von ASP .NET 4.0 und AppFabric gibt es eine Reihe praktikabler Alternativen zu dem oben genannten Mechanismus. Unter Bezugnahme auf die oben erwähnte Frage haben wir jetzt AppFabric's AppInitialize (via net.pipe) sowie die Auto-Start-Funktion von ASP .NET 4.0, die die Entwicklung von Windows-Diensten als Web-Apps zu einer praktikablen Alternative macht. Ich habe jetzt aus mehreren Gründen damit begonnen (der größte Grund ist, dass der Einsatz nicht mehr nervt):
Wenn Sie diesen Weg gehen (verzeihen Sie mir das Kopieren und Einfügen von meinem ursprünglichen Beitrag), würde ich auf jeden Fall in Betracht ziehen, die Hintergrundlogik in einer separaten Webanwendung auszuführen. Dafür gibt es mehrere Gründe:
Dadurch kehren wir zum Marshalling-Aspekt zurück. WCF, NServiceBus / RabbitMQ / ActiveMQ usw., Vanille MSMQ, RESTful API (Think MVC) sind alle Optionen. Wenn Sie Windows Workflow 4.0 verwenden, können Sie einen Hostendpunkt bereitstellen, den Ihre Webanwendung verwenden kann.
Der Webhosting-Ansatz für Services ist für mich noch ziemlich neu, nur die Zeit wird zeigen, ob es die richtige Wahl war. Soweit so gut. Übrigens, wenn Sie AppFabric nicht verwenden möchten (ich konnte es aus irgendeinem bizarren Grund nicht, weil Windows Server Web Edition nicht unterstützt wird), funktioniert die im Beitrag des Gu erwähnte Autostart-Funktion einwandfrei. Halten Sie sich jedoch von der Datei applicationhost.config fern. Alles in diesem Beitrag kann über die IIS-Konsole (Konfigurationseditor auf der Hauptserverebene) eingerichtet werden.
Hinweis: Ich hatte ursprünglich ein paar weitere Links in dieser Nachricht gepostet, aber leider ist dies mein erster Beitrag zu diesem Austausch und es wird nur ein Link unterstützt! Grundsätzlich gab es zwei andere, um ihnen Google "Tod an Windows-Dienste ... Es lebe AppFabric!" und "Auto-Start-Asp-Net-Anwendungen". Das tut mir leid.
quelle
Tatsächlich gibt es in Windows eine dritte Möglichkeit, Hintergrunddienste auszuführen, und diese ist in der UNIX-Welt weit verbreitet. Der dritte Weg ist ein
CRON
Job, der einen Teil Ihrer Infrastruktur betreibt. In Windows ist dies als das bekannttask scheduler
und wird häufig für die geplante Ausführung von Code verwendet. Um dies zu verwenden, erstellen Sie eine Befehlszeilen-App, die nach einem vordefinierten Zeitplan ausgeführt wird. Dies hat den Vorteil, dass Sie sich keine Sorgen machen müssen, wenn der Prozess wie ein Dienst in Betrieb bleibt. Wenn er aus irgendeinem Grund fehlschlägt, wird er nur beim nächsten Mal gestartet.Für das Marshalling bestimmter Tasks müssen Sie diese Tasks nur in einem permanenten Binärspeicher speichern. Bis die Befehlszeilen-App sie aus dem Speicher auswählt und ausführt. Ich habe dies in der Vergangenheit getan, indem ich die Cassandra-Datenbank als Sitzungszustandsanbieter verwendet habe, um Hintergrundaufgaben für bestimmte Benutzer in der Cassandra-Datenbank zu erledigen und sie dann von der Befehlszeile auswählen und für den Benutzer ausführen zu lassen.
Dies war vielleicht nicht die typische Marshalling-Lösung, aber für mich hat es sehr gut funktioniert, und es hat sich als sehr elegante Lösung herausgestellt, da die geplanten Aufgaben Herunterfahren, Netzwerkprobleme überstanden haben und jeder Computer die Aufgabe ausführen konnte, da sie zentral war gelagert.
Schamlose Werbung, aber das ist mein Projekt und die Lösung, die ich kurz beschrieben habe, ist, warum ich das Projekt erstellt habe: http://github.com/managedfusion/fluentcassandra/
quelle
Cron + Web App
Dies ist ein kampferprobtes Design, das sich horizontal mit Ihrer Webfarm skalieren lässt und sicherstellt, dass Sie den Web-Technologie-Stack verwenden, den Sie bereits kennen.
So funktioniert das:
http://mydomain.com/system/cron
.Hurra! Jetzt haben Sie eine Route, die alle 30 Sekunden aufgerufen wird. Und wenn die Verarbeitung der Anfrage 5 Minuten dauert, ist dies für niemanden von Belang, da sie nicht Teil der Seitenanfrage eines Benutzers ist.
Die
cron
Aktion sieht sehr einfach aus: Er hat eine Liste von Methoden, die auf einer bestimmten Frequenz ausgeführt werden können. Wenn eine Anforderung eingeht, sieht er, ob eine Methode ausgeführt werden muss, und ruft die entsprechende Methode auf. Dies bedeutet, dass Sie den Zeitplan in Ihrer Datenbank steuern können , in der Sie wahrscheinlich bereits viele andere wichtige Konfigurationsdaten für Ihre Site haben.Wichtiger noch (für Sie) ist, dass Ihre Jobs nicht nach einem festen Zeitplan abgerufen werden müssen. Sie können eine beliebige Logik schreiben, um zu bestimmen, wann eine Methode ausgeführt werden soll.
Vor-und Nachteile
VorteileHinweis: Wenn Sie Fragen oder Bedenken haben, fügen Sie bitte einen Kommentar hinzu . Ich bin glücklich, näher darauf einzugehen.
quelle
Ich habe in meiner aktuellen Anwendung so gut wie jede Möglichkeit ausprobiert und genutzt. Ich habe damit begonnen, dasselbe zu tun, was Sie derzeit tun, nämlich eine Benutzeranforderung zu bearbeiten, um die Daten zu füllen, und sie dann für die Zukunft zwischenzuspeichern. Ich erkannte, dass dies auch eine schlechte Idee war (vor allem, da Sie auf mehrere Webserver skalieren, nehmen mehr Benutzer den Treffer).
Ich hatte auch einen geplanten Auftrag, bei dem eine URL in der ASP.NET-App aufgerufen wurde. Dies ist eine anständige Lösung, die jedoch ab dem Zeitpunkt, zu dem Sie einen Webserver überschritten haben, eine Panne aufweist.
Gegenwärtig verwende ich zwei verschiedene Methoden, beide mit Quartz.NET, einer großartigen kleinen Bibliothek. Das erste ist Quartz.NET, das mit ASP.NET in-process ausgeführt wird, das in global.asax eingerichtet wird und alle paar Minuten ausgeführt wird. Ich verwende dies, um den ASP.NET-Cache außerhalb des Bandes zu aktualisieren, was der einzige Grund ist, warum er als Teil von ASP.NET ausgeführt wird.
Das zweite ist, dass ich eine Bibliothek namens DaemonMaster geschrieben habe, um Quartz.NET zu verpacken - es macht es einfach, eine DLL in ein Verzeichnis abzulegen und in einem Windows-Dienst ausführen zu lassen. Ich fand, dass es hilft, einige der lästigen Teile der Arbeit mit einem Windows-Dienst zu vermeiden und auch die Quartz.NET-API zu bereinigen. Die Dienste, die über DaemonMaster ausgeführt werden, unterscheiden sich in zwei Varianten. Bei der ersten handelt es sich um Jobs, die jede Nacht oder alle X Minuten ausgeführt werden müssen. Die anderen Jobs arbeiten in einer Warteschlange basierend auf Daten, die von der ASP.NET-Anwendung eingehen. Die ASP.NET-App löscht JSON-Objekte in RabbitMQ, und die Dienste rufen RabbitMQ ab und verarbeiten die Daten.
Auf dieser Grundlage würde ich vorschlagen, dass Sie einen Windows-Dienst verwenden (und DaemonMaster ausprobieren) und bei Bedarf eine Warteschlange wie RabbitMQ verwenden, um die Daten von der ASP.NET-App an die Dienste zu übergeben - es hat das Beste aus all diesen Lösungen herausgeholt . Wenn Sie den Cache laden, ist die Ausführung in ASP.NET sinnvoll, ansonsten glaube ich nicht.
quelle
Ich würde es richtig machen und einen Windows-Dienst ausführen lassen, der eine "Warteschlange" überwacht. Ich sage "Warteschlange", weil das Programmieren mit MSMQ mit dem Einstecken heißer Poker in Ihre Augäpfel vergleichbar ist.
Ich habe mich in die Einfachheit von Delayed :: Job in Rails verliebt , und etwas Ähnliches ist in .NET problemlos möglich.
Grundsätzlich fügen Sie jede Art von
SomethingOperation
(etwas, das einePerform()
Methode hat). Serialisieren Sie dann einfach die relevanten Parameter, geben Sie ihr eine Priorität, eine Art Standardwiederholungsverhalten und speichern Sie sie in einer Datenbank.Ihr Dienst überwacht dies nur und bearbeitet die Aufträge in der Warteschlange.
quelle
Wir waren ziemlich zufrieden mit einem Service Bus / Message Queue / Service-Ansatz. Die Grundarchitektur ist dies.
Die Website sendet eine Nachricht an die Warteschlange
Der Windows-Dienst empfängt und verarbeitet Nachrichten in seiner eigenen Zeit
Der Vorteil ist, dass der Front-End-Service, mit dem auch Benutzer verbunden sind, keine Verzögerung erfährt. Der Windows-Dienst kann heruntergefahren und aktualisiert werden, ohne dass die Hauptwebsite unterbrochen wird. Außerdem ist es extrem schnell .
Wenn Sie nicht alle Ihre Daten in der Nachricht speichern können, können Sie diese jederzeit speichern und später abrufen. Ich schlage vor, einen Dokumentenspeichermechanismus wie RavenDB oder MongoDB zu verwenden, bei dem es sehr einfach ist, Ihre Klassen ohne Änderungen zu speichern.
Die Website sendet eine Nachricht an die Warteschlange
Der Windows-Dienst empfängt und verarbeitet Nachrichten in seiner eigenen Zeit
Zur Vereinfachung verwenden wir: Rhino ESB und Topshelf . Die Konfiguration ist äußerst einfach und die Implementierung in eine vorhandene Anwendung hat sich als sehr zeitsparend erwiesen.
quelle
Ich bin gespannt, warum eine Kombination aus beidem nicht in Frage kommt. Im Moment lösen Sie Jobs bei Seitenaufrufen aus, und einige Pechvögel bleiben stecken und warten 10 Sekunden, bis die Seite angezeigt wird. Zumindest verstehe ich Ihre derzeitige Methode so.
Es dauert jedoch immer länger, bis diese Jobs ausgeführt werden, wenn die Site wächst, und Sie möchten die Benutzererfahrung auf der Site nicht beeinträchtigen. Nicht einmal für ein paar (oder vielleicht viele) unglückliche Benutzer im Laufe des Tages. Jetzt überlegen Sie, Jobs im Hintergrund zu planen.
Ich verstehe nicht, warum ein Hintergrundjob, der in regelmäßigen Abständen ausgeführt wird, keinen Besucher nachahmen kann. Jetzt bin ich kein Windows-Programmierer, aber in der Linux-Welt habe ich einen Cron-Job eingerichtet, der in regelmäßigen Abständen ausgeführt wird und 2 Codezeilen enthält.
Es vereint die Vorteile beider Systeme. Es ist im Hintergrund gemacht. Es wirkt sich nicht auf Benutzer aus. Es wird weiterhin eine Seitenansicht verwendet, um den Job zu starten. Ich habe diesen Ansatz schon einmal gesehen. Es ist in der Regel der Mittelweg zwischen den einfachen Wegen der Vergangenheit und den komplexeren Wegen, die die Straße hinunter kommen.
Aktualisieren
Ich denke, Sie können das Problem des Lastenausgleichs umgehen, indem Sie die Job-Läufer auf den Webservern selbst ausführen. Der Job-Runner zieht eine URL aus der Job-Warteschlange und führt sie folgendermaßen aus:
Aufgrund der Art der Job- / Messaging-Warteschlangen werden die Jobs gleichmäßig auf die Job-Läufer verteilt, was bedeutet, dass die speziell gestaltete URL möglicherweise auf Ihre Webserver verteilt wird.
quelle
specially_crafted_url
von einer bekannten IP stammt, können Sie in Ihrem Load Balancer eine Regel hinzufügen, die Round-Robin-Vorgänge nur für Anforderungen von dieser IP ausführt.Ich denke, der Nachteil des reinen Service-Ansatzes ist, dass Sie Code in den Service und nicht in die Kern-App verstreut haben.
Folgendes haben wir mit umfangreichen nicht zeitkritischen Hintergrundjobs gemacht, die den Code zusammenhalten und den Service vereinfachen:
Noch einfacher ist es, den Anruf in einer Konsolen-App zu tätigen und ihn mit dem Taskplaner oder VisualCron in einen "Dienst" zu verwandeln.
quelle
Ich mochte TopShelf. Beibehaltung der Einfachheit und ordnungsgemäße Ausführung als Windows-Dienst. Erstellen Sie im Allgemeinen eine Konsolen-App, fügen Sie etwa 15 bis 20 Codezeilen hinzu, und installieren Sie sie dann als Dienst.
http://code.google.com/p/topshelf/
quelle
Wie wäre es mit einem sehr einfachen Windows-Dienst, der auf dem Webserver ausgeführt wird und regelmäßig eine Wartungs-URL aufruft, die Ihre verschiedenen Aufgaben erledigt. Lassen Sie es drosseln, wie viel Arbeit es in einer bestimmten Anfrage erledigt.
quelle
Ich werde mich hier gegen den offensichtlichen Trend wenden und vorschlagen, das In-IIS-Modell zu wählen. Ich habe es selbst benutzt und es funktioniert wirklich gut. Es ist wirklich nicht so schwer, eine anständige Thread-Pool-Klasse zu implementieren (im Laufe der Jahre habe ich meine Thread-Pool-Klasse erweitert, um die dynamische Erstellung und Zerstörung von Threads, das Wiederholen von Jobs usw. zu unterstützen). Vorteile sind:
Meiner Meinung nach ist eine In-IIS-Lösung einfach der "nächste Schritt" vom Huckepack auf zufällige Seitenaufrufe.
quelle
Resque ist nett. Oder sogar Kthxbye, wenn Sie über den resultierenden Wert benachrichtigt werden müssen, sobald dieser abgeschlossen ist.
Beide Redis / Ruby basierten tho.
Um ehrlich zu sein, wenn Sie einen service-basierten Ansatz verfolgen, muss dieser nicht unbedingt in Ihre aktuelle Plattform integriert werden, was ich für ein Plus halte. Ich hoffe, es könnte ein Set-and-Forget-System sein, das (mit irgendeiner Art von Überwachung) läuft und Aufträge erledigt. Ich bin nicht sicher, ob es überhaupt auf der gleichen Plattform ausgeführt werden muss, da es nur die Datenbankinformationen aktualisiert / ändert.
Ich bin mir ziemlich sicher, dass Sie mit viel mehr für viel weniger davonkommen könnten, wenn Sie diese Art von Arbeit in einer separaten Entität bewirtschaften würden, zumal es den Anschein hat, als würden Sie sich mit Threading-Problemen befassen. Sowohl Resque als auch Kthxbye verschieben die Verarbeitung in separate Prozesse, damit das Betriebssystem die Parallelität verarbeiten kann.
Resque
Kthxbye
quelle
Ich würde einen von WAS gehosteten WCF-Dienst verwenden, der eine MSMQ-Warteschlange abhört.
Profis
Einfachnachrichten aus der Web-App abfeuern und vergessen
MSMQ / WCF-Drosselung und -wiederholung
Garantierte Lieferung; D
Dead Letter Management
Verteilte Verarbeitung
WAS / MSMQ-Aktivierung
Con's
Die MSMQ-Funktionen in WCF machen die Verwendung von MSMQ sehr angenehm. Ja, Sie werden an der Konfiguration scheitern, aber der Nutzen wird das Opfer überwiegen.
quelle
Ich bin ein paar Mal darauf gestoßen, als ich Webanwendungen entwickelte. Wir haben es gelöst, indem wir eine Windows-Konsolenanwendung erstellt haben, die die Aufgabe ausführt, und eine geplante Aufgabe erstellt, die von Zeit zu Zeit ausgeführt wird, um die Aufgabe tatsächlich auszuführen.
quelle
Sie können die Arbeit an einem Hintergrundthread (oder an vielen Hintergrundthreads) mit Rx und so etwas wie dem Folgenden weiterleiten:
Benutzen:
Hosten Sie all das in einer Klasse, von der es nur eine gibt (auch bekannt als Singleton, aber tun Sie es richtig - verwenden Sie Ihren IoC-Container, um den Lebensstil zu bestimmen).
Sie können die Größe des Thread-Pools usw. steuern, indem Sie einen benutzerdefinierten Scheduler schreiben, anstatt den EventLoopScheduler (der einen einzelnen Thread ausführt) zu verwenden.
quelle
Ich habe diese Art von Dingen einige Male implementiert. Unter Windows habe ich ein Python-Befehlszeilenprogramm eingerichtet, das zu verschiedenen Zeiten etwas ausführt. Dieses Programm macht auch eine xmlrpc-Schnittstelle an einem Port verfügbar. Anschließend wird jede Minute ein Job mit geplanten Tasks ausgeführt und die xmlrpc-Schnittstellen abgefragt. Wenn sie nicht aktiv sind, wird versucht, sie zu starten. Wenn nicht, schickt es mir eine E-Mail.
Der Vorteil ist, dass der ausgeführte Job nicht an Cron oder Zeitplan gebunden ist. Ich habe einen Prozessjob, der alle Sekunden ausgeführt wird, aber zwischen dem Starten eines neuen Jobs wird immer länger gewartet, je nachdem, ob Arbeit zu erledigen war. Außerdem kann es verwendet werden, um basierend auf dem Ergebnis intelligent zu handeln. Hast du einen 500er Fehler? Hast du eine wirklich lange Verspätung? Mach etwas anderes. Benachrichtigen Sie einen anderen Dienst. Usw.
Und dasselbe System funktioniert unter Unix mit geringfügigen Änderungen.
quelle
Ich habe selbst keine Antwort für Sie, aber das Problem hat geklingelt - ich erinnere mich, dass einige zufällige Typen es einmal in einem Podcast besprochen haben .
quelle
Task Queue Java API Übersicht
Aufgabenkonzepte
In der App Engine-Hintergrundverarbeitung ist eine Aufgabe eine vollständige Beschreibung einer kleinen Arbeitseinheit. Diese Beschreibung besteht aus zwei Teilen:
Aufgaben als Offline-Web-Hooks
Glücklicherweise bietet das Internet bereits eine solche Lösung in Form einer HTTP-Anfrage und ihrer Antwort. Die Datennutzdaten sind der Inhalt der HTTP-Anforderung, z. B. Webformularvariablen, XML, JSON oder codierte Binärdaten. Die Code-Referenz ist die URL selbst; Der eigentliche Code ist die Logik, die der Server bei der Vorbereitung der Antwort ausführt.
quelle
Tue beides
Fügen Sie dem Fragenpfad einen optionalen Parameter hinzu, der die Arbeit erledigt, die Sie derzeit auf Benutzeranforderungen huckepack tragen:
Hintergrundaufgaben auf einer großen Site ausführen
Erstellen Sie eine Konsolenanwendung, die auf jedem Server ausgeführt wird und die gemeinsam genutzte IIS-Protokollbinärdatei öffnet und bis zum aktuellen Ende der Datei liest. Verwenden Sie einen Dateisystemwatcher oder ein Zeitintervall, um vorwärts zu lesen und Updates zu sammeln, während IIS das Protokoll löschte.
Verwenden Sie diese Informationen, um festzustellen, welche Seiten gerade angezeigt wurden.
Verwenden Sie die Seiten-URLs aus dem analysierten Protokoll, um die "extrastuff" -Version der URL auf localhost mit einem Webclient-Objekt aufzurufen.
Fügen Sie Code hinzu, um die Dateien am Ende jedes Protokollzeitraums zu wechseln, oder starten Sie den Prozess in jedem Protokollzeitraum neu.
quelle