Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Best practice für Nachrichten-Logger: Viele Nachrichten performant *und* ohne Datenverlust speichern
andski
myCSharp.de - Member



Dabei seit:
Beiträge: 9

Themenstarter:

Best practice für Nachrichten-Logger: Viele Nachrichten performant *und* ohne Datenverlust speichern

beantworten | zitieren | melden

Hallo,

ich will aus Interesse einen Logger implementieren. Folgendes muss gehen:
  • Nachrichten in eine Datei schreiben.
  • Möglichen Datenverlust minimieren. Das heisst, im Falle eines Absturzes sollen nicht die letzten 200 Meldungen verloren gehen. Der Logger muss also fast jede Nachricht sofort in die Datei schreiben.
  • GUI darf in ihrer Performance nicht beeinflusst werden.


Mein bisheriger Ansatz besteht darin, dass die Logger-Klasse einen Writer-Thread startet, der 10 mal pro sekunde alle Nachrichten in der Queue in die Datei schreibt. Probehalber habe ich das mit einer Schleife mit 100.000 Iterationen getestet. Jeder Durchlauf ruft einmal die log()-Funktion auf. Im Hintergrund läuft der Writer-Thread und schreibt die Datei. Das Ganze dauert etwa 0.5 sekunden.

Offenkundiges Problem: In der Zeit, in der der Writer-Thread schläft wird die Queue gefüllt. Stürzt das Programm jetzt ab, sind die letzten x-Tausend Meldungen weg. Nicht Gut.

Um dies zu "lösen" müsste also jede Nachricht sofort in die Datei geschrieben werden. Das ging bisher jedoch nur auf Kosten der Performance. 100.000 Einträge dauerten somit ca. 15 Sekunden.

Ich habe mir mal eine kleine Test-Applikation gebaut, die log4net verwendet. Für 100.000 Logs brauchte ich so ebenfalls 0.5 Sekunden. Allerdings weiss ich nicht wie das dort implementiert wurde.

Mir ist bewusst, dass 100.000 Nachrichten in so extrem kurzer Zeit in den meisten Fällen kaum geloggt werden müssen. Jedoch interessiert es mich, wie man an diese Sache heran gehen kann, um bei sehr guter Performance möglichst jede Meldung sofort zu loggen.

Bitte deshalb um Rat und bin dankbar für Hinweise.

Gruß
Andski
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von andski am .
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo andski,

du könntest den Logger als separaten Prozess implementieren. Die eigentliche Anwendung würde die Nachrichten dann z.B. per TCP/IP an den Logger schicken. Der würde deine performante Logging-Variante implementieren. Natürlich müsste nach jeder Nachricht die TCP/IP-Verbindung geflushed werden. Stürzt die eigentliche Anwendung ab, kann der Logger trotzdem noch in Ruhe die letzten Nachrichten in die Datei schreiben. Bei einem Absturz des Loggers wären die letzten Nachrichten zwar weg, aber so ein Absturz ist dafür viel unwahrscheinlicher.

herbivore
private Nachricht | Beiträge des Benutzers
andski
myCSharp.de - Member



Dabei seit:
Beiträge: 9

Themenstarter:

beantworten | zitieren | melden

Hallo,

an so eine Lösung habe ich noch gar nicht gedacht.
Aber gibt es auch eine Möglichkeit, den Logger als Klasse direkt im Program zu implementieren, sodass bei einer sehr großen Nachrichtenflut möglichst jede Nachricht sofort in die Datei geschrieben wird? Die Probleme hierbei sind also einmal dass sich schneller neue Nachrichten anhäufen, als geschrieben werden können (es sei denn man schreibt eine Menge Nachrichten mit einem Mal, was aber wieder zu Datenverlust führen kann).

Gruß
andski
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo andski,

den Trade Off, wenn du den Logger innerhalb des zu loggenden Prozesses implementierst, hast du doch schon geschildert. Mir ist nicht klar, was du dir da noch für Alternativen versprichst. Also ich wüsste nicht, was es zwischen a) Nachrichten sammeln und auf einen Rutsch schreiben und dafür den möglichen Verlust, der gesammelten und noch nicht geschriebenen Nachrichten hinnehmen oder b) jede Nachricht einzelne schreiben und dafür die schlechtere Performance hinnehmen, noch für Alternativen geben soll.

Natürlich ist das ständige Schreiben einzelner kleiner Datenhäppchen auf eine mechanisch-magnetische Festplatte per se langsam. Eine Ramdisk könnte das beschleunigen.

herbivore
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 966

beantworten | zitieren | melden

Hi,

Datenbanken haben ein ähnliches Problem:
* es finden viele parallele Lese- und Schreibvorgänge statt
* ein Schreibprozess schreibt die modifizierten, im Speicher liegenden Blöcke zurück wenn die IO-Last es erlaubt
* damit Transaktionen aber nicht verloren gehen (was committed ist bleibt auch nach einem Crash erhalten) müssen alle Änderungen erst einmal in einem hocheffizienten Log geschrieben werden um bei einem Crash daraus den korrekten Datenzustand wieder herstellen zu können (steal-no-force Strategie)

Möglicherweise könnte man sich da etwas abschauen wie es die verschiedenen DBMS es implementieren.
private Nachricht | Beiträge des Benutzers
weismat
myCSharp.de - Member



Dabei seit:
Beiträge: 878
Herkunft: Frankfurt am Main

beantworten | zitieren | melden

Erstmal würde ich einen Standardlogger wie log4net benutzen.
Bei log4net koennte dann ein udp oder Tcp Appender benutzt werden kombiniert mit einem eigenen Programm, dass die Daten von dem Appender dann persistent macht und zum Beispiel dann als ein eigener Prozess mit eigenen Queues, eigenem Flush etc. arbeitet.
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von weismat am .
private Nachricht | Beiträge des Benutzers
mogel
myCSharp.de - Member

Avatar #avatar-3347.jpg


Dabei seit:
Beiträge: 158

beantworten | zitieren | melden

Zitat von andski
Um dies zu "lösen" müsste also jede Nachricht sofort in die Datei geschrieben werden. Das ging bisher jedoch nur auf Kosten der Performance. 100.000 Einträge dauerten somit ca. 15 Sekunden.

Da Du keinen Quelltext postest, vermute ich mal:
  1. log() - Aufruf
  2. Log-Datei öffnen
  3. Seek an das Ende
  4. Meldung schreiben
  5. Datei schließen


Das kostet richtig Ressourcen. Richtig wäre: Log-Datei am Programm Anfang öffnen, und nach jeder Meldung gleich flushen, Log-Datei nie schließen. Läuft bei mir nach diesem Prinzip seit Jahren.

Damit wirst Du auch keine Meldung verlieren.

Hand, mogel
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7581
Herkunft: Waidring

beantworten | zitieren | melden

Hallo andski,

wie herbivore schon vorgeschlagen hat, würde ich auch eine weiteren Prozess für das eigentliche Loggen verwenden und für die Kommunikation MSMQ verwenden, da so die Verlust-Wahrscheinlichkeit von Meldungen geringer ist. Siehe hierzu z.B. HowTo: Messaging mit MSMQ, ein Einstieg.

mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
private Nachricht | Beiträge des Benutzers
Ahrimaan
myCSharp.de - Member



Dabei seit:
Beiträge: 363
Herkunft: Thorn

beantworten | zitieren | melden

Hallo gfoidl,

genau das würde ich auch vorschlagen, wenn jmd in MSMQ die Nachrichten nicht abholt (Prozess stürzt ab) bleiben die in der Pipeline.
Dann kann der Prozess neu starten und alles abgeholt werden.
private Nachricht | Beiträge des Benutzers
andski
myCSharp.de - Member



Dabei seit:
Beiträge: 9

Themenstarter:

beantworten | zitieren | melden

Hallo und Danke an eure Vorschläge.

@mogel: Es läuft momentan so, wie Du es vermutet hast: Datei öffnen, schreiben, schließen.
Die Variante mit dem Prozess klingt noch einen Tick sicherer. Ich werde es mal so machen.

Gruß
andski
private Nachricht | Beiträge des Benutzers