2016-02-18 34 views
27

ich eine CIFS-Freigabe haben von Windows Server 2012 R2 wie diesePHP file_exists gibt manchmal falsch für eine Datei auf CIFS-Freigabe

/etc auf Ubuntu 14.04.2 LTS (3.13.0-61-generic-Kernel) montiert/fstab

//10.1.2.3/Share /Share cifs credentials=/root/.smbcredentials/share_user,user=share_user,dirmode=0770,filemode=0660,uid=4000,gid=5000,forceuid,forcegid,noserverino,cache=none 0 0 

Die gid=5000 zur Gruppe entspricht, die eine www-data PHP Prozess ausgeführt wird.

Die Dateien werden ordnungsgemäß installiert, wenn ich über die als Benutzer www-data angemeldete Konsole überprüfe - sie sind lesbar und entfernbar (die Operationen, die vom PHP-Skript verwendet werden).

Das PHP-Skript verarbeitet etwa 50-70 000 Dateien pro Tag. Die Dateien werden auf dem Host-Windows-Rechner erstellt und einige Zeit später wird das auf dem Linux-Rechner laufende PHP-Skript über eine neue Datei benachrichtigt, prüft, ob die Datei existiert (file_exists), liest sie und löscht sie. Normalerweise funktioniert alles gut, aber manchmal (einige hundert bis 1-2 000 pro Tag) löst das PHP-Skript einen Fehler aus, dass die Datei nicht existiert. Das sollte niemals der Fall sein, da es nur über tatsächlich existierende Dateien informiert wird.

Wenn ich diese Dateien manuell als nicht vorhanden überprüfe, sind sie auf dem Ubuntu-Rechner korrekt zugänglich und haben ein Erstellungsdatum, bevor das PHP-Skript ihre Existenz überprüft hat.

Dann triggert ich das PHP-Skript manuell, um diese Datei aufzunehmen und sie wird ohne Probleme aufgenommen.

Was ich bereits versucht

Es gibt mehrere ähnliche Fragen, aber ich glaube, alle Ratschläge ausgeschöpft:

  • Ich habe clearstatcache() vor der Kontrolle file_exists($f)
  • Die Datei- und Verzeichnisberechtigungen sind in Ordnung (genau die gleiche Datei wird später korrekt aufgenommen)
  • Der zur Überprüfung verwendete Pfad file_exists($f) ist ein absoluter Pfad ohne Sonderzeichen - die Dateipfade sind immer von Format /Share/11/222/333.zip (mit verschiedenen Stellen)
  • I verwendet noserverino Aktien Parameter
  • Halterung verwendet I cache=none Aktien Parameter

/proc/fs/cifs/Stats/ Displays montieren als unten, aber ich weiß nicht, ob hier irgendetwas verdächtig ist. Der Anteil in Frage 2) \\10.1.2.3\Share

Resources in use 
CIFS Session: 1 
Share (unique mount targets): 2 
SMB Request/Response Buffer: 1 Pool size: 5 
SMB Small Req/Resp Buffer: 1 Pool size: 30 
Operations (MIDs): 0 

6 session 2 share reconnects 
Total vfs operations: 133925492 maximum at one time: 11 

1) \\10.1.2.3\Share_Archive 
SMBs: 53824700 Oplocks breaks: 12 
Reads: 699 Bytes: 42507881 
Writes: 49175075 Bytes: 801182924574 
Flushes: 0 
Locks: 12 HardLinks: 0 Symlinks: 0 
Opens: 539845 Closes: 539844 Deletes: 156848 
Posix Opens: 0 Posix Mkdirs: 0 
Mkdirs: 133 Rmdirs: 0 
Renames: 0 T2 Renames 0 
FindFirst: 21 FNext 28 FClose 0 
2) \\10.1.2.3\Share 
SMBs: 50466376 Oplocks breaks: 1082284 
Reads: 39430299 Bytes: 2255596161939 
Writes: 2602 Bytes: 42507782 
Flushes: 0 
Locks: 1082284 HardLinks: 0 Symlinks: 0 
Opens: 2705841 Closes: 2705841 Deletes: 539832 
Posix Opens: 0 Posix Mkdirs: 0 
Mkdirs: 0 Rmdirs: 0 
Renames: 0 T2 Renames 0 
FindFirst: 227401 FNext 1422 FClose 0 

Ein Muster, das ich glaube, ich sehe ist, dass der Fehler nur in Frage, wenn die Datei verarbeitet wurde angehoben wird bereits (gelesen und gelöscht) früher durch den PHP-Skript. Es gibt viele Dateien, die korrekt verarbeitet und später erneut verarbeitet wurden, aber ich habe diesen Fehler nie für eine Datei gesehen, die zum ersten Mal verarbeitet wird. Die Zeit zwischen der erneuten Verarbeitung variiert von 1 bis etwa 20 Tagen. Zur erneuten Verarbeitung wird die Datei unter dem gleichen Pfad auf dem Windows-Host mit aktualisiertem Inhalt einfach neu erstellt.

Was kann das Problem sein? Wie kann ich besser nachforschen? Wie kann ich feststellen, ob das Problem auf der PHP- oder OS-Seite liegt?


aktualisieren

ich die Software verschoben haben, dass die Dateien in ein Ubuntu VM erzeugt, dass die gleichen Aktien die gleiche Art und Weise montiert. Diese Komponente ist in Java codiert. Ich sehe keine Probleme beim Lesen/Schreiben in die Dateien.


Update - PHP Details

Der genaue PHP-Code ist:

$strFile = zipPath($intApplicationNumber); 

clearstatcache(); 

if(!file_exists($strFile)){ 
    return responseInternalError('ZIP file does not exist', $strFile); 
} 

Die intApplicationNumber wird ein Anforderungsparameter (zB 12345678.), Die einfach durch die auf einen Pfad verwandelt zipPath() Funktion (zB \Share\12\345\678.zip - immer ein voller Pfad).

Das Skript kann gleichzeitig mit verschiedenen Anwendungsnummern aufgerufen werden, wird jedoch nicht gleichzeitig mit derselben Anwendungsnummer aufgerufen.

Wenn das Skript fehlschlägt (gibt den 'ZIP file does not exist' Fehler zurück), wird es eine Minute später erneut aufgerufen. Wenn dies fehlschlägt, wird es dauerhaft als fehlgeschlagen markiert. Dann, in der Regel mehr als eine Stunde später, kann ich die Skript aufrufen manuell mit dem gleichen Aufruf (GET Anfrage), dass es auf der Produktion fertig ist und es funktioniert gut, die Datei gefunden wird und in der Antwort gesendet:

public static function ResponseRaw($strFile){ 
    ob_end_clean(); 
    self::ReadFileChunked($strFile, false); 
    exit; 
} 

protected static function ReadFileChunked($strFile, $blnReturnBytes=true) { 
    $intChunkSize = 1048576; // 1M 
    $strBuffer = ''; 
    $intCount = 0; 
    $fh = fopen($strFile, 'rb'); 

    if($fh === false){ 
     return false; 
    } 

    while(!feof($fh)){ 
     $strBuffer = fread($fh, $intChunkSize); 
     echo $strBuffer; 
     if($blnReturnBytes){ 
      $intCount += strlen($strBuffer); 
     } 
    } 

    $blnStatus = fclose($fh); 

    if($blnReturnBytes && $blnStatus){ 
     return $intCount; 
    } 

    return $blnStatus; 
} 

Nachdem der Client die Datei erhalten hat, benachrichtigt er den PHP-Server, dass die Datei an einen Speicherort im Archiv verschoben werden kann (mittels copy() und unlink()). Dieser Teil funktioniert gut.


STRACE Ergebnis

Nach mehreren Tagen ohne Fehler, tauchte der Fehler auf. Ich lief strace und berichtet

access("/Share/11/222/333.zip", F_OK) = -1 ENOENT (No such file or directory) 

für einige Dateien, die existieren, wenn ich ls /Share/11/222/333.zip von der Kommandozeile ausgeführt werden. Daher liegt das Problem auf Betriebssystemebene, PHP ist nicht zu verantworten.

Die Fehler traten auf, wenn die Auslastung der Festplatte auf dem Host (aufgrund anderer Prozesse) anstieg. Daher scheint @ Riskyasins Vorschlag am wahrscheinlichsten zu sein - es handelt sich um ausgelastete Ressourcen/Zeitüberschreitungen.

Ich werde versuchen, @ Miguel-Svq der Rat der überspringen der Existenz Test und einfach für fopen() sofort gehen und den Fehler dann behandeln. Ich werde sehen, ob sich etwas ändert.

+1

Gute Frage. Es ist nicht das erste Mal, dass ich so etwas als unzuverlässig empfinde. Ein Workaround, der Ihnen ein wenig hilft, könnte sein, die file_exists erneut zu versuchen und das Skript nicht sofort zu stoppen. – DanFromGermany

+0

Danke @DanFromGermany - ja, es ist eine der schmutzigen Ideen, die ich hatte - wiederhole es (auch nach einer Pause von N Sekunden), falls es sich um eine Art vorübergehenden Schluckauf handelt. Aber ich möchte wirklich verstehen, warum das passiert und es in der Wurzel reparieren. –

+3

Ich glaube nicht wirklich, dass es um PHP geht, sondern um NFS. Es kann zu Zeitüberschreitungen oder ausgelasteten Ressourcen kommen, da diese auf Vernetzung angewiesen sind. 'strace' und' tcpdump' auf beiden Seiten, um zu sehen, was tatsächlich passiert, können Ihnen Hinweise geben. Versuchen Sie auch mit Benutzer von PHP/Webserver während des Testens. – risyasin

Antwort

1

Sie können versuchen, die directio Option verwenden Caching tun inode-Daten zu vermeiden, auf Dateien auf dieser Halterung geöffnet:

//10.1.2.3/Share /Share cifs credentials=/root/.smbcredentials/share_user,user=share_user,dirmode=0770,filemode=0660,uid=4000,gid=5000,forceuid,forcegid,noserverino,cache=none,directio 0 0 
+0

Die [man page] (http://linux.die.net/man/8/mount.cifs) sagt "Diese Option wird in 3.7 veraltet sein. Benutzer sollten cache = none anstelle von neueren Kernel verwenden". Mein Kernel ist 3.13 und ich habe bereits 'cache = none'. Ist die Verwendung von directio dann sinnvoll? –

0

Dies kaum eine definitive Antwort auf mein Problem ist, sondern eine Zusammenfassung dessen, was Ich habe herausgefunden, womit ich mich arrangiert habe.

Am Ende des Problems liegt, dass es das Betriebssystem ist, das meldet, dass die Datei nicht existiert. strace Lauf zeigt gelegentlich

access("/Share/11/222/333.zip", F_OK) = -1 ENOENT (No such file or directory) 

für die Dateien, die nicht existieren (und zeigen, wenn sie mit ls aufgeführt).

Der Windows-Freigabe-Host befand sich manchmal unter hoher Festplattenbelastung. Was ich getan habe, ist eine der Freigaben zu einem anderen Host zu verschieben, so dass die Last jetzt zwischen den zwei verteilt wird. Außerdem ist die allgemeine Belastung des Systems in letzter Zeit etwas geringer. Immer wenn ich den Fehler bekomme, dass die Datei nicht existiert, wiederhole ich die Anfrage einige Zeit später und sie ist nicht mehr da.