2015-05-04 7 views
6

Vielleicht ist das zugrunde liegende Problem ist, wie der node-kafka Modul I hat die Dinge umgesetzt verwenden, aber vielleicht auch nicht, so hier gehen wir ...Node.js EventEmitter Ereignisse nicht teilen Ereignisschleife

Mit der Knoten-kafa Bibliothek, Ich habe ein Problem mit dem Abonnement von consumer.on('message') Veranstaltungen. Die Bibliothek verwendet das Standardmodul events, daher denke ich, dass diese Frage generisch genug sein könnte.

Meine eigentliche Code-Struktur ist groß und kompliziert, also hier ist ein Pseudo-Beispiel des grundlegenden Layouts, um mein Problem hervorzuheben. (Hinweis: Dieser Code-Schnipsel ist nicht getestet, so könnte ich Fehler hier, aber die Syntax ist nicht in Frage hier sowieso)

var messageCount = 0; 
var queryCount = 0; 

// Getting messages via some event Emitter 
consumer.on('message', function(message) { 
    message++; 
    console.log('Message #' + message); 

    // Making a database call for each message 
    mysql.query('SELECT "test" AS testQuery', function(err, rows, fields) { 
     queryCount++; 
     console.log('Query #' + queryCount); 
    }); 
}) 

Was ich sehe hier ist, wenn ich meine Server zu starten, gibt es 100.000 oder so rückständige Nachrichten, die Kafka mir geben will, und zwar durch den Event-Emitter. Also fange ich an, Nachrichten zu bekommen. Das Abrufen und Protokollieren aller Nachrichten dauert ungefähr 15 Sekunden.

Dies ist, was ich für eine Ausgabe unter der Annahme der mysql Abfrage ist ziemlich schnell zu sehen erwarten würde:

Message #1 
Message #2 
Message #3 
... 
Message #500 
Query #1 
Message #501 
Message #502 
Query #2 
... and so on in some intermingled fashion 

Ich würde erwarten, dass dies, weil mein erstes mysql Ergebnis sollte bereit sein, sehr schnell, und ich würde erwarten, dass das Ergebnis (s) um in der Ereignisschleife an die Reihe zu kommen, um die Antwort verarbeiten zu lassen. Was ich eigentlich bin immer ist:

Message #1 
Message #2 
... 
Message #100000 
Query #1 
Query #2 
... 
Query #100000 

ich jede einzelne Nachricht bekommen, bevor eine mysql Antwort der Lage ist, verarbeitet werden. Also meine Frage ist, warum? Warum kann ich nicht ein einziges Datenbankergebnis abrufen, bis alle Nachrichtenereignisse abgeschlossen sind?

Ein weiterer Hinweis: Ich habe einen Knickpunkt bei .emit('message') in Node-Kafka und bei mysql.query() in meinem Code und ich treffe sie rundenbasierte. So scheint es, dass alle 100.000 emittiert werden, stapeln sich nicht vor dem Eintritt in meinen Ereignisteilnehmer. So ging meine erste Hypothese über das Problem.

Ideen und Wissen würde sehr geschätzt :)

+0

Was passiert, wenn Sie die Anzahl der gespeicherten Nachrichten auf eine viel größere Zahl erhöhen?Ist es möglich, dass dein MySQL so langsam ist? – Avery

+0

@Avery Ich hatte mich das gewundert, aber wenn ich dies replizieren mit nur einer einzigen Nachricht zu verarbeiten, kann ich nicht einmal die Verzögerung für die MySQL-Antwort wahrnehmen. Dies läuft alles auch lokal. Und die eigentliche mysql-Abfrage ist extrem einfach (nur ein SELECT für ~ 8 Felder aus einer einzelnen Tabellenzeile und diese Tabelle hat jetzt nur noch 60 Zeilen) –

+0

Wenn dieses Beispiel tatsächlich für Ihren Code steht, dann bin ich auch verloren . Können Sie dieses Ergebnis tatsächlich mit diesem Beispiel erzeugen? Ich habe keine MySQL-Instanz zum Testen zur Verfügung. – Avery

Antwort

2

Der node-kafka-Treiber verwendet eine recht liberale Puffergröße (1M), was bedeutet, dass es so viele Nachrichten von Kafka erhalten, die in den Puffer passen. Wenn der Server zurückgestaut ist, kann dies (abhängig von der Nachrichtengröße) bedeuten, dass (mehrere zehntausend) Nachrichten mit einer Anfrage eingehen.

Da EventEmitter synchron ist (die Knotenereignisschleife wird nicht verwendet), bedeutet dies, dass der Treiber (mehrere zehntausend) Ereignisse an seine Listener sendet, und da er synchron ist, wird er nicht an die Knotenereignisschleife, bis alle Nachrichten zugestellt wurden.

Ich glaube nicht, dass Sie die Flut von Eventlieferungen umgehen können, aber ich denke nicht, dass speziell die Event Delivery problematisch ist. Das wahrscheinlichere Problem ist das Starten einer asynchronen Operation (in diesem Fall eine MySQL-Abfrage) für jedes Ereignis, wodurch die Datenbank mit Abfragen überflutet wird.

Eine mögliche Problemumgehung wäre, eine Warteschlange zu verwenden, anstatt die Abfragen direkt von den Ereignishandlern auszuführen. Mit async.queue können Sie beispielsweise die Anzahl gleichzeitiger (asynchroner) Tasks begrenzen. Der "Worker" -Teil der Warteschlange würde die MySQL-Abfrage ausführen, und in den Ereignishandlern würden Sie die Nachricht lediglich in die Warteschlange schieben.

+0

Danke @robertklep. Ich werde die async-Warteschlange versuchen. Ich übergebe meine eigene Warteschlange, so dass es nur eine mysql-Abfrage gibt und mem-caching die Ergebnisse für die wartenden Anfragen verwendet, aber ich vermute, dass ein gut gepflegtes/getestetes Modul besser sein wird :) –

Verwandte Themen