Über ein FIFO anmelden und dann in eine Datei umleiten?

8

Ich habe eine Anwendung, die jede Transaktion protokollieren muss. Jede Protokollnachricht wird gelöscht, da aufgezeichnet werden muss, was zu einem Absturz geführt hat. Meine Kollegen und ich waren neugierig, wie die Leistungseffekte der Pufferung erzielt werden können, während gleichzeitig sichergestellt wird, dass die Protokollnachricht den Prozess verlassen hat.

Was wir uns ausgedacht haben, ist:

  • Erstellen Sie ein FIFO, in das die Anwendung schreiben kann, und
  • Leiten Sie den Inhalt dieses FIFO über in eine reguläre Datei um cat.

Das heißt, was normalerweise war:

app --logfile logfile.txt

ist jetzt:

mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

Gibt es Fallstricke bei diesem Ansatz? Es hat funktioniert, als wir es getestet haben, aber wir möchten unbedingt sicherstellen, dass die Nachrichten auch dann in die Umleitungsdatei gelangen, wenn die ursprüngliche Anwendung abstürzt.

(Wir haben keinen Quellcode für die Anwendung, daher kommen Programmierlösungen nicht in Frage. Außerdem schreibt die Anwendung nicht darauf stdout, sodass eine direkte Weiterleitung an einen anderen Befehl nicht in Frage kommt. Dies syslogist also keine Möglichkeit .)


Update: Ich habe ein Kopfgeld hinzugefügt. Die akzeptierte Antwort beinhaltet nichtlogger den einfachen Grund, loggernach dem ich nicht gefragt habe. Wie die ursprüngliche Frage besagt, suche ich nur nach Fallstricken bei der Verwendung eines FIFO.

Chrisaycock
quelle
In einigen der bisherigen Antworten scheint es eine immense Verwirrung zu geben. Wie ich ursprünglich in meiner Frage hervorgehoben hatte, suche ich nach Fallstricken für den Ansatz, ein FIFO als Protokollierungsvermittler zu verwenden . Ich bin nicht an alternativen Vorschlägen interessiert, die zumindest die Fallstricke meiner ursprünglichen Frage nicht untersuchen.
Chrisaycock
Wenn meine Antwort zur Protokollierung bei stdout keine Richtung ist, an der Sie interessiert sind, können Sie dann möglicherweise "Außerdem schreibt die Anwendung nicht in stdout, sodass eine direkte Weiterleitung an einen anderen Befehl nicht in Frage kommt" aus der Frage entfernen.
Nickgrim

Antworten:

6

Beachten Sie, dass bei der Programmierung normalerweise ein FIFO erforderlich ist, bei dem der eingegebene Betrag den ausgelesenen Betrag übersteigen kann.

Als solches funktioniert ein Fifo nicht ganz reibungslos, wie Sie es erwarten, sondern würde Ihr Hauptproblem lösen, während Sie ein anderes einführen.

Es gibt drei mögliche Einschränkungen.

  1. Das Schreiben in das Fifo wird auf unbestimmte Zeit blockiert, wenn bei der Initialisierung nichts das andere Ende liest.
  2. Das FIFO hat eine feste Breite von 64 KB. Wenn der Puffer bis zu diesem Punkt gefüllt ist, werden weitere Schreibvorgänge blockiert, bis der Leser aufgeholt hat.
  3. Der Pfeifenschreiber wird mit SIGPIPE getötet, wenn der Leser stirbt oder verlässt.

Dies bedeutet, dass Ihr Problem (emulierte gepufferte E / A bei einem nicht gepufferten Schreibvorgang emulieren) behoben wird. Dies liegt daran, dass das neue "Limit" für Ihr FIFO tatsächlich die Geschwindigkeit des Dienstprogramms ist, das in der Pipe auf die Festplatte schreibt (was vermutlich gepufferte E / A sein wird).

Trotzdem ist der Schreiber abhängig von Ihrem Protokollleser, um zu funktionieren. Wenn der Leser plötzlich aufhört zu lesen, blockiert der Schreiber. Wenn der Reader plötzlich beendet wird (nehmen wir an, Sie haben nicht mehr genügend Speicherplatz auf Ihrem Ziel), wird der Writer SIGPIPE und wahrscheinlich beendet.

Ein weiterer zu erwähnender Punkt ist, dass Sie bis zu 64.000 Daten in diesem Puffer verlieren können, wenn der Server in Panik gerät und der Kernel nicht mehr reagiert.

Eine andere Möglichkeit, dies zu beheben, besteht darin, Protokolle in tmpfs (/ dev / shm unter Linux) zu schreiben und die Ausgabe an einen festen Speicherort zu senden. Es gibt weniger restriktive Beschränkungen für die Speicherzuweisung (nicht 64 KB, normalerweise 2 GB!), Funktioniert jedoch möglicherweise nicht für Sie, wenn der Writer keine dynamische Möglichkeit zum erneuten Öffnen von Protokolldateien hat (Sie müssten die Protokolle regelmäßig von tmpfs bereinigen). Wenn der Server bei dieser Methode in Panik gerät, können Sie VIEL mehr Daten verlieren.

Matthew Ife
quelle
Das sind einige gute Informationen zu /dev/shm. Wir hatten auch darüber nachgedacht, obwohl es mir durch den Kopf gegangen war, es zu benutzen tail -f.
Chrisaycock
4
mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

Was passiert, wenn Ihr cat logfifoProzess stirbt, jemand ihn versehentlich tötet oder jemand ihn versehentlich auf den falschen Ort zeigt?

Meine Erfahrung ist, dass die appschnell blockieren und hängen. Ich habe dies mit Tomcat, Apache und einigen kleinen selbst erstellten Anwendungen versucht und bin auf dasselbe Problem gestoßen. Ich habe nie sehr weit nachgeforscht, weil loggeroder eine einfache E / A-Umleitung das getan hat, was ich will. Normalerweise brauche ich die Vollständigkeit der Protokollierung nicht, was Sie anstreben. Und wie Sie sagen, Sie wollen keinen Logger.

Es gibt einige Diskussionen zu diesem Problem bei nicht blockierendem Linux-Fifo (On-Demand-Protokollierung) .

Stefan Lasiewski
quelle
Interessant. Also könnte die App trotzdem blockieren? Wir denken daran, das Handtuch zu werfen und Fusion IO an dieser Stelle zu bestellen.
Chrisaycock
Versuche es. Für mich war dieses Ergebnis schnell (in einer Testumgebung auf Hardware mit niedriger Spezifikation). Dies war unter Ubuntu und RedHat 5. Ich bin mir nicht sicher, ob FreeBSD usw. ein ähnliches Verhalten aufweisen.
Stefan Lasiewski
2

Ihre Optionen sind durch die App ziemlich eingeschränkt, aber was Sie getestet haben, wird funktionieren.

Wir machen etwas Ähnliches mit Lack und Varnishncsa, um Protokolle an einem für uns nützlichen Ort abzurufen. Wir haben ein Fifo und lesen es einfach mit syslog-ng und senden es dorthin, wo wir es brauchen. Wir verarbeiten ungefähr 50 GB und sind bisher auf kein Problem mit diesem Ansatz gestoßen

Schmiere
quelle
Cool, froh zu hören, dass wir nicht die einzigen sind, die sich das einfallen lassen.
Chrisaycock
2

Die Umgebung ist CentOS und die Anwendung schreibt in eine Datei ...

Anstatt an eine reguläre Datei zu senden, würde ich die Ausgabe an syslog senden und sicherstellen, dass Syslog-Nachrichten sowohl an einen zentralen Server als auch lokal gesendet werden.

Sie sollten in der Lage sein, ein Shell-Skript wie das folgende zu verwenden:

logger -p daemon.notice -t app < fifo

Sie können auch Eingaben loggervon catoder nach tail -fin eine Pipe übernehmen:

tail -f fifo | logger ...
cat fifo | logger ...

Das einzige Problem ist, dass es nicht nach der Wichtigkeit der Protokollnachricht differenziert (alles ist HINWEIS ), sondern zumindest protokolliert und auch außerhalb des Hosts an einen zentralen Server gesendet wird.

Die Konfiguration von Syslog hängt davon ab, welchen Server Sie verwenden. Es gibt rsyslogund syslog-ng(beide sehr fähig).

BEARBEITEN : Überarbeitet, nachdem weitere Informationen vom Poster erhalten wurden.

Mei
quelle
Die Protokollnachrichten werden in eine Datei geschrieben, die wir auswählen können, in die die Anwendung jedoch nicht schreibt stdout. Das Betriebssystem ist CentOS (ich hatte die Frage als Linux markiert , aber ich denke, das ist leicht zu übersehen). Alle Nachrichten sind gleich wichtig, daher gibt es in dieser Anwendung keinen Unterschied zwischen einem Hinweis und einem Fehler.
Chrisaycock
Kein Unterschied zwischen einem Hinweis und einem Fehler? Oh wirklich ? Kein Unterschied zwischen Slow query detectedund Database halted?
Mei
(Ich habe den Beitrag aktualisiert.)
Mei
1

Du schreibst:

Außerdem schreibt die Anwendung nicht an stdout...

Haben Sie versucht, sich in der "Datei" /dev/stdoutanzumelden? Das könnte Ihnen Folgendes ermöglichen:

app --logfile /dev/stdout | logger -t app
Nickgrim
quelle
Unterscheidet sich das von einem FIFO? Was sind die Fallstricke? Ich suche per se keine Alternative ; Ich suche nach Erkenntnissen darüber, ob der von mir aufgeführte Ansatz robust ist. Das ist alles, was mich interessiert.
Chrisaycock
1
Ja, es ist anders als bei einem FIFO. Es ist im Wesentlichen eine Datei, die mit STDOUT verbunden ist. Damit können Sie sich bei STDOUT und von dort bei Syslog oder ähnlichem anmelden. Es ist als Lösung für Ihr ursprüngliches Problem gedacht, aber hoffentlich robuster als ein FIFO, da weniger bewegliche Teile vorhanden sind.
Nickgrim
1

Es macht keinen Sinn, in ein Fifo zu schreiben und es dann von einem anderen Prozess in eine Datei schreiben zu lassen. Schreiben Sie einfach direkt in die Datei und sobald die write()Rückkehr erfolgt, liegt sie in den Händen des Kernels. Es wird weiterhin auf die Festplatte geschrieben, wenn die Anwendung abstürzt.

psusi
quelle
Jede Protokollnachricht wird gelöscht : Diese blockieren Schreibvorgänge. Wir haben keine Kontrolle darüber, da wir nicht über den Quellcode der Anwendung verfügen.
Chrisaycock
@chrisaycock, richtig ... also wo ist das Problem?
Psusi
Meine Kollegen und ich waren neugierig, wie die Leistungseffekte der Pufferung erzielt werden können, während gleichzeitig sichergestellt wird, dass die Protokollnachricht den Prozess verlassen hat.
Chrisaycock
@chrisaycock, ohh, also verwendet die Anwendung derzeit O_SYNC oder fsync()wartet, bis jeder Schreibvorgang auf die Festplatte gelangt , und Sie möchten nicht, dass dies geschieht (riskieren Sie einen Verlust im Falle eines Systemabsturzes)?
Psusi
1
@chrisaycock, es hat nichts mit der Schnittstelle des Laufwerks zu tun, es bedeutet normalerweise nur, dass der Kernel es in den Dateisystem-Cache (und aus der Anwendung) kopiert hat. Wie ich ursprünglich in meiner Antwort sagte write(), kann die App nach der Rückkehr nach Belieben abstürzen - die Daten gelangen auf die Festplatte, solange der Kernel nicht abstürzt.
Psusi