NSQ ist eine Echtzeit-Messaging-Plattform, die sich auf die Fahnen schreibt, hohe Verfübarkeit ohne SPOF (Single Point of Failure) zu erreichen und dabei sehr einfach zu verwenden und deployen zu sein. Gründe genug, sich das Projekt einmal genauer anzusehen.
Funktionsweise
NSQ bietet einen Publish-Subscribe-Mechanismus, der in Form von Topics und Channels umgesetzt ist. Ein Topic ist ein Datenstrom, der wenigstens einen Channel hat. Nachrichten werden vom Publisher nur an ein bestimmtes Topic geschickt und dann von NSQ auf die dazugehörigen Channels verteilt. Ein Subscriber abonniert eine Kombination aus Topic und Channel und bekommt die Nachrichten von NSQ per Push-Mechanismus, sobald diese verfügbar sind. Hat ein Topic verschiedene Channels bekommt jeder Channel eine Kopie der Nachricht. Hat ein Channel mehrere Subscriber, dann werden die Nachrichten und somit auch die Last auf die verschiedenen Subscriber verteilt. Ein Subscriber kann sie dann mit FIN (finished) als erfolgreich bearbeitet quittieren, oder aber durch ein REQ (requeue) wieder zurück in die Queue zwingen. Weitere Details hierzu finden sich unter https://nsq.io/overview/design.html
Installation
NSQ ist in Go geschrieben und kommt deshalb, wie für diese Sprache üblich, in Binaries ohne weitere Abhängigkeiten daher. Die entpackten Dateien sollten einfach im ausführbaren Zustand im $PATH abgelegt werden, schon kann man mit NSQ starten. Tarballs gibt es für die gängigen Architekturen unter https://nsq.io/deployment/installing.html
Die Programme
Die wichtigste Komponente bei NSQ ist nsqd, der eigentliche Message-Broker, der Nachrichten vom Publisher entgegen nimmt und an einen oder mehrere Consumer weitergibt. Bei echten Deployments sollte zusäzlich auch nsqlookupd zum Einsatz kommen. Dieser kümmert sich darum, dass ein Consumer auch die richtigen nsqd Instanzen im Netzwerk findet. Um das Leben der Dev-Ops zu erleichtern, bringt NSQ auch die Administrations-Oberfläche nsqdadmin mit, mit der sich unter anderem Topics und Channels pausieren oder Nachrichten löschen lassen. Desweiteren gibt es noch eine Reihe weitere Programme, die einem das Debugging und den Umgang mit NSQ erleichtern. Im einfachsten Fall benötigt man nur ein einziges Kommando:
$ nsqd
Damit wird ein nsqd im Vordergrund gestartet und ist auch schon bereit, Daten von einem Publisher anzunehmen. Die schnellste Möglichkeit um eine Nachricht auf den Weg zu bringen, ist diese einfach über die HTTP Schnittstelle von
nsqd zu versenden:
$ curl https://localhost:4151/pub?topic=test -d '{"hello":"NSQ"}'
Damit wurde unsere erste Nachricht an das Topic test geschickt. In diesem Moment befindet sie sich noch im nsqd, denn bisher existiert noch kein Consumer um die Nachricht empfangen. Im einfachsten Fall wird nsq_tail gestartet um die Nachrichten für ein Topic zu empfangen.
$ nsq_tail -nsqd-tcp-address=127.0.0.1:4150 -topic=test
2015/06/1 16:04:46 INF 1 [test/tail168310#ephemeral] (127.0.0.1:4150) connecting to nsqd
{"hello":"NSQ"}
Und schon haben wir unsere erste Nachricht aus NSQ erhalten. In diesem Beispiel wurde die Nachricht als JSON verschickt, was aber nicht erforderlich ist, denn NSQ arbeitet unabhängig von den serialisierten Daten. Der Kommandozeile und der Log-Ausgabe ist zu entnehmen, dass nsq_tail sich zu nsqd auf localhost verbunden und das Topic test abonniert hat. Als Channel Name dient hier, von nsq_tail automatisch generiert, tail168310#ephemeral. Das Suffix #ephemeral signalisiert NSQ, dass der Channel nicht persistent ist und nach beenden der Verbindung automatisch wieder gelöscht wird.
Interessanter wird es jedoch, wenn mehrere Publisher und Consumer ins Spiel kommen. Um das Szenario auf einer Maschine umzusetzen, muss man folgende Kommandos jeweils in einer Console starten: Den nsqlookupd, der es den Clients ermöglicht, die richtigen nsqd Instanzen zu finden:
$ nsqlookupd
Eine praktische Web-Oberfläche:
$ nsqadmin -nsqd-http-address=127.0.0.1:4161
Jeweils einen *nsqd* auf ports 4150/4151 und 5150/5151:
$ nsqd -lookupd-tcp-address=127.0.0.1:4160 -tcp-address=:4150 -http-address=:4151
$ nsqd -lookupd-tcp-address=127.0.0.1:4160 -tcp-address=:5150 -http-address=:5151
Zwei Instanzen von nsq_tail, die beide den selben Channel Namen haben:
$ nsq_tail -lookupd-http-address=127.0.0.1:4161 -topic=test -channel=debug
$ nsq_tail -lookupd-http-address=127.0.0.1:4161 -topic=test -channel=debug
Zuletzt noch einen nsq_to_file, der den Channel archive abonniert und alle
eintreffenden Nachrichten auf die Platte (/tmp) speichert:
$ nsq_to_file -lookupd-http-address=127.0.0.1:4161 -topic=test -channel=archive
An dieser Stelle lohnt ein Blick auf die Admin Oberfläche unter https://localhost:4171/ und via curl ein paar Nachrichten an die beiden laufenden nsqd zu schicken.
curl https://localhost:4151/pub?topic=test -d 'Hello nsqd1'
curl https://localhost:5151/pub?topic=test -d 'Hello nsqd2'
Nur soviel vorweg: Die Nachrichten kommen, mehr oder weniger abwechselnd, auf den nsq_tail Instanzen an, während jedoch alle Nachrichten von nsq_to_file auf die Platte geschrieben werden.
Fazit
Was auf beim ersten Blick auf die Webseite nach schwer verdaulichem Fast-Food aussieht, entpuppt sich bei näherer Betrachtung sehr schnell als gesunde und leichte Kost. Aber das war erst der Anfang, NSQ bietet noch einiges mehr und lässt sich dank zahlreicher Client Bibliotheken in verschiedensten Sprachen recht einfach in bestehende Projekte integrieren.