Ich bin ein Neuling in Datenbanken, habe aber ein Problem, das ich anscheinend nicht herausfinden kann. Sorry im Voraus, wenn dies zu lange ist, versuche ich alle meine Bemühungen zusammenzufassen, damit Sie genau wissen, was ich bisher gemacht habe. Ich habe eine App, die Logik enthält und dann 3 Abfragen an eine Datenbank. Die erste Abfrage prüft, ob ein Wert existiert, der zweite prüft, ob ein anderer (relatierter) Wert existiert und der dritte, falls nicht vorhanden, fügt einen verwandten Wert hinzu. Denken Sie an mich, eine Abfrage auf der Nummer 2, und wenn es existiert, überprüfe ich für 3 und füge es bei Bedarf hinzu. Ich mache diese Schleife eine große Anzahl von Zeiten (Ich schaue auf allgemeine Abfragen, aber ich vermute, dass dieses Programm mehr lesen als Schreiben ist). Ich habe in meinem Programm nur eine Hashtabelle verwendet, aber da ich mehrere Prozeduren hinzugefügt habe, hatte ich Probleme mit der Synchronisierung, also entschied ich mich, eine Datenbank zu verwenden, damit mehrere Kerne gleichzeitig damit arbeiten können.
Zuerst habe ich versucht, mysql und verwendet eine Speicher-Engine (es könnte alles in den Speicher passen), machte einen zusammengesetzten Primärschlüssel das Wörterbuch in meinem Programm zu replizieren, indexierte es, deaktivierte Sperren, aber ich konnte nur um 11.000 Abfragen / Sekunde davon.
Ich versuchte dann redis (hörte, es war wie Memcache) und erstellt das gleiche Schlüssel / Wert-Diktat, das ich vorher hatte (hier ist der aktuelle Modus Kann ich zwei Spalten für einander einzigartig machen? Oder verwenden Sie zusammengesetzte Primärschlüssel in redis? ) und entfernte alle fsync-sachen, so dass es hoffentlich niemals auf harddrive i / o geht, aber ich bekomme immernoch nur etwa 30.000 anfragen / sekunde. Ich habe Systemverbesserungen betrachtet (ich benutze Linux), indem ich das Programm in einem Ramdrive usw. ausführen lasse, aber immer noch ein ähnliches Ergebnis.
Ich habe ein Setup-Skript und habe versucht, dies auf ec2 mit der High-CPU-Instanz zu tun, aber das Ergebnis ist ähnlich (Abfragen steigen für beide Lösungen nicht viel). Ich bin irgendwie am Ende meines Verstandes, aber ich möchte nicht aufgeben, weil ich von Leuten auf Stackoverflow lese und darüber spreche, wie sie 100.000k + Anfragen auf einem Standalone bekommen haben. Ich fühle, dass mein Datamodel sehr einfach ist (zwei Spalten von INT oder I können es zu einer Zeichenkette machen, wobei beide INTs kombiniert sind, aber das schien nicht zu verlangsamen) und sobald die Daten erzeugt (und von einem anderen Prozess abgefragt) habe ich keine Notwendigkeit für Persistenz (weshalb ich auch versuche, nicht auf eine Festplatte zu schreiben). Was für ein Setup fehlt mir, damit Entwickler diese Art von Leistung bekommen können? Ist außerhalb der Tabellenerstellung eine spezielle Konfiguration erforderlich? oder ist der einzige Weg, um diese Art von Leistung durch verteilte Datenbanken zu erhalten? Ich weiß, das Problem ist mit der Datenbank, weil, wenn ich die Datenbank Mitte Prozess herunterfahren meine Python-App trifft 100% auf jeden Kern läuft (obwohl es nichts schreibt), macht es mich denken, dass der Prozess des Wartens (für die liest, Ich vermute) ist, was es verlangsamt (ich habe viel CPU / Speicher frei, also frage ich mich, warum es nicht maximiert, ich habe 50% CPU und 80% meines Gedächtnisses frei während dieser Jobs, also habe ich keine Ahnung was los ist).
Ich habe mysql, redis und hbase. hoffentlich gibt es etwas, was ich tun kann, um eine dieser Lösungen so schnell arbeiten zu lassen, wie ich möchte, aber wenn es nicht geht, bin ich mit jeder Lösung in Ordnung (es ist wirklich nur eine temporäre Hashtabelle, die verteilte Prozeduren abfragen können) >
Was kann ich tun?
Danke!
Update: wie in den Kommentaren gefordert, hier ist ein Code (nach der spezifischen Anwendungslogik, die scheinbar gut läuft):
%Vor%oben ist der Code mit 3 Nachschlagen auf mysql. Ich habe auch versucht, einen großen Nachschlag zu machen (aber es war tatsächlich langsamer):
%Vor%Hier ist das Tabellendesign auf mysql:
%Vor%auf Redis, der Simlair zur 3-Abfrage-Struktur (da es das schnellste war, das ich auf mysql bekommen konnte, außer ich brauche keine Suche, wenn der Wert existiert, überschreibe ich es einfach, um eine Abfrage zu speichern):
%Vor%Meine Datenstruktur für redis ist in der verknüpften Frage (im Grunde ist es eine Liste, 3 = & gt; 1 2 3 anstelle von mysql mit 3 Zeilen zu repersent 3 = 1, 3 = 2, 3 = 3.
Hoffen Sie, dass das hilft, andere Fragen lassen Sie es mich wissen.
Betrachtet man die bereitgestellten Code-Snippets, würde ich sagen, dass hier der Haupt-Engpass die Netzwerk- oder TCP-Loopback-Roundtrips sind. Sowohl MySQL als auch Redis sind synchrone Client / Server-Speicher. Jedes Mal, wenn Sie eine Abfrage senden und auf die Antwort warten, bezahlen Sie für die Kernel-Planung, die Netzwerklatenz, die Trefferquote des CPU-Cache usw. ...
Die Personen, die auf TCP-Servern Hunderttausende von Abfragen pro Sekunde ausführen, verwenden keinen einzelnen Socket als Ziel für den Server, sondern mehrere Verbindungen für die clientseitige Parallelität und / oder pipeline ihre Abfragen , um die Auswirkungen dieser Latenz zu begrenzen.
Wenn Sie tatsächlich einen eindeutigen Socket haben und Ihre Abfrage nacheinander ohne Pipeline-Verarbeitung senden, messen Sie nicht den maximalen Durchsatz, den Sie mit einem Server erreichen können, sondern die Latenz des Netzwerks oder der IPCs.
Hoffentlich unterstützen die von den meisten NoSQL-Servern verwendeten Protokolle normalerweise das Pipelining. Hier also einige Hinweise für eine Redis-Implementierung.
Vielleicht möchten Sie zuerst die Redis-Benchmarkseite lesen . Alle typischen Leistungsengpässe, die beim Benchmarking von Redis auftreten können, werden beschrieben.
Hier ein paar Tipps, um den maximalen Durchsatz für Ihren Benchmark zu erreichen:
Ich habe einen einfachen Test mit mandeis (C Redis client) ausgeführt, um Ihren Anwendungsfall auf einem Xeon [email protected] zu simulieren. Code kann hier gefunden werden.
%Vor%Das Programm implementiert einen ähnlichen Code, der die Abfragen pipelinet. Es stapelt Elemente und sendet eine Reihe von sismember-Befehlen, um zu wissen, ob die Elemente vorhanden sind oder nicht, und dann eine Reihe von sadd-Befehlen für die Elemente, die hinzugefügt werden müssen.
Ergebnisse:
Die Auswirkungen von Unix-Domain-Sockets sind also hoch, wenn die Roundtrips nicht optimiert sind, und sie werden sehr niedrig, sobald Pipelining verwendet wird. Der größte Teil des Gewinns ist auf Pipelining zurückzuführen. Deshalb sollten Sie sich zuerst auf Software / Protokoll-Optimierungen konzentrieren.
Die Ergebnisse können durch Optimieren der System- / Netzwerkkonfiguration weiter verbessert werden. Der nächste Schritt, um mehr Durchsatz zu erzielen, besteht normalerweise darin, mehrere Redis-Instanzen auszuführen und die Daten mithilfe eines Hashing-Mechanismus zu zerlegen (serverseitig zu parallelisieren).