Heim  >  Artikel  >  Backend-Entwicklung  >  Zusammenfassung von Lösungen mit hoher Parallelität für PHP-Lese- und Schreibdateikonflikte

Zusammenfassung von Lösungen mit hoher Parallelität für PHP-Lese- und Schreibdateikonflikte

伊谢尔伦
伊谢尔伦Original
2017-07-17 10:09:212295Durchsuche

In PHP scheint Flock nicht so gut zu funktionieren! Bei mehrfacher Parallelität scheinen Ressourcen oft monopolisiert zu sein und nicht sofort oder überhaupt nicht freigegeben zu werden, was zu Deadlocks führt, die CPU-Auslastung des Servers sehr hoch macht und manchmal sogar dazu führt, dass der Server vollständig abstürzt. Es scheint, dass dies in vielen Linux-/Unix-Systemen passiert. Deshalb müssen Sie vor der Verwendung von Flock sorgfältig überlegen.

Wenn flock() richtig verwendet wird, ist es durchaus möglich, das Deadlock-Problem zu lösen. Wenn Sie die Verwendung der Funktion flock() nicht in Betracht ziehen, gibt es natürlich auch eine gute Lösung für unser Problem. Die Lösungen sind grob wie folgt zusammengefasst.
Option 1: Legen Sie beim Sperren der Datei eine Zeitüberschreitung fest. Die grobe Implementierung ist wie folgt:

if($fp=fopen($fileName,'a')){
 $startTime=microtime();
 do{
  $canWrite=flock($fp,LOCK_EX);
  if(!$canWrite){
   usleep(round(rand(0,100)*1000));
  }
 }while((!$canWrite)&&((microtime()-$startTime)<1000));
 if($canWrite){
  fwrite($fp,$dataToSave);
 }
 fclose($fp);
}

Das Timeout wird auf 1 ms eingestellt. Wenn die Sperre nicht innerhalb dieser Zeit erhalten wird, wird sie wiederholt erhalten, bis das Recht zum Betreiben des Die Datei wird natürlich erhalten. Wenn das Timeout-Limit erreicht ist, müssen Sie den Vorgang sofort beenden und die Sperre aufheben, damit andere Prozesse ausgeführt werden können.

Option 2: Verwenden Sie nicht die Flock-Funktion und verwenden Sie temporäre Dateien, um das Problem von Lese- und Schreibkonflikten zu lösen. Das allgemeine Prinzip lautet wie folgt:
(1) Legen Sie eine Kopie der Datei, die aktualisiert werden muss, in unserem temporären Dateiverzeichnis ab, speichern Sie den Zeitpunkt der letzten Änderung der Datei in einer Variablen und wählen Sie eine zufällige aus für diese temporäre Datei, was nicht einfach ist. Doppelter Dateiname.
(2) Überprüfen Sie nach dem Aktualisieren dieser temporären Datei, ob die letzte Aktualisierungszeit der Originaldatei mit der zuvor gespeicherten Zeit übereinstimmt.
(3) Wenn der Zeitpunkt der letzten Änderung derselbe ist, benennen Sie die geänderte temporäre Datei in die Originaldatei um. Um sicherzustellen, dass der Dateistatus synchron aktualisiert wird, muss der Dateistatus gelöscht werden.
(4) Wenn jedoch die letzte Änderungszeit mit der zuvor gespeicherten übereinstimmt, bedeutet dies, dass die Originaldatei in diesem Zeitraum geändert wurde. Zu diesem Zeitpunkt muss die temporäre Datei gelöscht und dann „falsch“ zurückgegeben werden. Zeigt an, dass die Datei zu diesem Zeitpunkt geändert wurde. Es sind noch andere Prozesse im Gange.
Der Implementierungscode lautet wie folgt:

$dir_fileopen=&#39;tmp&#39;;
function randomid(){
    return time().substr(md5(microtime()),0,rand(5,12));
}
function cfopen($filename,$mode){
    global $dir_fileopen;
    
clearstatcache
();
    do{
  $id=md5(randomid(rand(),TRUE));
        $tempfilename=$dir_fileopen.&#39;/&#39;.$id.md5($filename);
    } while(
file_exists
($tempfilename));
    if(file_exists($filename)){
        $newfile=false;
        copy($filename,$tempfilename);
    }else{
        $newfile=true;
    }
    $fp=fopen($tempfilename,$mode);
    return $fp?array($fp,$filename,$id,@
filemtime
($filename)):false;
}
function cfwrite($fp,$string){
 return fwrite($fp[0],$string);
}
function cfclose($fp,$debug=&#39;off&#39;){
    global $dir_fileopen;
    $success=fclose($fp[0]);
    clearstatcache();
    $tempfilename=$dir_fileopen.&#39;/&#39;.$fp[2].md5($fp[1]);
    if((@filemtime($fp[1])==$fp[3])||($fp[4]==true&&!file_exists($fp[1]))||$fp[5]==true){
        rename($tempfilename,$fp[1]);
    }else{
        unlink($tempfilename);
  //说明有其它进程 在操作目标文件,当前进程被拒绝
        $success=false;
    }
    return $success;
}
$fp=cfopen(&#39;lock.txt&#39;,&#39;a+&#39;);
cfwrite($fp,"welcome to beijing.\n");
fclose($fp,&#39;on&#39;);

Für die im obigen Code verwendeten Funktionen ist Folgendes zu erklären:
(1) rename(); Benennen Sie eine Datei oder ein Verzeichnis um . Diese Funktion ähnelt eigentlich eher mv unter Linux. Es ist praktisch, den Pfad oder Namen einer Datei oder eines Verzeichnisses zu aktualisieren. Wenn ich jedoch den obigen Code im Fenster teste und der neue Dateiname bereits vorhanden ist, wird eine Meldung angezeigt, dass die aktuelle Datei bereits vorhanden ist. Aber unter Linux funktioniert es einwandfrei.
(2) clearstatcache(); clear file status.php speichert alle Datei--Attribut--Informationen, um eine höhere Leistung zu erzielen, aber manchmal hatten mehrere Prozesse keine Zeit dafür Aktualisieren Sie die Dateiattribute im Cache, was leicht dazu führen kann, dass es sich beim letzten Aktualisierungszeitpunkt nicht um echte Daten handelt. Hier müssen Sie also diese Funktion verwenden, um den gespeicherten Cache zu leeren.

Option 3: Lesen und schreiben Sie die bearbeiteten Dateien nach dem Zufallsprinzip, um die Möglichkeit einer Parallelität zu verringern.
Diese Lösung scheint häufiger bei der Aufzeichnung von Benutzerzugriffsprotokollen verwendet zu werden. Zuvor mussten wir einen zufälligen Speicherplatz definieren, desto geringer ist die Möglichkeit der Parallelität. Unter der Annahme, dass der zufällige Lese- und Schreibbereich [1-500] beträgt, reicht die Verteilung unserer Protokolldateien von log1 bis log500. Bei jedem Zugriff eines Benutzers werden Daten zufällig in eine beliebige Datei zwischen log1 und log500 geschrieben. Gleichzeitig gibt es zwei Prozesse, die Protokolle aufzeichnen. Prozess A ist möglicherweise die aktualisierte Log32-Datei, aber was ist mit Prozess B? Dann kann die Aktualisierung zu diesem Zeitpunkt log399 sein. Sie müssen wissen, dass die Wahrscheinlichkeit im Grunde 1/500 beträgt, wenn Prozess B auch log32 ausführen soll, was fast gleich Null ist. Wenn wir Zugriffsprotokolle analysieren müssen, müssen wir diese Protokolle nur zuerst zusammenführen und dann analysieren. Ein Vorteil der Verwendung dieser Lösung zum Aufzeichnen von Protokollen besteht darin, dass die Möglichkeit, Prozessvorgänge in die Warteschlange zu stellen, relativ gering ist, sodass der Prozess jeden Vorgang sehr schnell abschließen kann.

Option 4: Alle auszuführenden Prozesse in eine Warteschlange stellen. Stellen Sie dann einen dedizierten Dienst ein, um den Dateivorgang abzuschließen. Jeder ausgeschlossene Prozess in der Warteschlange entspricht dem ersten spezifischen Vorgang, sodass unser Dienst zum ersten Mal nur die spezifischen Vorgangselemente aus der Warteschlange abrufen muss. Wenn hier eine große Anzahl von Dateivorgangsprozessen vorhanden ist, spielt dies keine Rolle . Stellen Sie sich einfach ans Ende unserer Warteschlange. Solange Sie bereit sind, sich anzustellen, spielt es keine Rolle, wie lang die Warteschlange ist.

Bei den vorherigen Optionen hat jede ihre eigenen Vorteile! Es kann grob in zwei Kategorien unterteilt werden:
(1) Warteschlangen sind erforderlich (langsame Auswirkung), wie Optionen 1, 2 und 4
(2) Warteschlangen sind nicht erforderlich. (Schnelle Auswirkung) Option 3
Beim Entwurf des Caching-Systems werden wir Option 3 im Allgemeinen nicht verwenden. Da das Analyseprogramm und das Schreibprogramm von Plan 3 nicht synchronisiert sind, wird beim Schreiben die Schwierigkeit der Analyse überhaupt nicht berücksichtigt, solange das Schreiben gut ist. Stellen Sie sich vor, wenn wir beim Aktualisieren eines Caches auch zufälliges Lesen und Schreiben von Dateien verwenden, scheinen beim Lesen des Caches viele Prozesse hinzugefügt zu werden. Die Optionen eins und zwei sind jedoch völlig unterschiedlich. Obwohl die Schreibzeit abgewartet werden muss (wenn der Erwerb der Sperre fehlschlägt, wird sie wiederholt erworben), ist das Lesen der Datei jedoch sehr praktisch. Der Zweck des Hinzufügens von Cache besteht darin, Engpässe beim Datenlesen zu reduzieren und dadurch die Systemleistung zu verbessern.

Das obige ist der detaillierte Inhalt vonZusammenfassung von Lösungen mit hoher Parallelität für PHP-Lese- und Schreibdateikonflikte. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn