phpbar.de logo

Mailinglisten-Archive

[php] Schlafende Prozesse / flock() / ignore_user_abort() / file_get_contents()

[php] Schlafende Prozesse / flock() / ignore_user_abort() / file_get_contents()

Yannik Hampe yannik at cipher-code.de
Sa Mär 20 00:40:39 CET 2010



Mario Haßler wrote:

> Am 17.03.2010 20:48 schrieb Yannik Hampe:
> 
> 
>> [...] Wie viele Prozesse sammeln sich denn da an? 5? 10? 100? 1000?
>> Irgendwann werden auch schlafende Prozesse für das System zu Last,
>> wenn es nur genug sind. [...]
> 
> Größenordnung bis zu 50 würde ich sagen.
> 
>> Dateisperren werden auch dann freigegen, wenn man fclose() aufruft.
>> fclose() wird am Ende jedes Scripts von php für alle noch nicht
>> freigegeben Dateien automatisch aufgerufen.
> 
> Gilt das auch für Skripte, die per Timeout beendet werden?

Auf so eine Frage antworte ich sehr ungern ohne eine gute Quelle zu 
zitieren. Ich gehe jedoch davon aus, dass dies auch für Skripte gilt die 
per Timeout beendet werden.

>> Woher weißt du denn, dass der Server hängt?
> 
> Eine Suchanfrage (bei der vermutlich eine der Index-Dateien neu auf-
> gebaut werden muss, s. o.) führt zum "halben" Laden der Seite (eben
> bis zu der Ausgabe vor Neuaufbau der Index-Datei) und macht danach
> nicht weiter (keine weitere HTML-Ausgabe, Browser zeigt weiter "Lade
> Seite..." an). Vermutung: Prozess wartet "ewig" auf Freigabe zum
> Schreiben der Index-Datei.
> 
>> [...] Untersuchen könntest du das in dem du alle deine flock-Aufrufe
>> durch so etwas erstzt:
>> flock($fp, LOCK_EX | LOCK_NB, $wouldblock);
>> if ($wouldblock) throw new Exception('Could not acquire lock for file ...');
> 
> Naja, es soll ja durchaus zulässig sein, dass ein Prozess warten muss,
> bis er an die Reihe kommt.

Ja, aber in dem Zusammenhang gehen mir die Ideen aus. Du könntest es mit 
dieser Methode versuchen. Ebentuell denn flock() aufruf noch in eine 
schleife rein, die du 10x im Millisekundentakt aufrufst und wenn die 
Exception dann noch erscheint, dann ist die Wahrscheinlichkeit zumindest 
recht groß, dass du die richtige Stelle gefunden hast.

Was vielleicht noch einfacher ist, wäre es ganz viele debug-Ausgaben zu 
machen. Einfach mal zu Beginn deines Skripts eine debug-Datei 
deklarieren, die für diesen Aufruf eindeutig ist: $filename= 
'log_'.uniqid(mt_rand()).'.txt';
und dann vor jedem flock()-Aufruf: file_put_contents($filename, 
'Versuche Dateisperre zu bekommen ('.__FILE__.', Zeile: '.__LINE__.')');
und ganz am Ende von dem Skript dann unlink($filename);
Wenn das Skript dann hängen bleibt, dann wird das unlink() nie erreicht 
und du findest eine logdatei. Und in dieser guckst du dann mal nach, was 
die letzte Ausgabe war und findest so möglicherweise so schnell heraus, 
wo dein Skript stecken bleibt.

Um mal nachzuprüfen, dass php wirklich an einem Systemaufruf hängt, 
könntest du auch mal die maximum_execution_time (falls du darauf Zugriff 
hast) erheblich runterregeln (so auf 5 Sekunden vielleicht). Wenn es 
nicht an einem Systemaufruf hängt, dann wird dein Skript abbrechen und 
dir eine Fehlermeldung an den Kopf werfen in der drin steht, wo das 
Skript steckte, als die 5 Sekunden um waren.
> 
> Außerdem hatte ich noch eine andere Idee: Da ich (aus purer Faulheit,
> eine Funktion zu entwickeln, die nach Änderung im Datenbestand die
> bestehende Index-Datei an der richtigen Stelle geraderückt) bei Daten-
> änderung die Index-Datei verwerfe und bei der nächsten Suchanfrage neu
> aufbaue, kann es bisher zu folgender Situation kommen: Anfrage A löst
> Neuaufbau aus und sperrt währenddessen die Index-Datei, Anfrage B
> stellt ebenfalls fest, dass die Index-Datei neu aufgebaut werden muss
> und wartet auf Freigabe der Sperre -- um dann die Index-Datei eben-
> falls neu aufzubauen. Währenddessen kommt Anfrage C usw. Ich kann mir
> vorstellen, dass dieses wenig durchdachte Prinzip zu einem Dateisperre-
> Stau führen kann und habe es nun dahingehend abgewandelt, dass nach
> Erhalt der Sperre die Bedingung für Neuaufbau nochmals überprüft wird.
> Falls der Index gerade neu erzeugt wurde und keine Änderung in der
> Zwischenzeit den Index als überholt deklassiert, biege ich vor
> ftruncate() wieder ab, baue die Index-Datei nicht wieder auf und gebe
> die Sperre gleich wieder frei.

Klingt nach einer guten Idee ^^.
> 
> Eine Frage bleibt für mich aber trotzdem offen: Wieso hat es bei dem
> oben beschriebenen "Hängenbleiben" nicht geholfen, die Seite neu zu
> laden, wenn es geholfen hat, erst das Session-Cookie im Browser zu
> löschen und dann die Seite neu zu laden? Teilt mir der Server keinen
> neuen Prozess zu, wenn er über die Session-ID feststellt, dass ich
> schon einen Prozess (oder mehrere) laufen habe? Ich kann mir nicht
> vorstellen, dass den Server die Session-IDs interessieren, aber woran
> kann es sonst liegen?

Ich vermute mal, dass DEIN code irgendetwas anders macht, wenn keine 
Session besteht. Die Sessionid hat mit der Prozessverteilung des Servers 
eigentlich herzlich wenig zu tun. Eigentlich meine ich sogar, dass der 
Server sogar erst merken dürfte, dass eine Session da ist, nachdem die 
Prozesszuweisung längst durch ist ^^.
> 
> Nochmals vielen Dank an alle, die mir geantwortet haben!
> 
> Mario Haßler

Yannik

php::bar PHP Wiki   -   Listenarchive