2013-02-12 5 views
5

Ich benutze eine Flask-App auf Heroku mit Gunicorn mit Eventlet-Mitarbeitern. Eine bestimmte Route in meiner App empfängt häufig POST-Daten (x-www-form-urlencoded) mit einigen ziemlich großen Feldern - in der Größenordnung von höchstens 500 KB.Flask auf Heroku: request.form ist unglaublich langsam mit großen POST-Daten?

Dies funktioniert gut, wenn sie lokal ausgeführt wird, aber auf Heroku, fordert auf, dass Route zu vervollständigen überall von 5 bis 30 Sekunden dauert - und fast 100% der Zeit in dem ersten Zugriff ausgegeben request.form ist:

t = time.time() 
action = str(request.form['action']) 
dt = time.time() - t # Often 10 seconds or more! 

Dies wird auch durch die Verfolgungsnachverfolgung von Newrelic bestätigt. Es gibt ein paar Millisekunden hier und da für die Datenbankoperationen und dann einen großen Teil der Zeit im Python-Code, der offensichtlich auf einige I/O gewartet hat, da die gemeldete CPU-Zeit normalerweise weniger als eine Millisekunde beträgt.

Ich konnte es nicht vollständig in einer lokalen Umgebung reproduzieren, die dasselbe gunicorn/eventlet-Setup verwendet, das ich in Produktion verwende. Sogar der integrierte Debug-WSGI-Server ist bei diesen Anforderungen blitzschnell.

Hat jemand eine Idee, was könnte schief gehen? Ist es ein Problem mit Flask oder etwas, mit dem ich nur den Support von Heroku kontaktieren muss?

+2

Haben Sie versucht, die App auf die freie Sandbox von dotcloud zu setzen? Ich habe es kürzlich für eine kleine Flask-App verwendet, und es war ganz einfach. Vielleicht testen Sie Ihre App dort oder irgendwo ähnlich, um zu sehen, ob Sie das Problem mit Heroku oder mit Flask oder Ihrer App isolieren könnten? –

+1

Ich zweite @AllanAnderson - versuchen Sie ein ähnliches Setup auf einem anderen Anbieter - wenn es auf die gleiche Weise bricht, könnten Sie einige Beispieldaten, die das Problem verursacht, zur Verfügung stellen? –

+2

* "und fast 100% der Zeit wird für den ersten Zugriff auf request.form ausgegeben" * Ist es möglich, dass Sie die Auswirkungen von Dyno-Leerlauf erleben? https://devcenter.heroku.com/articles/dynos#dyno-idling – Dominic

Antwort

3

Ich denke, ich habe genau herausgefunden, was vor sich ging. TL; DR es war überhaupt nicht langsam auf dem Server-Ende, ich wurde nur von Newrelic gemeldeten Antwortzeiten in die Irre geführt!

Ich habe versucht, den gleichen Code auf dotCloud Sandbox wie ein @AllanAnderson vorgeschlagen. Ich habe zuerst einen reduzierten Testfall erstellt: ein einfaches HTML-Formular mit einigen versteckten Feldern, die mit etwa 900KB Daten vorgeladen wurden, und eine Ansichtsfunktion, die nur das read.form-Wörterbuch liest und die verstrichene Zeit für jeden Zugriff misst Zeit Zeit().

Auf Heroku, sahen die Ergebnisse wie folgt aus:

5.87100 seconds: read field "p1": 786432 bytes 
0.00019 seconds: read field "p2": 131072 bytes 
0.00003 seconds: read field "p3": 12288 bytes 
0.00001 seconds: read field "p4": 1024 bytes 

Und auf dotCloud:

0.00096 seconds: read field "p1": 786432 bytes 
0.00019 seconds: read field "p2": 131072 bytes 
0.00003 seconds: read field "p3": 12288 bytes 
0.00001 seconds: read field "p4": 1024 bytes 

jedoch beiden Tests die gleiche Menge an Zeit in meinem Browser zu nehmen schienen ... und Inzwischen haben Sie wahrscheinlich die richtige Antwort auf dieses "Problem" erraten. :-)

Es stellt sich heraus, dass Gunicorn auf Heroku die View-Funktion ausführt, sobald die Header empfangen wurden und der erste Zugriff auf request.form blockiert ist, bis der Rest der Anfrage empfangen wurde. Also sah NewRelic all diese lächerlich langsamen Antwortzeiten, die wirklich nur das Ergebnis des Hochladens von POST-Daten über eine schlechte Netzwerkverbindung waren. Das Setup von dotCloud wartet anscheinend nur, bis die gesamte Anfrage empfangen wurde.

Dies macht die Metriken von Newrelic weniger nützlich, aber es ist nicht wirklich ein Problem mit der Endbenutzererfahrung.

+0

Freut mich zu hören, dass Sie herausgefunden haben, was Ihre Messwerte in die Irre führt. Yay Prozess der Beseitigung! –