fastcgi: prefork oder threaded? - minspare, maxspare usw...

Django, Flask, Bottle, WSGI, CGI…
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mit gefällt prefork, weil man dann maxRequests angeben kann.

Aber wann ist was besser?

Und gibt es irgendwelche Richtlinien zu minspare, maxspare, maxchildren usw?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Wovon redest du? python-fastcgi? flup? fcgi? Mit welchem Server am anderen Ende? apache? lighttpd? nginx?

Unabhängig davon sollte dir ja klar sein, das ein Thread-Ansatz immer nur einen CPU eines multi-core Systems ausnutzen kann, dafür aber ein prefork-Ansatz die Kommunikation zwischen den einzelnen Prozessen schwierig macht. Wie so oft hängt die Antwort also davon ab, was du eigentlich willst.
Bottle: Micro Web Framework + Development Blog
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hat die Frage eigentlich irgendwas mit FastCGI zu tun? Mir scheint du sprichst von den Apache MPMs...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja, sorry. In meinem Fall flup, fastCGI mit Apache...

Das mit dem Multicore ist schon ein recht interessanter Hinweis.

Somit ist prefork wohl zu bevorzugen. Eine Kommunikation zwischen den Prozessen findet doch bei einer normalen Django App eh nicht statt.

Wobei, was ist Speicherverbrauch? Wenn man z.B. auf Modulebene ein Cache-Objekt hinterlegt.

EDIT: Ach, beim flup setup ist mir auch nicht so ganz klar, wie man zwischen prefork und threaded wählen kann. Bei Django kann man django.core.servers.fastcgi.runfastcgi() den Parameter "method" mitgeben...

Geht das bei flup mit den unterschiedlichen importieren? Also entweder:

Code: Alles auswählen

from flup.server.fcgi_fork import WSGIServer # prefork?
oder:

Code: Alles auswählen

from flup.server.fcgi import WSGIServer # threaded?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Wie gesagt, separate Python Prozesse (prefork) haben keinen gemeinsamen Speicher. Interpreter, Modulvariablen u.s.w. sind dann jeweils mehrfach vorhanden. Für einen Cache bietet sich da eine externe Lösung (memcache, redis, sql) an, die man auch aus mehreren Prozessen gleichzeitig ansprechen kann.

Edit: ja
Bottle: Micro Web Framework + Development Blog
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Huch, du weißt schon dass sich die MPMs nur auf die Apache-Prozesse beziehen und dass der Python-Code sowieso in den FastCGI-Prozessen abläuft, denen die Einstellungen der MPM ziemlich egal sind?

Den Einwand mit dem Multicore verstehe ich nicht ganz. Sowohl prefork als auch threaded kann mehrere CPUs verwenden, denn Threads eines Prozesses können auf verschiedenen CPUs ablaufen. Der Unterschied ist nur, dass prefork Prozesse startet (die einen oder mehrere Threads nutzen - das weiß ich nicht so genau) und Threaded (Worker) "nur" Threads zur Abarbeitung der Requests nutzt.

Um mal die Apache-Dokumentation zu zitieren:
Apache 2.2: Multi-Processing Modules (MPMs) hat geschrieben:The server can be better customized for the needs of the particular site. For example, sites that need a great deal of scalability can choose to use a threaded MPM like worker or event, while sites requiring stability or compatibility with older software can use a prefork.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Leonidas hat geschrieben:Den Einwand mit dem Multicore verstehe ich nicht ganz. Sowohl prefork als auch threaded kann mehrere CPUs verwenden, denn Threads eines Prozesses können auf verschiedenen CPUs ablaufen.
CPython Prozesse belasten maximal einen CPU und sind nicht Multicore-fähig (Stichwort GIL). Es wird immer nur eine einzige Python Instruktion gleichzeitig ausgeführt, ganz egal wie viele CPUs zur Verfügung stehen.

Threads helfen bei IO-Problemen (sind also durchaus sinnvoll für Netzwerkanwendungen), da ein Thread laufen kann während ein anderer gerade blockiert. Sie werden aber dank des GIL nicht zeitgleich, sondern nur abwechselnd ausgeführt. Bei CPU-Intensiven Problemen bringen CPython Threads überhaupt gar keinen Vorteil.
Bottle: Micro Web Framework + Development Blog
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Defnull hat geschrieben:CPython Prozesse belasten maximal einen CPU und sind nicht Multicore-fähig (Stichwort GIL). Es wird immer nur eine einzige Python Instruktion gleichzeitig ausgeführt, ganz egal wie viele CPUs zur Verfügung stehen.
CPython beherrscht durchaus mehrere Threads, nur halt nicht mehrere Python-Threads gleichzeitig. Aber C-Funktionen in der Stdlib, ctypes oder Erweiterungsmodule wie lxml geben den GIL frei.

Und wie du bereits meintest, bei IO funktioniert das ebenfalls.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hm, ja was nun ;) Also ich denke ja, das Multicore nur dann richtig genutzt werden können, wenn mehrere unabhängige Python Prozesse gestartet werden. Ist das also bei prefork der Fall?

Laut der Apache Aussage ist "prefork" ehr alt???

Wenn ich das richtig gesehen habe, wird bei trac flup.server.fcgi genommen, was also threaded ist. Django nutzt normalerweise prefork.

Hab was gefunden: http://www.alrond.com/en/2007/jan/25/pe ... rameworks/
Dort wird u.a. Django mit threaded und einmal im prefork modus getestet.

Nach den folgenden Bildern zu urteilen, verbraucht prefork mehr RAM und ist langsamer?

Bild

Bild

CPU war ein "AMD OpteronT Processor 146 (2 GHz)", was glaube ich ein Single core ist.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Du verwechseltst immer noch Apache mit dem FastCGI-Prozess. Die beiden sind unabhängig. "prefork" ist der *Name* der Apache MPM die neue Prozesse startet um Requests abzuarbeiten. Generell würde ich diese Ansätze eher *forking* und *threaded* nennen, das "prefork" ist einfach nur ein Name von Apache, weil er erst die Prozesse forkt und dann die Requests annimmt. Das ist keine generell gültige Bezeichnung.

Der FastCGI-Prozess in dem Python abläuft ist nun vollständig unabhängig von Apache und es steht ihm frei ob er Threads oder Subprozesse nutzt. Mit flup kann man sich das offensichtlich aussuchen, aber ich wiederhole, das ist vom Apache (und generell vom Webserver) völlig unabhängig.

Was ich etwa nutze ist Apache MPM Worker (threaded) und FastCGI threaded. Man kann aber genausogut auch MPM Worker verwenden und den forking-FastCGI-Server.

Und mit Django hat das eigentlich auch nichts zu tun, denn es ist flup ja auch total egal was es ausführt, das könnte genausogut auch Werkzeug oder bottle sein.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also auf die Apache Konfiguration hab ich eh keinen Einfluss. Ich weiß auch nicht wie der Eingestellt ist. Mir geht es also nur um threaded/prefork in flup.

Wenn ich das also richtig verstehe, kann an einmal beim Apache threaded/prefork auswählen und unabhängig davon in flup zwischen threaded/prefork wählen???

Gibt es dann Wechselwirklungen zwischen Apache und flup? Nach dem Motto, wenn Apache mit X läuft, ist es besser das flup mit Y läuft?

Aus dem Benchmark von http://www.alrond.com/en/2007/jan/25/pe ... rameworks/ :
I started with two methods prefork and threaded. But the python doesn’t work so well with treads.

Code: Alles auswählen

python manage.py runfcgi method=threaded host=127.0.0.1 port=8801
python manage.py runfcgi method=prefork host=127.0.0.1 port=8801
Somit spielt bei dem Benchmark Apache überhaupt kein Rolle, oder?

Hier noch ein "Fazit" aus dem Benchmark:
Use prefork not threaded FastCGI: Prefork requires a little more memory than threaded, but under extreme load it was stable and used less CPU (See Alronds article for why).
von http://jetfar.com/notes-on-running-djan ... -on-nginx/

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Ich glaub du solltest dir mal anschauen, was fastcgi eigentlich ist.

Fastcgi ist ein Netzwerkprotokoll. Ein Fastcgi-Server (z.B. flup) nimmt Fastcgi-Anfragen entgegen, verarbeitet sie und gibt in den meisten Fällen HTTP Antworten zurück. Ein Fastcgi Gateway (apache) nimmt HTTP Anfragen entgegen, wandelt sie in Fastcgi Anfragen um und reicht sie an einen Fastcgi-Server weiter.

Code: Alles auswählen

Client --HTTP-> apache --fcgi-> flup --WSGI-> appcode
Client <-HTTP-- apache <-HTTP-- flup <-WSGI-- appcode
EDIT: Auf 'Absenden geklickt statt auf 'Vorschau' *grml*

Fastcgi ist also einfach nur das Netzwerk-Protokoll, mit dem dein Apache-Server mit deinem Application-Server spricht. Mehr nicht.

Du kannst Apache auch mit mod_proxy an einen Application-Server anbinden, der direkt HTTP spricht. Oder du kannst Apache komplett weg lassen. Fastcgi war ursprünglich eine Möglichkeit, CGI Scripte schneller zu machen (daher auch der Name) ohne die eigentlichen Programme ändern zu müssen (gleiche Umgebungsvariablen wie bei CGI). Heutzutage macht Fastcgi kaum noch Sinn, aber das ist eine andere Geschichte.

Um zum Punkt zurück zu kommen: Du hast zwei Netzwerk-Server. HTTP/Apache und fastcgi/flup. Beide können jeweils threads, prozessen (forks) oder asynchron arbeiten. Sie sind dabei aber völlig unabhängig voneinander.

Apache ist lahm, ganz egal ob mit prefork oder mit threads. Wenn du Performance willst, nimm nginx, lighttpd oder noch viel besser: Einen asynchronen HTTP Server der direkt WSGI spricht: fapws3.

Das meiner Erfahrung nach beste Setup in Sachen Geschwindigkeit ist eh ein schneller HTTP Load Balancer (phound) und dahinter für jeden CPU Kern eine fapws3 Instanz.

Ich hab auf meinem Desktop PC (4Kern CPU) mit diesem Setup (und bottle.py 'Hello World') etwa 25.000 Requests/Sekunde hin bekommen. Das reicht.
Zuletzt geändert von Defnull am Freitag 5. März 2010, 15:18, insgesamt 3-mal geändert.
Bottle: Micro Web Framework + Development Blog
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ja, das weiß ich im Grunde schon. Aber hilft mir jetzt nicht so ganz weiter ;)

Mal anders gefragt:

Bei Apache kann man threaded/prefork angeben und bei flup kann man threaded/prefork angeben.

Was macht in welche Kombination Sinn. Wo liegen die Vor- und Nachteile.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Wenn ich das also richtig verstehe, kann an einmal beim Apache threaded/prefork auswählen und unabhängig davon in flup zwischen threaded/prefork wählen???
Ja, genau.
jens hat geschrieben:Gibt es dann Wechselwirklungen zwischen Apache und flup? Nach dem Motto, wenn Apache mit X läuft, ist es besser das flup mit Y läuft?
Nein, aus der Sicht des Webservers ist der FastCGI-Prozess eine Blackbox und aus der Sicht des FastCGI-Prozesses einen Blackbox. Wie sie die Daten verarbeiten ist ja eigentlich nur Implementationsdetail.
jens hat geschrieben:Aus dem Benchmark von http://www.alrond.com/en/2007/jan/25/pe ... rameworks/ :
I started with two methods prefork and threaded. But the python doesn’t work so well with treads.

Code: Alles auswählen

python manage.py runfcgi method=threaded host=127.0.0.1 port=8801
python manage.py runfcgi method=prefork host=127.0.0.1 port=8801
Somit spielt bei dem Benchmark Apache überhaupt kein Rolle, oder?
Nein, teilweise auch deswegen weil da kein Apache sondern nginx verwendet wird. Natürlich wäre der Benchmark etwas langsamer oder schneller je nachdem welchen Web-Server und im Falle von Apache, welche MPM verwendet wird. Weil die Requests ja erstmal da durch müssen.

Allerdings frage ich mich schon, mit wie vielen Requests du rechnest, dass sowas für dich überhaupt einen Unterschied machen würde.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Leonidas hat geschrieben:Allerdings frage ich mich schon, mit wie vielen Requests du rechnest, dass sowas für dich überhaupt einen Unterschied machen würde.
Naja, das will ich ja raus finden.

Ist es also so, das es bei Low-Traffic keinen Unterschied macht? Wobei man bedenken muß, das der Server evtl. lahm ist und wenig RAM hat. Von daher machen evtl. kleine Änderungen schon was aus.

Kann man also pauschale Aussagen überhaupt nicht machen?
Welche Faktoren spielen eine Rolle?
* Hardware Seite:
** CPU: Single- / Multi-core
** RAM Aussatttung
* WebApp:
** CPU/Festplatten/Netzwerk lastig?
* Auslastung, also Request Anzahl

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Ist es also so, das es bei Low-Traffic keinen Unterschied macht? Wobei man bedenken muß, das der Server evtl. lahm ist und wenig RAM hat. Von daher machen evtl. kleine Änderungen schon was aus.
Naja, wenn der Server lahm ist, wird es so oder so lahm sein. Es ist ja nicht so als ob die beiden Verianten um Größenordnungen unterschiedlich sind. Sondern nur ein klein wenig. Und das klein wenig reißts bei einem lahmen Server dann auch nicht mehr raus. Hab ich selbst schon auf meinem letzten vServer festgestellt.
jens hat geschrieben:** CPU: Single- / Multi-core
Der Apache kann beides auslasten, unabhängig ob du Worker oder Prefork nutzt. Der FastCGI-Server kann das nur wenn du Prozesse nutzt (jetzt mal etwas übertrieben gesagt).
jens hat geschrieben:** RAM Aussatttung
Forken erstellt neue Prozesse, die mehr Speicher brauchen als Threads, die sich den Heap teilen und nur eigene Stacks brauchen.
jens hat geschrieben:** CPU/Festplatten/Netzwerk lastig?
CPU-lastig: Prozesse (bei FastCGI, Apache ist das relativ egal, würde dennoch zum Worker tendieren). IO-Lastig: macht keine so großen Unterschiede.
jens hat geschrieben:* Auslastung, also Request Anzahl
Kann man schwer pauschal sagen. Je mehr Requests, desto größere Parallelität sollte man unterstützen. Threads sind an dieser Stelle etwas nützlicher, weil sie "leichtgewichtiger" sind und daher schneller mehr davon angelegt werden kann und auch das umschalten zwischen Threads schneller geht, aber Python unter FastCGI ist mit Threads tatsächlich nicht die beste Alternative. Also wenn ich viele Requests arwarten würde, würde ich MPM Worker hernehmen, eine Menge RAM und Forking bei FastCGI (vielleicht auch flup ersetzen, müsste man schauen) oder FastCGI gleich gar ersetzen. Und eigentlich würde ich noch Caches einsetzen, ich denke die bringen aus dem Stehgreif wesentlich mehr als so etwas.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

zu fapws3 geht es hier weiter: http://www.python-forum.de/topic-22138.html

EDIT: Ich habe die Threads zusammen geführt!

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Weiß jemand warum eine Django-App mit fastCGI immer mit 6 Threads läuft? Gestartet so:

Code: Alles auswählen

    # usable parameter see also django/core/servers/fastcgi.py
    runfastcgi(
        protocol="fcgi", # fcgi, scgi, ajp, ... (django default: fcgi)
        host=None, # hostname to listen on (django default: None)
        port=None, # port to listen on (django default: None)
        socket=None, # UNIX socket to listen on (django default: None)

        method="threaded", # prefork or threaded (django default: "prefork")
        daemonize="false", # whether to detach from terminal (django default: None)
        umask=None, # umask to use when daemonizing e.g.: "022" (django default: None)
        pidfile=None, # write the spawned process-id to this file (django default: None)
        workdir="/", # change to this directory when daemonizing. (django default: "/")

        minspare=2, # min number of spare processes / threads (django default: 2)
        maxspare=5, # max number of spare processes / threads (django default: 5)
        maxchildren=50, # hard limit number of processes / threads (django default: 50)
        maxrequests=100, # number of requests before killed/forked (django default: 0 = no limit)
        # maxrequests -> work only in prefork mode

        debug=settings.DEBUG, # Enable flup debug traceback page
        outlog=None, # write stdout to this file (django default: None)
        errlog=None, # write stderr to this file (django default: None)
    )

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Was glaubst ;) 1 + maxSpare ist 6, ob und unter welchen Umständen maxSpare da sind kann ich dir nicht sagen ;)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

minspare/maxspare stehen aber in dem Fall für Prozesse. Zumindest werden immer zwei Prozesse gestartet, die dann bis zu fünf werden, ja nach Last. Aber jeder Prozess hat laut /proc/PID/status immer genau sechs Threads...

Ich vermute mal maxchildren bezieht sich auch auf Prozesse. Wobei mir nicht ganz klar ist, wie der Wert zu maxspare steht...

Im übrigen sind es bei dem dev. Server immer genau zwei Threads (natürlich nur immer ein Prozess)

Ich sollte mal testen, was passiert, wenn ich statt method="threaded" auf "prefork" umstelle.

btw. Hatte ganz vergessen, das ich zum Thema threaded/prefork schon mal was geschrieben hab. EDIT: Ich hab die beiden Board-Stränge zusammen geführt...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten