RabbitMQ .NET
RabbitMQ .NET
RabbitMQ ist ein Message Broker, was bedeutet, dass er als Vermittler von Nachrichten zwischen verschiedenen Komponenten dient. Dafür benötigt man einen Server, worauf RabbitMQ läuft. Die Nachrichten werden also nicht direkt gesendet, sondern gehen zuerst zum RabbitMQ Server und dann zum Empfänger. Dadurch müssen sich die Komponenten nicht kennen oder aufeinander warten. RabbitMQ unterstützt Warteschlangen, welche Nachrichten solange speichern, bis sie ausgelesen wurden. In diesem Blogpost werden wir uns genauer mit RabbitMQ befassen und schauen, wie man es in C#/.NET verwendet.
Anforderungen
Bevor wir mit dem Programmieren starten können, brauchen wir noch einen Docker Container, worauf RabbitMQ läuft und müssen das NugetPackage installieren.
Docker
Um RabbitMQ herunterzuladen und einen Docker Container zu erstellen, verwendet man diesen Befehl:
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-management
Nuget Package
Für das Nuget Package gehen wir in die Package Manager Konsole und führen diesen Befehl aus:
Install-Package RabbitMQ.Client
Funktionsweise
Um die Funktionsweise von RabbitMQ zu verstehen, schauen wir uns die verschiedenen Begriffe an.
Producer (Sender):
Ein Producer ist eine Anwendung oder ein System, das Nachrichten erstellt und an den Message Broker (RabbitMQ) sendet.
Consumer (Empfänger):
Ein Consumer ist eine Anwendung oder ein System, das Nachrichten von RabbitMQ empfängt und verarbeitet.
Exchange:
Ein Exchange ist ein Vermittlerpunkt für Nachrichten. Es ist verantwortlich für die Routen der Nachrichten an bestimmte Warteschlangen. Es gibt verschiedene Arten von Exchanges, darunter Direct, Fanout, Topic und Headers. Jeder Typ behandelt Routing auf unterschiedliche Weise.
Queue (Warteschlange):
Eine Warteschlange ist ein Speicherbereich für Nachrichten. Konsumenten lesen Nachrichten aus einer Warteschlange. Eine Nachricht wird von einem Producer an eine Warteschlange gesendet und kann von einem oder mehreren Konsumenten abgerufen werden.
Routing Key:
Bei der Veröffentlichung einer Nachricht gibt der Sender einen Routing-Key an. Dieser Routing-Key wird von Exchanges verwendet, um zu entscheiden, an welche Warteschlangen die Nachricht weitergeleitet werden soll.
Code
Wie erwähnt, benötigen wir für die Entwicklung in C# das Nuget Package RabbitMQ.Client. RabbitMQ bieter im übrigen auch Libraries für andere Sprachen, wie Java, Python, PHP, C, C++ und viele mehr.
Nachrichten senden
Um Nachrichten zu senden, muss zuerst eine Connection erstellt werden. Mit dieser Connection können wir einen Channel erstellen, welcher uns viele Methoden zur Verfügung stellt.
var connectionFactory = new ConnectionFactory() { HostName = host }; using var connection = connectionFactory.CreateConnection(); using var channel = _connection.CreateModel();
RabbitMQ empfiehlt auf ihrer Website, eine Connection so lange wie möglich am Leben zu halten. Die Erstellung von Connections benötigt viele Ressourcen und kann ineffizient werden, wenn man für jede Nachricht eine eigene Connection erstellt. Einen Channel hingegen kann man für jede Aufgabe erstellen.
Nun müssen wir eine Warteschlange erstellen. Dafür verwenden wir die Methode "QueueDeclare()".
channel.QueueDeclare("MyQueue", false, false, false, null); var body = Encoding.UTF8.GetBytes("Hello World"); channel.BasicPublish(string.Empty, "MyQueue", null, body);
Wie man sieht, muss der Body als Byte-Array mitgegeben werden. Da ich eine Text-Nachricht senden möchte, wandle ich sie mit "Encoding.UTF8.GetBytes()" in einen Byte-Array um.
Nachrichten empfangen
Die Vorgehensweise für das Empfangen von Nachrichten ist ähnlich. Wir benötigen ebenfalls eine Connection und einen Channel. Anschliessend verwenden wir wieder "QueueDeclare()", um die Warteschlange zu erstellen. Dies ist nicht zwingend notwendig, doch stellt sicher, dass die Warteschlange existiert, wenn der Consumer zum Beispiel schon auf Nachrichten wartet, bevor der Producer die Warteschlange erstellt hat. Die Methode "QueueDeclare()" erstellt nämlich nur die Warteschlange, falls sie noch nicht existiert.
Anschliessend müssen wir einen Consumer erstellen und definieren, was beim Erhalt einer Nachricht passieren soll. Zum Schluss habe ich noch ein "Console.ReadLine()", um das stoppen der Konsolenapplikation zu verhindern.
var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, eventArgs) => { var body = eventArgs.Body.ToArray(); var message = Encoding.UTF8.GetString(body); Console.WriteLine(message); }; channel.BasicConsume("MyQueue", true, consumer); Console.ReadLine();
Den gesamten Code habe ich noch in diesem Repository auf GitHub abgelegt.
Fazit
RabbitMQ bietet eine effiziente Lösung für die Nachrichtenvermittlung in verteilten Systemen. Die Vorteile, wie Zuverlässigkeit und Skalierbarkeit, machen es zu einer beliebten Wahl. Die Verwaltung kann jedoch etwas komplex werden wodurch es für kleinere Projekte eher nicht geeignet ist.
Es gibt auch Alternativen wie Apache Kafka oder Microsoft Azure Service Bus. Diese bieten ähnliche Funktionen, aber mit unterschiedlichen Schwerpunkten und Vor- und Nachteilen.
Kommentare
Kommentar veröffentlichen