Hallo,
ich bin seit einem halben Jahr hinter einem Problem her, dass sich einfach nicht lösen lässt.
System: Unix FreeBSD, PHP5
Beschreibung des Programmteils:
Der untenstehende Code ist Teil einer Klasse, der exklusiven Zugriff auf named pipes steuert. Dazu wird ein Filelock-System eingesetzt, da Metaphoren-Lock nicht für derartige Belastungen, wie sie auf dieses System wirken, funktionieren. (Hinweis: pro Sekunde treffen mehrere Anfragen ein).
Fehlerbeschreibung:
Das System versagt in unregelmäßigen Abständen, da das Filelock nicht mehr durchgeführt werden kann. Sprich, die Funktion, die das Lock durchführt, verweigert einfach den Dienst, ein Locking-Mechanismus ist nichtmehr möglich und die geschützte Schnittstelle von außen überhaupt nicht mehr ansprechbar, da das Lock defekt ist.
Durchgeführte Maßnahmen und Tests:
- Neustart des Apache -> zeigt keine Wirkung (eigentlich sollten danach hängende Locks frei werden)
- Während des Fehlers sind keine gesetzten Locks feststellbar, dennoch kann kein neues Lock gesetzt werden
- Bei Auftreten des Fehlers wurde die lock Datei gelöscht und eine neue angelegt (neues file-inode). Das behob den Fehler ebenfalls nicht. Eine neue Datei mit ganz neuem Namen brachte ebenfalls keine Erkenntnisse.
- In den Serverstatistiken ist nichts auffälliges zu sehen, Spitzenlasten gab es nicht zu den Fehlerzeiten
- Komplettes Rebooten des Servers ist derzeit die einzige Lösung
Anliegen:
Hat irgendjemand eine leise Ahnung, warum das Filelock einfach zufällig versagt? Und warum ein Neustart des Apache die Locks nicht freigibt, sondern nur ein totaler Neustart des Servers hilft? Ich bin mehr als ratlos und kann dieses Problem auch nirgendwo beschrieben finden.
Hier jetzt der Code, etwas vereinfacht. Das Script durchläuft mehrere Schleifen, um das Filelock zu bekommen. Danach bricht es ab und das Script stirbt kurz danach. Es gibt also keinen Flaschenhals.
$this->flock_path = 'lock';
$this->flock_mode = 'w';
$this->flock_sleep_if_locked = 10;
$this->flock_retry_if_locked = 50;
private function lock_ask_answer($prepared_input)
{
$fp = fopen($this->flock_path,$this->flock_mode);
$v = 0;
$lock_success = FALSE;
do
{
if(!$fp) $fp = fopen($this->flock_path,$this->flock_mode);
else
{
if($v>0)
{
if($this->debug) echo '<font color="orange">v='.$v.': Lock-Datei ('.$this->flock_path.') konnte nicht genommen - nächster Versuch...</font><br>';
usleep($this->flock_sleep_if_locked);
}
$lock_success = flock($fp,LOCK_EX|LOCK_NB,$eWouldBlock);
}
++$v;
}
while($v<=$this->flock_retry_if_locked AND (!$fp OR !$lock_success OR $eWouldBlock));
if(!$fp OR !$lock_success OR $eWouldBlock)
{
if($this->debug) echo '<font color="red">Lock-Datei konnte nicht genommen werden.</font><br>';
fclose($fp);
return FALSE;
}
else
{
// Script gegen ungewollte Abbrüche blockieren
ignore_user_abort(TRUE);
// Hier wird in die named Pipes geschrieben und daraus ausgelesen...Codeteil wurde zur Übersicht entfernt
flock($fp,LOCK_UN);
fclose($fp);
ignore_user_abort(FALSE);
// Script wieder frei
return $answer;
}
}
[/PHP]