python-http-server, mehrere gleichzeitige Anfragen
Entwickelt ich eine ziemlich umfangreiche http-server in python geschrieben unter Verwendung von tornado. Ohne Einstellung, nichts besonderes, blockiert der server auf Anfragen und können nur eine zu einem Zeitpunkt. Die Anforderungen im wesentlichen auf Daten zuzugreifen (mysql/redis) und drucken Sie es aus in json. Diese Anforderungen können nach oben zu nehmen von einer Sekunde auf die schlimmsten Fall. Das problem ist, dass eine Anfrage kommt, dass dauert eine lange Zeit (3s), dann eine einfache Anfrage kommt sofort nach, dass nehmen würde, 5ms zu behandeln. Auch da, die erste Anfrage wird noch ein 3s, der zweite startet erst, wenn die erste erledigt ist. So der zweite Antrag nimmt die >3s behandelt werden.
Wie kann ich diese situation besser? Ich brauche das zweite einfache Anfrage an die Ausführung beginnt unabhängig von anderen Anfragen. Ich bin neu in python und mehr Erfahrung mit apache/php, wo es keine Vorstellung von zwei getrennten requests blockieren sich gegenseitig. Ich habe mir in mod_python zu emulieren, die php-Beispiel, aber das scheint zu blockieren, sowie. Kann ich mein tornado-Servers, um die Funktionalität, die ich will? Überall lese ich, es sagt, dass der tornado ist Super im Umgang mit mehreren gleichzeitigen Anforderungen.
Ist hier der demo-code, mit dem ich arbeite. Ich habe einen sleep-Befehl ist, die ich verwende, um zu testen, ob die Parallelität funktioniert. Ist Schlaf eine faire Art und Weise zu testen Parallelität?
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.gen
import time
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous
@tornado.gen.engine
def handlePing1(self):
time.sleep(4)#simulating an expensive mysql call
self.write("response to browser ....")
self.finish()
def get(self):
start = time.time()
self.handlePing1()
#response = yield gen.Task(handlePing1)#i see tutorials around that suggest using something like this ....
print "done with request ...", self.request.path, round((time.time()-start),3)
application = tornado.web.Application([
(r"/.*", MainHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
port=8833;
http_server.listen(port)
print "listening on "+str(port);
tornado.ioloop.IOLoop.instance().start()
Vielen Dank für jede Hilfe!!!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Edit: denken Sie daran, dass Redis wird auch single-threaded, so dass selbst wenn Sie die Anzahl gleichzeitiger Anforderungen, Ihren Engpass wird Redis. Sie werden nicht in der Lage, um weitere Anforderungen, da Redis nicht in der Lage, diese zu verarbeiten.
Tornado ist single-threaded event-loop-basierte server.
Aus der Dokumentation:
Parallelität in tornado wird erreicht durch asynchrone Rückrufe. Die Idee ist, so wenig wie möglich in die Haupt-event-Schleife (single-threaded) zu blockieren zu vermeiden und aufzuschieben, i/o-Operationen über Rückrufe.
Wenn die Verwendung asynchroner Vorgänge nicht für Sie arbeiten (ex: Nein async-Treiber für MySQL, oder Redis), ist Ihre einzige Möglichkeit der Behandlung mehr gleichzeitige Anforderungen ausführen mehrerer Prozesse.
Der einfachste Weg ist, um vor Ihrer tornado-Prozesse mit einem reverse-proxy wie HAProxy oder Apache. Der tornado doc empfiehlt Nginx: http://www.tornadoweb.org/en/stable/overview.html#running-tornado-in-production
Ihre im Grunde laufen mehrere Versionen Ihrer app auf verschiedenen ports. Ex:
Eine gute Faustregel ist, zu laufen 1 Prozess für jeden Kern auf dem server.
Nginx kümmern balancing jede eingehende Anfragen an die verschiedenen backends. Also, wenn einem der Wunsch ist langsam (~ 3s) Sie haben n-1 andere Prozesse lauschen auf eingehende Anfragen. Es ist möglich – und sehr wahrscheinlich–, dass alle Prozesse beschäftigt sein wird die Verarbeitung einer slow-ish-Anfrage, in diesem Fall werden die Anfragen automatisch in die Warteschlange gestellt und verarbeitet, wenn jeder Prozess frei wird, zB. beendet die Verarbeitung der Anfrage.
Ich empfehle, Sie beginnen mit Nginx, bevor Sie versuchen, HAProxy als die letztere ist ein wenig weiter Fortgeschritten und somit ein bisschen schwieriger, um das setup richtig zu machen (viele Schalter, zu optimieren).
Hoffe, das hilft. Key take-away: Tornado ist ideal für asynchronen I/O, weniger für die CPU-schweren workloads.
Hatte ich dieselben problem, aber kein tornado, kein mysql.
Haben Sie eine Datenbank-Verbindung gemeinsam mit allen server?
Erstellte ich eine
multiprocessing.Pool
. Jeder hat seine eigene db-Verbindung zur Verfügung gestellt voninit
Funktion. Ich wickle langsam code in der Funktion und inmap
es zum Pool. Also ich haben keine gemeinsamen Variablen und verbindungen.Schlaf nicht blockiert andere threads, aber DB-Transaktion block-threads.
Müssen Sie setup-Pool an der Spitze Ihres Codes.
Viele gleichzeitige schnelle Anfragen können Verlangsamung eine große bitte, aber diese Parallelität wird auf Datenbank-server.