Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

Was fehlt?

Es liegt in der Natur der Sache: Ein Wiki ist niemals fertig. Wir geben uns große Mühe, mit der Entwicklung Schritt zu halten; lassen Supportanfragen direkt in neue Artikel einfließen … aber auch wir sind nicht perfekt. Wenn du hier nicht fündig wirst: Nicht schmollen - Bescheid sagen! Unter hallo@uberspace.de steht dir unser Team gerne bereit. Hand drauf!

webserver:fastcgi

FastCGI

FastCGI stellt eine äußerst effektive Möglichkeit dar, um Web-Applikationen persistent laufen zu lassen. Bei klassischen CGI-Scripts sieht es nämlich so aus, dass bei einem eingehenden HTTP-Request der Webserver das betreffende Script startet (was also typischerweise bedeutet, dass zunächst der betreffende Interpreter der Programmiersprache von der Platte gelesen und ausgeführt werden muss, dieser dann das eigentliche Script von der Platte liest, interpretiert und ausführt), was dann den Request verarbeitet und, nachdem es sein „Hallo, Welt!“ von sich gegeben hat, wieder beendet - kommt eine Sekunde später ein weiterer Request rein, muss erneut der Interpreter gestartet werden. Der Overhead ist von daher gigantisch und für größere Applikationen nicht praktikabel.

Grundlagen

FastCGI-Scripts hingegen sind so gestaltet, dass sie in eine Schleife verfallen, die dazu in der Lage ist, hintereinander mehrere Requests zu verarbeiten. Dabei muss weder der Interpreter noch das Script erneut von Platte geladen werden, weshalb das Ausliefern einer derart generierten Seite sehr schnell vor sich geht.

Um es mal an einem konkreten Beispiel - hier mit Perl - deutlich zu machen: So sähe ein „Hallo, Welt!“-Script als CGI aus:

#!/usr/bin/env perl
print "Content-type: text/plain\n\n";
print "Hallo, Welt!\n";

Es ist klar erkennbar: Das Script gibt etwas aus und ist danach fertig. Und so sähe die FastCGI-Variante aus:

#!/usr/bin/env perl
use FCGI;
my $req = FCGI::Request();
while($req->Accept() >= 0) {
  print "Content-type: text/plain\n\n";
  print "Hallo, Welt!\n";
}

Hier ist ebenso klar erkennbar: Wir befinden uns in einer Schleife, die darauf angelegt ist, „ewig“ zu laufen: $req→Accept() wartet auf einen eingehenden Request, und sobald er kommt, lässt es die Schleife einmal durchlaufen.

Hierbei wird aber auch schon deutlich: Man kann ein CGI-Script nicht einfach unter FastCGI laufen lassen; es braucht in jedem Fall (wenigstens minimale) Anpassungen. Viele größere Softwareprojekte bringen allerdings von Haus aus entsprechende FastCGI-Anbindungen mit, beispielsweise das Catalyst-Framework für Perl, die Softwareprojektverwaltung Trac oder Ruby on Rails (wobei hier eher empfohlen wird, jenes unter mongrel laufen zu lassen, weil die FastCGI-Implementierung hier als nicht sehr stabil gilt).

Nutzung

Wir stellen dir ein eigenes fcgi-bin Verzeichnis zur Verfügung, das in /var/www/virtual/$USER/fcgi-bin zu finden ist (in deinem Home-Verzeichnis findet sich für den schnelleren Zugriff darauf ein Symlink dorthin). Jedes Script, das du dort ablegst, wird als FastCGI-Script ausgeführt.

Möchtest du FastCGI-Scripts auch außerhalb des fcgi-bin-Verzeichnisses ausführen (also innerhalb des DocumentRoots), reicht eine Zeile in einer .htaccess-Datei, um beispielsweise alle Dateien mit der Endung .fcgi als FastCGI-Scripts ausführen zu lassen, brauchst du diese Zeilen:

Options +ExecCGI
AddHandler fcgid-script .fcgi

(Auf unserem Host helium kommt derzeit noch mod_fastcgi statt mod_fcgid zum Einsatz. In diesem Fall muss die zweite Zeile AddHandler fastcgi-script .fcgi heißen.)

Anschließend werden alle Dateien mit der Endung .fcgi als FastCGI-Script ausgeführt, auch außerhalb von fcgi-bin.

Wichtig ist, dass die Scripts ausführbar sind - dazu solltest du die Rechte 0755 (Lese- und Ausführungsrechte für alle, Schreibrechte nur für dich) vergeben. Vergibst du weitergehende Schreibrechte, werden die Scripts aus Sicherheitsgründen nicht mehr ausgeführt; vergibst du weniger Rechte, kann der Webserver das Script möglicherweise nicht lesen und ausführen.

Dies gilt nicht nur für das Script selbst, sondern auch für das Verzeichnis, in dem es liegt - setz also auch bitte für jenes mit einem chmod 755 die entsprechenden Rechte.

Wenn du keine eigenen FastCGI-Scripts schreibst, sondern größere Softwarepakete einsetzt, die FastCGI-Support haben, empfehlen wir dir, dich dort in der betreffenden Doku umzuschauen. Im Zweifelsfall frag uns einfach; bei vielen Projekten können wir gerne helfen.

Touch to restart?

In einigen Dokumentationen (zum Beispiel in der zu Django unter FastCGI) liest man, dass man zum Neustart der Applikation nach Code-Änderungen das von FastCGI ausgeführte Deployment-Script (gerne „Dispatcher“ genannt) aktualisieren müsse, z.B. mit touch. Dabei handelt es sich aber nicht um ein Standardfeature von FastCGI. Wir setzen auf den meisten unserer Hosts mod_fcgid ein, und das hat überhaupt kein solches Feature. Auf älteren Hosts arbeiten wir noch mit mod_fastcgi, das zwar ein solches Feature besitzt, es aber standardmäßig nicht aktiviert hat - und auch selbst empfiehlt, ein solche Auto-Reload-Feature lieber innerhalb der jeweiligen unter FastCGI laufenden Applikation zu implementieren:

-autoUpdate (none)
Causes mod_fastcgi to check the modification time of the application on disk before processing each request. If the application on disk has been changed, the process manager is notified and all running instances of the application are killed off. In general, it's preferred that this type of functionality be built-in to the application (e.g. every 100th request it checks to see if there's a newer version on disk and exits if so). There may be an outstanding problem (bug) when this option is used with -restart.

Insofern funktioniert touch-to-restart bei Uberspace.de grundsätzlich nicht. Du kannst, wenn du einen Restart erzwingen willst, aber anstelle von touch einfach mittels kill (mit Prozess-ID) bzw. killall (mit Prozessname) die betreffenden Prozesse beenden; das jeweilige FastCGI-Modul startet deine Applikation beim nächsten Request dann automatisch neu.

Übrigens ... PHP

PHP läuft bei uns ebenfalls unter FastCGI und nicht als Apache-Modul (mod_php). Auf diese Weise erreichen wir, dass auch deine PHP-Scripts mit deinen Userrechten laufen und nicht mit den Rechten des Webservers, was für eine optimale rechtemäßige Trennung zwischen den Uberspaces sorgt.

Allerdings besteht hier trotzdem ein gewisser Unterschied: Es läuft so nämlich nur der PHP-Interpreter persistent, nicht aber die Applikation. Soll heißen, wenn ein HTTP-Request reinkommt, muss zwar kein PHP-Interpreter mehr gestartet werden, weil er dank FastCGI bereits läuft (außer beim allerersten Request), aber der PHP-Interpreter muss immer noch das betreffende PHP-Script von der Platte lesen und es interpretieren, bevor tatsächlich etwas passiert. Das ist bei mod_php genauso, insofern ist das performancetechnisch nicht schlechter. Es ist aber eben trotzdem nicht so performant, wie eine ganze Applikation unter FastCGI laufen zu lassen, bei der der interpretierte Code dann bereits im Speicher ist.

Übrigens, nur um das kurz erwähnt zu haben: PHP unterstützt unter anderem auch HTTP Basic Authentication, wobei die vom Benutzer eingegebenen Zugangsdaten als PHP_AUTH_USER und PHP_AUTH_PW im $_SERVER-Array bereitstehen - was aber normalerweise nur beim Einsatz von PHP als Apache-Modul (mod_php) funktioniert und nicht unter FastCGI. Die Entwickler beider Seiten sind offenbar unterschiedlicher Ansicht, wie die HTTP-Variable heißen muss, die FastCGI setzen und PHP auslesen muss. Bei allen Uberspaces, die nach dem 08.02.2011 angelegt wurden, haben wir automatisch einen Workaround eingefügt, der den betreffenden HTTP-Header so übersetzt, dass auch PHP ihn interpretiert:

RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Sollte dein Uberspace älter sein und du Basic Authentication mit PHP benötigen, kannst du obige Zeile auch einfach in einer .htaccess-Datei zur Anwendung bringen, oder sag uns kurz Bescheid und wir fügen das nachträglich in deinen VirtualHost ein.

webserver/fastcgi.txt · Zuletzt geändert: 2014/12/23 08:43 von uber