Ich habe einen "analytics dashboard" -Bildschirm, der für meine django-Web-Anwendungen-Benutzer sichtbar ist und dessen Berechnung sehr lange dauert. Es ist einer dieser Bildschirme, der jede einzelne Transaktion in der Datenbank für einen Benutzer durchläuft und ihnen Messwerte gibt.
Ich würde mir wünschen, dass dies eine Echtzeitoperation ist, aber die Berechnungszeiten können 20-30 Sekunden für einen aktiven Benutzer betragen (kein Paging erlaubt, sondern Durchschnittswerte für Transaktionen).
Die Lösung, die Ihnen in den Sinn kommt, ist, dies im Backend über einen Batch-Befehl manage.py zu berechnen und dann nur die zwischengespeicherten Werte für den Benutzer anzuzeigen. Gibt es ein Django-Entwurfsmuster, das diese Arten von Modellen / Displays erleichtern soll?
Was Sie suchen, ist eine Kombination aus Offline-Verarbeitung und Caching. Mit Offline meine ich, dass die Berechnungslogik außerhalb des Anfrage-Antwort-Zyklus stattfindet. Mit Caching meine ich, dass das Ergebnis Ihrer teuren Berechnung für X-Zeit ausreichend gültig ist, während der Sie es für die Anzeige nicht neu berechnen müssen. Dies ist ein sehr häufiges Muster.
Es gibt zwei weitverbreitete Arbeitsansätze, die außerhalb des Anfrage-Antwort-Zyklus stattfinden müssen:
Relativ gesehen ist Cron einfacher zu installieren und Sellerie ist leistungsfähiger / flexibler. Davon abgesehen genießt Sellery eine fantastische Dokumentation und eine umfassende Testsuite. Ich habe es in der Produktion für fast jedes Projekt verwendet, und obwohl es einige Anforderungen beinhaltet, ist es nicht wirklich ein Problem, es einzurichten.
Cron-Jobs sind die altehrwürdige Methode. Wenn Sie nur eine Logik ausführen und ein Ergebnis in der Datenbank speichern müssen, hat ein Cron-Job keine Abhängigkeiten. Die einzigen frechen Bits mit Cron-Jobs sind, dass Ihr Code im Kontext Ihres django-Projekts ausgeführt wird - das heißt, Ihr Code muss Ihre settings.py korrekt laden, um Ihre Datenbank und Ihre Apps zu kennen. Für Uneingeweihte kann dies zu einer gewissen Verschlimmerung der Wahr- nehmung der richtigen PYTHONPATH
und so.
Wenn Sie die Cron-Route verwenden, empfiehlt es sich, einen benutzerdefinierten Verwaltungsbefehl zu schreiben. Du wirst es leicht haben, deinen Befehl vom Terminal aus zu testen (und Tests zu schreiben), und du musst keinen speziellen Hoopla am oberen Rand deines Verwaltungsbefehls ausführen, um eine richtige Django-Umgebung einzurichten. In der Produktion führen Sie einfach path/to/manage.py yourcommand
aus. Ich bin mir nicht sicher, ob dieser Ansatz ohne die Unterstützung von virtualenv funktioniert, die Sie eigentlich trotzdem verwenden sollten. p>
Ein weiterer Aspekt, der bei Cronjobs berücksichtigt werden sollte: Wenn Ihre Logik eine gewisse Zeit benötigt, um ausgeführt zu werden, ignoriert Cron die Sache. Eine nette Möglichkeit, deinen Server zu töten, ist, jede Stunde einen zweistündigen Cronjob zu starten. Sie können Ihren eigenen Sperrmechanismus aktivieren, um dies zu verhindern. Seien Sie sich dessen jedoch bewusst - was als kurzer Cronjob beginnt, bleibt möglicherweise nicht so, wenn Ihre Daten wachsen oder wenn Ihr RDBMS sich schlecht verhält, etc usw.
In Ihrem Fall klingt es so, als wäre Cron weniger anwendbar, weil Sie die Graphen für jeden Benutzer so oft berechnen müssen, ohne zu berücksichtigen, wer das System tatsächlich benutzt. Hier kann Sellerie helfen.
... sind die Knie der Biene. Normalerweise werden Leute von der "Standard" -Anforderung eines AMQP-Brokers erschreckt. Es ist nicht schrecklich lästig RabbitMQ einzurichten, aber es erfordert ein wenig außerhalb der komfortablen Welt von Python. Für viele Aufgaben verwende ich nur redis als meinen Aufgabenspeicher für Sellerie. Die Einstellungen sind unkompliziert :
%Vor%Voilá, keine Notwendigkeit für einen AMQP-Broker.
Sellerie bietet eine Fülle von Vorteilen gegenüber einfachen Cron-Jobs. Wie cron können Sie regelmäßige Aufgaben einplanen, aber Sie können auch Aufgaben als Reaktion auslösen zu anderen Stimuli, ohne den Anfrage / Antwort-Zyklus zu verzögern.
Wenn Sie das Diagramm nicht jedes Mal für jeden aktiven Benutzer berechnen möchten, müssen Sie es bei Bedarf generieren. Ich gehe davon aus, dass die Abfrage nach den neuesten verfügbaren Durchschnittswerten billig ist, die Berechnung neuer Durchschnittswerte teuer ist und Sie die tatsächlichen Diagramme clientseitig mit etwas wie flot . Hier ist ein Beispielfluss:
Sie können dies mit einer periodischen Aufgabe kombinieren, um das Diagramm jede Stunde für Benutzer mit einer aktiven Sitzung neu zu berechnen, um zu verhindern, dass wirklich veraltete Diagramme angezeigt werden. Dies ist nicht die einzige Möglichkeit, die Katze zu häuten, aber sie bietet Ihnen alle Kontrolle, die Sie benötigen, um Frische zu gewährleisten, während die CPU-Last der Berechnungsaufgabe gedrosselt wird. Das Beste von allem ist, dass die periodische Aufgabe und die Aufgabe "auf Anforderung" dieselbe Logik haben - Sie definieren die Aufgabe einmal und rufen sie von beiden Stellen aus für zusätzliche DRYness auf.
Die Django-Cache-Framework bietet Ihnen alle Hooks, die Sie benötigen, um beliebig lange zwischenspeichern zu können, da Sie die meisten Produktionsseiten auf memcached als ihr Cache-Backend, habe ich in letzter Zeit begonnen, redis mit dem django-redis-cache Backend statt, aber ich bin mir nicht sicher, ob ich es für eine große Produktions-Site noch traue.
Hier ist ein Code, der die Verwendung des Low-Level-Cachings anzeigt API , um den oben beschriebenen Workflow zu erreichen:
%Vor%Bearbeiten: Beachten Sie, dass durch das Beilegen eines Abfrage-Sets das gesamte Abfrage-Set in den Speicher geladen wird. Wenn Sie eine Menge Daten mit Ihrem durchschnittlichen Abfrage-Set hochziehen, könnte dies suboptimal sein. Das Testen mit realen Daten wäre auf jeden Fall sinnvoll.
Die einfachste und IMO-richtige Lösung für solche Szenarien besteht darin, alles im Voraus zu berechnen, wenn die Dinge aktualisiert werden. Wenn der Benutzer das Dashboard sieht, berechnet er nichts, sondern zeigt nur bereits berechnete Werte an.
Es kann verschiedene Wege geben, dies zu tun, aber das generische Konzept besteht darin, eine Berechnungsfunktion im Hintergrund auszulösen, wenn sich etwas ändert, von dem die Berechnung abhängt.
Um eine solche Berechnung im Hintergrund auszulösen, benutze ich normalerweise Sellerie , also nehmen wir an, dass der Benutzer ein Objekt foo
in view view_foo
hinzufügt, rufen wir an eine Sellerie-Aufgabe update_foo_count
, die im Hintergrund ausgeführt wird und foo count aktualisiert, alternativ können Sie einen Sellerie-Timer haben, der die Anzahl alle 10 Minuten aktualisiert, indem überprüft wird, ob eine Neuberechnung durchgeführt werden muss verschiedene Orte, an denen Benutzer Daten aktualisiert.
Wenn die Daten, die langsam zu berechnen sind, denormalisiert und gespeichert werden können, wenn Daten hinzugefügt werden, anstatt wenn sie angezeigt werden, dann könnten Sie an Django-Denorm .
Tags und Links python django batch-file