Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden.
Du solltest ein Upgrade durchführen oder einen alternativen Browser verwenden.
Du solltest ein Upgrade durchführen oder einen alternativen Browser verwenden.
Datenbanksystem für mind. 100k Inserts / Updates pro Sekunde
- Ersteller Falc410
- Erstellt am
Piktogramm
Admiral
- Registriert
- Okt. 2008
- Beiträge
- 8.861
IP Adressen sind ja eigentlich Integer mit 32bit (v4) oder 128bit (v6). Hier wäre es eine Maßnahme die IPs direkt als Int in die Logs zu schreiben oder aber spätestens beim Einlesen der Dateien umzuwandeln. Das Umwandeln frisst einmal Rechenzeit, spart perspektivisch jedoch Laufzeit und Speicher bei weiteren Aktionen.
Wenn du Logfiles rausschreibst die +100MB groß sind. Splitte die Logs sinnvoll auf bevor du sie einliest. Ein paar tausend Einträge je Vorgang sollten reichen (4MB Chunks nutze ich oft, wenn ich keine Muse habe genauer zu rechnen =) ). Damit hält sich dann auch dein Speicherbedarf in Grenzen, wenn jeder Thread nur 4MB Rohdaten bekommt.
Bei Bulk Inserts ist es mitunter nicht sinnvoll, immer sofort in die persistenten Tabellen zu schreiben. Deswegen gibt es bei vielen DBS die Möglichkeit temporäre Tabellen anzulegen. Da kannst du schreiben, sortieren, filtern, löschen und Indizes erstellen, ohne dass es deine Haupttabellen berührt. Zudem kannst du jedem Einlesethread deines Programms eine eigene temp. Table geben. Wenn die temp Tables dann passen, kannst du sie in deine Haupttabellen werfen.
Bei der Schreiblast wäre es auch ein Experiment wert, ob es evtl. sinnvoll ist kontinuirlich neute, persistente Tabellen anzulegen. Ein Reindex auf eine Tabelle, die 14 Tage Logs enthält wird auch dicker Hardware ordentlich Zeit fressen.
Wenn du Logfiles rausschreibst die +100MB groß sind. Splitte die Logs sinnvoll auf bevor du sie einliest. Ein paar tausend Einträge je Vorgang sollten reichen (4MB Chunks nutze ich oft, wenn ich keine Muse habe genauer zu rechnen =) ). Damit hält sich dann auch dein Speicherbedarf in Grenzen, wenn jeder Thread nur 4MB Rohdaten bekommt.
Bei Bulk Inserts ist es mitunter nicht sinnvoll, immer sofort in die persistenten Tabellen zu schreiben. Deswegen gibt es bei vielen DBS die Möglichkeit temporäre Tabellen anzulegen. Da kannst du schreiben, sortieren, filtern, löschen und Indizes erstellen, ohne dass es deine Haupttabellen berührt. Zudem kannst du jedem Einlesethread deines Programms eine eigene temp. Table geben. Wenn die temp Tables dann passen, kannst du sie in deine Haupttabellen werfen.
Bei der Schreiblast wäre es auch ein Experiment wert, ob es evtl. sinnvoll ist kontinuirlich neute, persistente Tabellen anzulegen. Ein Reindex auf eine Tabelle, die 14 Tage Logs enthält wird auch dicker Hardware ordentlich Zeit fressen.
- Registriert
- Juni 2006
- Beiträge
- 6.425
Drexel schrieb:Zugegebenermaßen nur 111 Ergebniss, knapp über 1 Mio. Checks, Durchlaufzeit 0,3-0,4 Sekunden, Speicherverbrauch lt. Taskmanager 5 MB...
Das Ergebnis kann ich schlecht verifizieren da es ja random generierte IPs waren mit random generierten Netzen aber der Code sieht für mich korrekt aus. Ich hätte nicht erwartet, dass so schnell ist, du gehst ja bei jeder Zeile das Array von nets durch - d.h. mit steigender Anzahl von Subnetzen hast du hier auch mehr Iterationen und das nur um IPv4 von IPv6 zu unterscheiden. Das könnte man wahrscheinlich noch optimieren.
Und obwohl so viele Funktionen aufgerufen werden und jedes mal neue Arrays erstellt werden, scheint der Garbage Collector von C# deutlich besser zu sein.
Letztendlich sieht es so aus, als ob dein C# Code doppelt so schnell ist wie mein pypy Code. Hätte ich nicht gedacht. Aber für C# bräuchte ich wohl Mono auf den Linux Maschinen. Trotzdem cool, dass du es mal implementiert hast
@Piktogramm Die IPs kommen als Netflow rein. Theoretisch kann ich das raw öffnen und die Byte auslesen, praktisch dürfte dieser Parser aber noch ineffzienter sein. Auf die Netflows ("Logs") hab ich also keinen Einfluss.
Piktogramm
Admiral
- Registriert
- Okt. 2008
- Beiträge
- 8.861
Wenn es ein Rohdatenformat gibt, indem das Meiste als Integer steht (Date als Unixtime, IP Adressen als Int32 bzw. Int128, ...), dann musst du an sich ja eben nichts parsen[1]. Das wäre ja gerade der Witz, dass mit (fixen) Offsets und Ranges gearbeitet werden kann. An der Stelle würdest du dir auch alle Casts von String zu Integer sparen. In den aller meisten Programmiersprachen ist das einiges Fixer als das Parsen von Strings.Falc410 schrieb:@Piktogramm Die IPs kommen als Netflow rein. Theoretisch kann ich das raw öffnen und die Byte auslesen, praktisch dürfte dieser Parser aber noch ineffzienter sein. Auf die Netflows ("Logs") hab ich also keinen Einfluss.
Falls es nur menschenlesbare Datenformate gibt -> Schnellst möglich alles in die Datenbank kippen und das Parsing/Casting der Datenbankengine übergeben. Das ist normalerweise weniger Aufwand beim Implementieren und vergleichbar schnell wie handgeklöppelte Lösungen in PHP, Java, Python & Co.
[1] Je nachdem wie das Datenformat ausschaut evtl. die Unterscheidung der Protokollversion als IPv4/v6
Piktogramm hat recht. Der Code von Drexel wird die meiste Zeit für das Konvertieren der Strings zu Zahlen benötigen (IPAddress.Parse). Ich möchte nicht wissen wie viel Energie in der Welt verschwendet wird, weil immer wieder Zahlen aus textbasierten Datenformaten konvertiert werden müssen.Piktogramm schrieb:Wenn es ein Rohdatenformat gibt, indem das Meiste als Integer steht (Date als Unixtime, IP Adressen als Int32 bzw. Int128, ...), dann musst du an sich ja eben nichts parsen[1].
In Java sieht der Code fast genauso aus und sollte auch etwa genauso schnell sein.Falc410 schrieb:Aber für C# bräuchte ich wohl Mono auf den Linux Maschinen.
Drexel
Lt. Commander
- Registriert
- Jan. 2012
- Beiträge
- 1.612
Falc410 schrieb:d.h. mit steigender Anzahl von Subnetzen hast du hier auch mehr Iterationen und das nur um IPv4 von IPv6 zu unterscheiden. Das könnte man wahrscheinlich noch optimieren.
Ja mit steigender Anzahl von Netzen gibt es unter umständen mehr Schleifen, aber bei einem Treffer wird die Schleife abgebrochen. IPv4 vs IPv6 unterscheide ich eigentlich gar nicht großartig. Ich iterier einfach über alles drüber. Ich schau nur ob beide Adressen von der gleichen Version sind mit
if (nets[index].AddressFamily == compareAddress.AddressFamily),
wenn nicht spare ich mir weitere vergleiche und verwerfe das direkt.
Das einzige Array was immer wieder neu erstellt wird ist das Part Array mitFalc410 schrieb:Und obwohl so viele Funktionen aufgerufen werden und jedes mal neue Arrays erstellt werden, scheint der Garbage Collector von C# deutlich besser zu sein.
parts = line.Split(';');.
Die nets und maks Arrays bleiben erhalten.
Falc410 schrieb:Letztendlich sieht es so aus, als ob dein C# Code doppelt so schnell ist wie mein pypy Code. Hätte ich nicht gedacht. Aber für C# bräuchte ich wohl Mono auf den Linux Maschinen. Trotzdem cool, dass du es mal implementiert hast
Kann morgen auch gerne mal nen Durchlauf mit 35 Netzen machen, ne größere Demo Datei mit mehr Random Werten wären auch cool, nicht dass da irgendwas gecached wird, wenn die Werte immer die gleichen sind...
Hab das spasseshalber mal nach Java übersetzt und dabei noch eine Verbesserung gefunden. Das Parsen der compareAddress kann bereits vor der for Schleife ausgeführt werden, was die Performance nochmal deutlich verbessert.
Java:
import java.io.BufferedReader;
import java.io.FileReader;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
public class IpAddressChecker {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
InetAddress[] nets = new InetAddress[] {
InetAddress.getByName("10.0.0.0"),
InetAddress.getByName("192.168.0.0"),
InetAddress.getByName("129.127.0.0"),
InetAddress.getByName("2001:1000:0000::"),
InetAddress.getByName("195.143.10.0"),
InetAddress.getByName("195.143.17.0"),
InetAddress.getByName("195.143.22.0"),
InetAddress.getByName("195.143.43.0"),
InetAddress.getByName("140.35.128.0"),
InetAddress.getByName("151.60.48.0"),
};
InetAddress[] masks = new InetAddress[] {
InetAddress.getByName("255.0.0.0"),
InetAddress.getByName("255.255.0.0"),
InetAddress.getByName("255.255.0.0"),
InetAddress.getByName("ffff:ffff:f000::"),
InetAddress.getByName("255.255.255.0"),
InetAddress.getByName("255.255.255.0"),
InetAddress.getByName("255.255.255.0"),
InetAddress.getByName("255.255.255.0"),
InetAddress.getByName("255.255.192.0"),
InetAddress.getByName("255.255.254.0"),
};
List<String[]> result = new ArrayList<>();
int checkCounter = 0;
String line = null;
String[] parts;
BufferedReader file = new BufferedReader(new FileReader("d:/sample_data.txt"));
while ((line = file.readLine()) != null) {
parts = line.split(";");
InetAddress compareAddress = InetAddress.getByName(parts[0]);
for (int index = 0; index < nets.length; index++) {
checkCounter++;
if (nets[index].getAddress().length == compareAddress.getAddress().length) {
if (isInSameSubnet(nets[index], compareAddress, masks[index])) {
result.add(parts);
break;
}
}
}
}
System.out.println("Checks: " + checkCounter);
System.out.println("Results: " + result.size());
System.out.println("Duration: " + (System.currentTimeMillis() - start));
}
private final static boolean isInSameSubnet(InetAddress ip1, InetAddress ip2, InetAddress mask) {
byte[] a1 = ip1.getAddress();
byte[] a2 = ip2.getAddress();
byte[] m = mask.getAddress();
for (int i = 0; i < a1.length; i++)
if ((a1[i] & m[i]) != (a2[i] & m[i]))
return false;
return true;
}
}
Drexel
Lt. Commander
- Registriert
- Jan. 2012
- Beiträge
- 1.612
Jepp, da haste natürlich recht.Nolag schrieb:Das Parsen der compareAddress kann bereits vor der for Schleife ausgeführt werden, was die Performance nochmal deutlich verbessert.
Du hast aber das Skippen der ersten Zeile mit den Überschriften weggelassen, das führt zu einer Exception, wenn Du die in eine IPAdresse umwandeln willst. Zumindest in C#...
bog
Ensign
- Registriert
- Apr. 2008
- Beiträge
- 254
wenn schon, wieso nicht direkt 'nen abstecher nach C/++ machen?
https://rosettacode.org/wiki/Parse_an_IP_Address#C
dann kannst auch direkt bitweise die subnetze abchecken wie in meinem vorigen post verlinkt. laesst sich ja zur not auch schoen per p/invoke auslagern, wenn die anbindung mit C# angenehmer ist.
https://rosettacode.org/wiki/Parse_an_IP_Address#C
dann kannst auch direkt bitweise die subnetze abchecken wie in meinem vorigen post verlinkt. laesst sich ja zur not auch schoen per p/invoke auslagern, wenn die anbindung mit C# angenehmer ist.
Drexel
Lt. Commander
- Registriert
- Jan. 2012
- Beiträge
- 1.612
Der Java und C# Code hier arbeitet auch mit bitweisen Operatoren, hatte auch schon im Verdacht, dass da evtl. die bessere Performance herkommt, keine Ahnung wie die netaddr library arbeitet. Spricht natürlich generell nix dagegen, das auch in anderen Sprachen zu implementieren, aber ich denke C# und Java waren halt die Sprachen, die die jeweiligen Poster parat hatten...
- Registriert
- Juni 2006
- Beiträge
- 6.425
Das C++ schneller ist, war mir schon bewusst. Aber ich hätte nicht erwartet, dass Python bzw. diese Library so langsam ist (gerade im Vergleich zu C# und Java die auch beide nicht gerade für Performance bekannt sind).
Und ursprünglich hatte ich ja auch eher Sorge um das DBS und nicht den Code vom Script der vorher läuft. Für einen PoC reicht mir das erstmal, wenn es denn mal Produktiv gehen sollte, dann muss ich mal schauen mit was es implementiert wird.
Auf jeden Fall wieder viel gelernt und die Erkenntnis, dass die 60.000 Datensätze die pro Sekunde reinkommen nur zu einem Bruchteil überhaupt in die Datenbank wandern müssen (konnte viel aussortieren).
Und ursprünglich hatte ich ja auch eher Sorge um das DBS und nicht den Code vom Script der vorher läuft. Für einen PoC reicht mir das erstmal, wenn es denn mal Produktiv gehen sollte, dann muss ich mal schauen mit was es implementiert wird.
Auf jeden Fall wieder viel gelernt und die Erkenntnis, dass die 60.000 Datensätze die pro Sekunde reinkommen nur zu einem Bruchteil überhaupt in die Datenbank wandern müssen (konnte viel aussortieren).
new Account()
Banned
- Registriert
- Mai 2018
- Beiträge
- 7.198
Eventuell kannst du dein Python mit Cython auch zu C konvertieren.
kuddlmuddl
Commander
- Registriert
- Mai 2010
- Beiträge
- 2.672
Das C++ schneller ist, war mir schon bewusst. Aber ich hätte nicht erwartet, dass Python bzw. diese Library so langsam ist (gerade im Vergleich zu C# und Java die auch beide nicht gerade für Performance bekannt sind).
ich hab paarmal python zu c++ portiert und bin durchschnittlich ca um faktor 1000 schneller geworden damit
das kann aber nur gelingen wenn rechen- oder speicherintensive dinge in python gemacht werden
Eine operation in bibliotheken wie zb nen filter in opencv dauert immer etwa gleich lange- egal ob der aufruf von c++ oder von python aus gemacht wird
Drexel
Lt. Commander
- Registriert
- Jan. 2012
- Beiträge
- 1.612
C# oder Java sind nicht per se langsam, die Übersetzung zur Runtime von Byte zu Maschinencode vermittelt oft einen langsamen Eindruck oder schlecht gemacht GUIs. Bei so wenig Code der dann oft durchlaufen wird, fällt die Übersetzung aber nicht ins Gewicht. Ebenso wie die Garbage Collection die den Thread anhält fällt eigentlich auch wenig ins Gewicht. Wenn der Code einmal voll übersetzt ist, sind sie auch recht fix.
bog
Ensign
- Registriert
- Apr. 2008
- Beiträge
- 254
ich vermute, dass das im speziellen auf die "faktor 1000 schneller" aussage bezogen war; da stimme ich zu. und fuer C# kann ich mangels genug erfahrung nicht sprechen, aber C++ und java sind gerne mal um einen faktor 2 auseinander - das durfte ich bei manchen simulationen schon leidlicherweise erfahren.Drexel schrieb:C# oder Java sind nicht per se langsam
gerade bei rechenintensiven problemen wie dem im OP traue ich maschinennaeheren implementierungen deshalb - sei das meinetwegen durch einbindung nativen codes - durchaus einen sehr starken performancegewinn zu.
r15ch13
Lieutenant
- Registriert
- Dez. 2003
- Beiträge
- 790
Bin gerade ueber RavenDB gestolpert. Laut Marketing blabla soll die 150k writes pro Sekunde schaffen.
https://ravendb.net/features/high-performance
https://ravendb.net/features/high-performance
Piktogramm
Admiral
- Registriert
- Okt. 2008
- Beiträge
- 8.861
Solche Aussagen sind in der Regel recht wertlos, es fehlen schlicht alle notwendige Angaben um den Spaß einordnen zu können. 100.000Inserts /s bekommt man auch mit sqlite hin. Die Frage ist eher, wie das Ganze ausschaut, wenn ein paar Constraints, Trigger und Indizes mit im Spiel sind.
An der Stelle wird es haarig. Genauso wie der TE ja eigentlich kein Problem hat, dass die DB nicht performt, sondern dass er enorm viel Rechenzeit auf das (unnötige) parsen der Daten wirft.
An der Stelle wird es haarig. Genauso wie der TE ja eigentlich kein Problem hat, dass die DB nicht performt, sondern dass er enorm viel Rechenzeit auf das (unnötige) parsen der Daten wirft.
Ähnliche Themen
- Antworten
- 20
- Aufrufe
- 3.285
- Antworten
- 12
- Aufrufe
- 2.802