Laden...

Womit Daten loggen für Geräteserver

Erstellt von #CPferdchen vor 8 Jahren Letzter Beitrag vor 8 Jahren 1.620 Views
#
#CPferdchen Themenstarter:in
28 Beiträge seit 2011
vor 8 Jahren
Womit Daten loggen für Geräteserver

Hallo,

im Rahmen meiner Masterarbeit arbeite ich zur Zeit an einem Geräteserver. Der Server holt sich Werte von verschiedenen Geräten wie SPS, Leistungsmessgerät, Sensoren usw. die über verschiedene Arten und Schnittstellen angebunden sind. Zum Beispiel USB, CAN, Flexray, TCP/IP.
Zum Server gehört ein Clients der definiert welche Werte von welchen Geräten er haben möchte und teilt dies dem Server mit. Der Server startet und verwaltet die GEräte und stellt dem Client die Werte zur Verfügung. Entweder direkt (eingebunden als DLL in Client App) oder über TCP/IP.
Die Datenrate mit der die Werte aus den Geräte gelesen und übertragen werden soll liegt bei einigen bei 1 oder 5 m/s meist eher 10m/s , der Datentype sollte i.d.R. ein primitiver Typ sein.

Nun möchte ich in meiner Server-Applikation ein Datenlogging/DataHistory anlegen. Dazu habe ich eine sycronisierte Queue angelegt in die Wert, Zeitpunkt und Geräte(Herkunft/Id abgelegt werden können. Nun würde ich mir einen Task anlegen der diese Queue ausließt und alles was darin ist persistent abspeichert.

Meine Anforderung:

  • wenig Performance fressend (um Datenraten einzuhalten)
  • große Datenmengen (Laufzeit des Servers über Monate)
  • alte Daten leicht löschbar (nur Werte der letzen x-Stunden/Tage)
  • leicht umgänglichen Datensystem (ungeschulte Person soll sich die Daten anschauen können und eventuell auch damit Arbeiten)
  • aufgetrenntes Speichern der Werte für verschiedene Geräte

Meine bisherigen Ideen sind:

  • SQLite (Erlaubt performante Transactions, gute Auftrennung(Tables),schon mit gearbeitet, für größere Datenmengen, gute Wartbarkait ,umgäglichkeit nur bedingt mit SQLite Browser (Installation notwendig))
  • mehrere asyncron beschriebene .data / .txt Dateien für jedes Gerät (sehr nativ,schon mit gearbeitet, schlecht wartbar auch wenn z.B. alle Stunde eine neue Datei angelgt wird, nicht so super für große Datenmengen, txt kann jeder öffnen )
  • Common Logging .Net API (gar keine Erfahrung, überhaupt sinnvoll?, Elefanten/Spatzen schießen)
  • XML (nativ, Auftrennung in einer Datei möglich, einigermassen umgänglich, Wartbarkeit auch ok)

Nun bin ich mir unsicher was ich nutzen sollte. Vorallem was die Performance angeht. Um den Punkt Umgänglichkeit zum umschiffen hab ich auch schon überlegt die Funktion einbaue aus den gespeicherten Werten eine Excel-Datei zu genieren. Am meisten bin ich von SQLite angetan, aber mein Betreuer aus oben genannten Gründen nicht 😜

Habt ihr noch andere Ideen? Oder Argumente pro SQLite?

Viele Grüße

6.911 Beiträge seit 2009
vor 8 Jahren

Hallo #CPferdchen,

wenn du eh am Server arbeitest, so kannst du dort eine richtige Datenbank verwenden. Z.B. SQL Server und dort die Daten hinschreiben.

Für die Verwaltung der Werte bzw. Umgänglichkeit erstellt du eine (einfache) Web-Anwendung und somit kann auch ein ungeschulter Benutzer die Daten manipulieren (entsprechende Rechte können vorausgesetzt werden in der Anwendung).

Über Reporting Services, usw. könnten dann auch gleich Diagramme, Berichte erstellt werden.

sycronisierte Queue angelegt in die Wert, Zeitpunkt und Geräte(Herkunft/Id abgelegt werden können. Nun würde ich mir einen Task anlegen der diese Queue ausließt und alles was darin ist persistent abspeichert.

Ob ein Task reicht od. nicht hängt von der Anwendung ab.
Alternativ kannst du auch einen Logging-Dienst erstellen und dein Programm kommuniziert mit diesem Dienst per WCF (ev. mit MessageQueue-Binding). Deine Anwendung stellt die Daten in diese "Qeueu" und der Dienst liest die Daten sicher aus und speichert diese in der Datenbank.
Ev. ist dies aber schon zuviel des Guten und ein Task reicht auch. Das musst du entscheiden.

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!"

W
872 Beiträge seit 2005
vor 8 Jahren

Ich würde Dir an Deiner Stelle Event Tracing empfehlen.
Es ist etwas komplexer als normales Logging, dafür rasend schnell - so wird es in der CLR für die Garbage Collector Statistiken benutzt.
Ich habe selber etwas dazu auf meinem Blog - Windows Event Tracing in C# - vor kurzem geschrieben.

Edit: Mit Perfview kannst Du in Excel exportieren - wichtig ist auch, daß das Sammeln und das Auswerten getrennt sind. Es gibt auch andere Tools zum Sammeln, die zum Beispiel anhand der Dateigröße rollen. Es gibt viele Möglichkeiten, aber das ganze ist nicht so einfach.

#
#CPferdchen Themenstarter:in
28 Beiträge seit 2011
vor 8 Jahren

Hallo,

Vielen Dank für eure Antworten.

wenn du eh am Server arbeitest, so kannst du dort eine richtige Datenbank verwenden. Z.B. SQL Server und dort die Daten hinschreiben.

Würde aber heißen, dass immer wenn ich ein neues System mit dem Geräteserver aufsetze ich auch einen SQL Server mit aufsetzen muss. Ein zentraler SQL Server in unserem Unternehmen wäre hier die Lösung, aber der Geräteserver soll auch isoliert vom Netz funktionieren.

Alternativ kannst du auch einen Logging-Dienst erstellen und dein Programm kommuniziert mit diesem Dienst

Das ganze als Dienst laufen zu lassen ist eine super Idee. Kannte ich als eigene Anwedung in C# bis her nicht. Wenn ich mir dieses Tutotial Windows Services mit C#so anschaue wäre das vielleicht auch was für meine TCP Client/Server Kommunikation.

Ob ein Task reicht od. nicht hängt von der Anwendung ab.

Wie meinst du das? Die Anzahl der Task oder ob ich einen Dienst verwende?

Ich würde Dir an Deiner Stelle Event Tracing empfehlen.
Es ist etwas komplexer als normales Logging, dafür rasend schnell - so wird es in der CLR für die Garbage Collector Statistiken benutzt.
Ich habe selber etwas dazu auf meinem Blog vor kurzem geschrieben.

Rasend schnell hört sich gut an 😄. Werde mal versuchen dazu eine Test Applikation zu schreiben. Hast du noch weitere nützliche Links zu dem Thema?

Ich habe gestern dieses mit SQLite gebastelt, aber euere Lösungen hören sich schneller und professioneller an.


using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Threading;
using System.Threading.Tasks;
using VB.Core.Channel;


//TODO: Erkennen und separieren der Channel auf einzelne Tables
//TODO: Eigene Spalten in den Tables statt einen String
//TODO: gescheiten Zeitstempel anlegen

namespace VB.Server
{
  public class Data
  {
    public Data (ChannelAddress channelAddress, Type channelType, object value)
    {
      ChannelAddress = channelAddress;
      ChannelType = channelType;
      Value = value;
    }

    public ChannelAddress ChannelAddress { get; set; }
    public Type ChannelType { get; set; }
    public object Value { get; set; }

    public override string ToString ()
    {
      return string.Format ("{0} | {1} | {2}", ChannelAddress, ChannelType, Value);
    }
  }

  public static class DataHistory
  {
    public static Queue SynchronizedQueue = Queue.Synchronized (new Queue (new Queue<Data> ()));
    private static readonly object _lockObject = new object ();

    public static void syncEnqueue (ChannelAddress channelAddress, Type channelType, object value)
    {
      lock (_lockObject)
      {
        SynchronizedQueue.Enqueue (new Data (channelAddress, channelType, value));
      }
    }

    public static string syncDequeue ()
    {
      lock (_lockObject)
      {
        return  (SynchronizedQueue.Dequeue ()).ToString ();
      }
    }
  }

  public class DataHistoryTask
  {
    private bool _shouldStop;
    private const int TransactionLimit = 100;

    public void Start ()
    {
      new Task (
        () =>
        {
          
          SQLiteConnection.CreateFile ("sqliteTest.db");
          SQLiteConnection sqLiteConnection = new SQLiteConnection ();
          sqLiteConnection.ConnectionString = "Data Source = sqliteTest.db; Version=3";
          sqLiteConnection.Open ();

          SQLiteCommand sqLiteCommand = new SQLiteCommand (sqLiteConnection);
          sqLiteCommand.CommandText = "CREATE TABLE IF NOT EXISTS Test (tick INTEGER NOT NULL, str VARCHAR(200) NOT NULL)";
          sqLiteCommand.ExecuteNonQuery ();

          while (_shouldStop != true)
          {
            Thread.Sleep (1000);

            if (DataHistory.SynchronizedQueue.Count < 1000)
            {
              continue;
            }

            using (var sqLiteTransaction = sqLiteConnection.BeginTransaction ())
            {
              sqLiteCommand.Connection = sqLiteConnection;
              sqLiteCommand.Transaction = sqLiteTransaction;
              int transactionCounter = 0;

              while( DataHistory.SynchronizedQueue.Count > 0 && transactionCounter < TransactionLimit)
              {          
                sqLiteCommand.CommandText = "INSERT INTO Test (tick, str) VALUES(1,'" + DataHistory.syncDequeue () + "')";
                sqLiteCommand.ExecuteNonQuery ();
                transactionCounter++;
              }
              sqLiteTransaction.Commit ();
              Thread.Sleep (1);
            }
          }
          sqLiteConnection.Close ();
        }).Start ();
    }

    public void Stop ()
    {
      _shouldStop = true;
    }
  }
}

EDIT:

 if (DataHistory.SynchronizedQueue.Count < 1000)
            {
              continue;
            }

und

  while( DataHistory.SynchronizedQueue.Count > 0 && transactionCounter < TransactionLimit)

muss ich nochmal abändern 😛

LG

W
872 Beiträge seit 2005
vor 8 Jahren

Schau Dir die Channel 9 Videos und diese Übersicht an.
Ich habe noch mehr Material als Powerpoint.

6.911 Beiträge seit 2009
vor 8 Jahren

Hallo #CPferdchen,

Wie meinst du das? Die Anzahl der Task oder ob ich einen Dienst verwende?

Ich meine das so, dass es darauf ankommt wie sehr du das Logging von der Anwendung entkoppeln willst. Mit dem separaten Dienst ist das Logging in einen eigenen Prozess - den Dienst-Prozess - ausgelagert mit allen Vor- und Nachteilen.
Wird mittels Task geloggt, so ist das Logging im selben Prozess. Wobei Logging duch Task wohl am ehesten per Producer/Consumer (siehe z.B. auch Sinnvoller Einsatz des Producer Consumer Patterns) umgesetzt wird.

Was für deine Anwendung und Anforderung besser passend ist, kann ich nicht beurteilen - das obliegt dir.

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!"

P
1.090 Beiträge seit 2011
vor 8 Jahren

Hast du mal geschaut ob eine der Standard Logger, deiner Anforderungen erfüllen.

Log4Net, z.B. bietet die Möglichkeit in Dateien, Datenbanken oder als Mail zu loggen.
(Den Verwenden ich z.B. und falls doch mal was anderes Verlangt wird, habe ich einen Wrapper um den Logger und die Faktory geschrieben (grob 10 Zeilen Code))

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern