Was ist die effizienteste Methode zum Analysieren von FIX-Protokollnachrichten in .NET?

8

Ich stieß auf diese sehr ähnliche Frage , aber das Frage ist markiert QuickFIX (die für meine Frage nicht relevant ist) und die meisten Antworten sind QuickFIX-bezogen.

Meine Frage ist breiter. Ich suche nach der effizientesten Methode zum Analysieren einer FIX-Protokoll Nachricht mit C # . Als Hintergrund besteht eine FIX-Nachricht aus einer Reihe von Tag / Wert-Paaren, die durch das ASCII <SOH> -Zeichen (0x01) getrennt sind. Die Anzahl der Felder in einer Nachricht ist variabel.

Eine Beispielnachricht könnte so aussehen:

%Vor%

Für jedes Feld werden das Tag (eine ganze Zahl) und der Wert (für unsere Zwecke ein String) durch das Zeichen '=' getrennt. (Die genaue Semantik jedes Tags ist im Protokoll definiert, aber das ist für diese Frage nicht besonders relevant.)

Es ist oft der Fall, dass Sie beim grundlegenden Parsen nur an einer Handvoll spezifischer Tags aus dem FIX-Header interessiert sind und keinen direkten Zugriff auf jedes mögliche Feld haben. Zu den Strategien, die ich in Betracht gezogen habe, gehören:

  • Verwendung von String.Split , Iteration über jedes Element und Einfügen des Tags in die Indexzuordnung in einer Hashtable - bietet vollständigen zufälligen Zugriff auf alle Felder, falls dies an einem bestimmten Punkt erforderlich ist

  • (Leichte Optimierung) Verwenden Sie String.Split , scannen Sie das Array nach relevanten Tags und setzen Sie das Tag zum Index-Mapping in einen anderen Container (nicht unbedingt eine Hashtable, da es sich um eine relativ kleine Anzahl von Elementen handelt Anzahl der Elemente ist vor dem Parsen bekannt)

  • Scannen Sie die Nachricht Feld für Feld mit String.IndexOf und speichern Sie den Offset und die Länge der Felder von Interesse in einer geeigneten Struktur

In Bezug auf die ersten beiden - obwohl meine Messungen zeigen String.Split ist ziemlich schnell, wie in die Dokumentation Die Methode weist für jedes Element des resultierenden Arrays einen neuen String zu, der beim Parsen vieler Nachrichten viel Unrat erzeugen kann. Kann jemand eine bessere Weise sehen, dieses Problem in .NET anzugehen?

BEARBEITEN:

Drei wichtige Informationen, die ich weggelassen habe:

  1. Tags sind in FIX-Nachrichten nicht unbedingt eindeutig, d. h. unter bestimmten Umständen können doppelte Tags auftreten.

  2. Bestimmte Typen von FIX-Feldern können "embedded <SOH> " in den Daten enthalten - diese Tags werden als "Daten" bezeichnet - ein Wörterbuch listet die Tag-Nummern dieses Typs auf.

  3. Die eventuelle Anforderung besteht darin, die Nachricht bearbeiten zu können (insbesondere Werte zu ersetzen).

SteveWilkinson 05.02.2011, 15:52
quelle

4 Antworten

8

Die Annahme besteht darin, dass Sie diese Nachrichten entweder über die Leitung erhalten oder wenn Sie sie von der Festplatte laden. In jedem Fall können Sie auf diese als Byte-Array zugreifen und das Byte-Array vorwärts lesen. Wenn Sie eine hohe Leistung wünschen / benötigen / benötigen, dann parsen Sie das Byte-Array selbst (für hohe Leistung verwenden Sie kein Wörterbuch der Hashtabelle von Tags und Werten, da dies im Vergleich extrem langsam ist). Das Parsen des Byte-Arrays selbst bedeutet auch, dass Sie vermeiden können, Daten zu verwenden, an denen Sie nicht interessiert sind, und Sie können das Parsen optimieren, um dies zu berücksichtigen.

Sie sollten in der Lage sein, die meisten Objektzuordnungen einfach zu vermeiden. Sie können FIX-Float-Datentypen sehr einfach und sehr schnell analysieren, ohne Objekte zu erstellen (Sie können hier mit Ihrer eigenen Version massiv double.parse übertreffen). Die einzigen, an die Sie vielleicht noch etwas mehr denken müssen, sind Tag-Werte, die Strings sind, z. Symbolwerte in FIX. Um das Erstellen von Zeichenfolgen hier zu vermeiden, können Sie eine einfache Methode zum Ermitteln eines eindeutigen Int-Bezeichners für jedes Symbol (das ein Werttyp ist) verwenden. Dies wird Ihnen wiederum dabei helfen, die Zuweisung auf dem Heap zu vermeiden.

Angepasstes optimiertes Parsen der korrekt ausgeführten Nachricht sollte QuickFix leicht übertreffen und Sie können alles ohne Garbage Collection in .NET oder Java machen.

    
Alexis 04.03.2011 12:25
quelle
3

Ich würde definitiv mit der Umsetzung Ihres ersten Ansatzes beginnen, weil es sich klar und einfach anhört.

A Dictionary<int,Field> scheint mir sehr gut zu sein, vielleicht in eine FixMessage klasse eingebunden, die Methoden wie GetFieldHavingTag(int tag) etc ... ausstellt.

Ich kenne das FIX-Protokoll nicht, aber wenn ich euch ansehe, scheint es, dass Nachrichten in der Regel kurz sind und auch die Felder, so dass die Speicherbelegung kein Problem sein sollte

>

Natürlich ist der einzige Weg, um sicher zu sein, ob ein Ansatz für Sie gut oder nicht ist, es zu implementieren und zu testen.

Wenn Sie feststellen, dass die Methode bei vielen Nachrichten langsam ist, profilieren Sie sie und finden Sie, wo / wo das Problem liegt.

Wenn Sie es nicht leicht lösen können, dann ja, ändern Sie die Strategie, aber ich möchte die Idee erzwingen, dass Sie es zuerst testen müssen, dann profilieren Sie es und ändern Sie es schließlich.

Stellen wir uns also vor, dass Sie nach Ihrer ersten Implementierung bemerkt haben, dass eine Menge String-Zuweisung Ihre Performances im Falle vieler Nachrichten verlangsamt.

Ja, ich würde einen ähnlichen Ansatz wie Ihren dritten Ansatz wählen, nennen wir ihn "on demand / faul approach".

Ich würde eine Klasse FixMessage erstellen, indem ich die String-Nachricht nehme und nichts tue, bis ein Nachrichtenfeld benötigt wird.
In diesem Fall würde ich IndexOf (oder etwas Ähnliches) verwenden, um das / die angeforderte (n) Feld (e) zu durchsuchen, wobei die Ergebnisse möglicherweise schneller gespeichert werden, falls eine andere gleiche Anforderung vorliegt.

    
digEmAll 05.02.2011 16:50
quelle
2

Ich weiß, dass dies eine Antwort auf eine ältere Frage ist - ich habe erst vor kurzem festgestellt, dass es viele FIX-bezogene Fragen zu SO gibt, also dachte ich mir, ich würde versuchen, dies zu beantworten.

Die Antwort auf Ihre Frage hängt möglicherweise von den spezifischen FIX-Nachrichten ab, die Sie tatsächlich analysieren. In einigen Fällen, ja - Sie könnten einfach einen "Split" für die Zeichenfolge ausführen, oder was Sie haben, aber wenn Sie alle im Protokoll definierten Nachrichten parsen wollen, haben Sie keine andere Wahl als zu referenzieren ein FIX-Datenwörterbuch, und die Nachricht Byte für Byte analysieren. Dies liegt daran, dass es in FIX-Nachrichten längencodierte Felder gibt - entsprechend der Spezifikation, die Daten enthalten kann, die jede Art von "Split" -Ansatz stören könnten, die Sie möglicherweise durchführen möchten.

Dies ist am einfachsten, wenn Sie auf das Wörterbuch verweisen und eine Nachrichtendefinition basierend auf dem Typ (Tag 35) der empfangenen Nachricht abrufen. Anschließend müssen Sie die Tags nacheinander extrahieren und auf die entsprechende Tag-Definition in der Nachrichtendefinition verweisen, um zu verstehen, wie die Daten analysiert werden müssen, die dem Tag zugeordnet sind. Dies hilft Ihnen auch bei "sich wiederholenden Gruppen", die in der Nachricht vorhanden sein können - und Sie werden nur verstehen können, dass ein Tag den Anfang einer sich wiederholenden Gruppe darstellt, wenn Sie die Nachrichtendefinition aus dem Wörterbuch haben.

Ich hoffe, das hilft. Wenn Sie ein Referenzbeispiel möchten, habe ich die VersaFix-Open-Source-FIX-Engine für .NET geschrieben, die einen wörterbuchbasierten Nachrichtenparser enthält. Sie können den Quellcode direkt von unserem Subversion-Server herunterladen, indem Sie Ihren SVN-Client auf:

zeigen %Vor%

Prost.

    
Russ Curry 15.11.2011 01:04
quelle
1

Sie sind wahrscheinlich besser dran, QuickFix in aller Ehrlichkeit zu verwenden und dafür einen Managed C ++ - Wrapper zu erstellen. Wenn Sie sich überhaupt mit der Latenz befassen, können Sie keine Zuordnungen als Teil des Parsens durchführen, da dies zur Ausführung des GC führen kann, der Ihre FIX-Engine unterbricht. Wenn Sie pausiert haben, können Sie keine Nachrichten senden oder empfangen, die, wie Sie sicher wissen, sehr schlecht sind.

Es gab eine Firma, die Microsoft vor ein paar Jahren hervorgehoben hatte, als sie eine FIX-Engine komplett in c # erstellte. Sie würden einen Pool von Objekten erstellen, die im Laufe des Handelstages verwendet werden, und während des Tages keine Zuteilungen vornehmen.

Ich weiß nicht, was Ihre Latenzanforderungen sind, aber für das, was ich tue, haben wir Codegen verwendet, verschiedene Arten von Multithread-Heaps, um die Performance zu verbessern und die Latenz zu reduzieren. Wir verwenden eine Mischung aus C ++ und Haskell.

Abhängig von Ihren Anforderungen können Sie Ihren Parser möglicherweise als Kernel-Modus-Treiber implementieren, damit Nachrichten so erstellt werden können, wie sie von der Leitung empfangen werden.

@Hans: 10 Mikrosekunden sind eine sehr lange Zeit. NASDAQ stimmt die Bestellungen in 98 Mikrosekunden ab, und SGX hat angekündigt, dass es 90 Mikrosekunden dauern wird, bis sie ihre neue Plattform in diesem Jahr rollen.

    
Steve Severance 08.02.2011 16:45
quelle

Tags und Links