Implementering af RabbitMQ

Introduktion

RabbitMQ bruges som en message broker til at facilitere kommunikation mellem microservices. Denne tilgang decouplerer services, så de kan arbejde asynkront og uafhængigt af hinanden.

I denne demo vises:

  1. En producer-service, der sender beskeder.
  2. RabbitMQ som en message broker.
  3. En Consumer-service, der modtager beskeder.

Arkitekturdiagram

uml diagram

Problematik i Kommunikation mellem Microservices

Når microservices kommunikerer direkte med hinanden, kan følgende udfordringer opstå:

  1. Tight Coupling: Services bliver afhængige af hinandens tilgængelighed og implementation, hvilket gør systemet mindre fleksibelt.
  2. Skaleringsproblemer: Direkte kommunikation mellem mange services kan føre til en kompleks netværksarkitektur og belastningsproblemer.
  3. Håndtering af fejl: Hvis en service går ned, kan det medføre, at afhængige tjenester også fejler, især i real-time systemer.
  4. Kompleks integration: Ved flere services kan der opstå udfordringer med at sikre, at alle services kan kommunikere korrekt med hinanden.

Hvordan RabbitMQ som Message Broker Løser Problemet

En message broker som RabbitMQ introducerer en middelware, der hjælper med at håndtere asynkron kommunikation mellem services. Dette giver flere fordele:

  1. Decoupling (Løs kobling): Services behøver ikke være online samtidig. Producenten (Producer) kan sende beskeder, som forbrugeren (Consumer) henter senere.
  2. Pålidelighed: RabbitMQ garanterer levering af beskeder og kan gemme dem, indtil de er leveret.
  3. Skalérbarhed: RabbitMQ kan håndtere mange forbindelser og beskeder, hvilket gør systemet mere skalerbart.
  4. Fejlhåndtering: Hvis en forbruger er midlertidigt nede, gemmer RabbitMQ beskeden, indtil forbrugeren er klar igen.

Dette sikrer, at ordrer ikke går tabt, selv hvis lagerstyringsservicen ikke er tilgængelig i øjeblikket. RabbitMQ vil gemme beskederne og levere dem, når servicen er oppe igen.

Arkitekturen løser således problematikken med kompleks direkte kommunikation og sikrer, at services kan arbejde uafhængigt af hinanden.


Opsætning med docker

docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:4.0-management

Denne Docker-kommando starter en midlertidig RabbitMQ-container med det officielle Management-plugin. Den mapper port 5672 (AMQP) og 15672 (Management-UI) til din host, så du kan sende/afhente beskeder og overvåge køer via http://localhost:15672 (standard login: guest/guest). Containeren navngives rabbitmq og fjernes automatisk ved stop.


Kode eksempel

Producer

Jeg har implementeret en Producer her

var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.QueueDeclare(queue: "hello",
                     durable: false,
                     exclusive: false,
                     autoDelete: false,
                     arguments: null);

string message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message);

channel.BasicPublish(exchange: "",
                     routingKey: "hello",
                     basicProperties: null,
                     body: body);

1. Opret forbindelse til RabbitMQ

var factory = new ConnectionFactory() { HostName = "localhost" }; 
using var connection = factory.CreateConnection(); 
using var channel = connection.CreateModel();

RabbitMQ arbejder med kanaler for effektiv kommunikation mellem klient og server.

2. Opret en kø



channel.QueueDeclare(queue: "hello",
					 durable: false,
					 exclusive: false,
					 autoDelete: false,
					 arguments: null
					 );

3. Klargør beskeden

string message = "Hello World!"; 
var body = Encoding.UTF8.GetBytes(message);

4. Send beskeden

channel.BasicPublish(exchange: "",
					 routingKey: "hello",
					 basicProperties: null,
					 body: body
					 );

Consumer

Jeg har implementeret en consumer her

var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.QueueDeclare(queue: "hello",
                     durable: false,
                     exclusive: false,
                     autoDelete: false,
                     arguments: null);

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
    var body = ea.Body.ToArray();
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine(" [x] Received {0}", message);
};
channel.BasicConsume(queue: "hello",
                     autoAck: true,
                     consumer: consumer);


1. Opret forbindelse til RabbitMQ

var factory = new ConnectionFactory() { HostName = "localhost" }; 
using var connection = factory.CreateConnection(); 
using var channel = connection.CreateModel();

2. Sikre eksistensen af køen

channel.QueueDeclare(queue: "hello",
					 durable: false,
					 exclusive: false,
					 autoDelete: false,
					 arguments: null
					 );

3. Opsæt en consumer

var consumer = new EventingBasicConsumer(channel); 
consumer.Received += (model, ea) => {     
	var body = ea.Body.ToArray();     
	var message = Encoding.UTF8.GetString(body);     
	Console.WriteLine(" [x] Received {0}", message); 
};

4. Begynd at lytte til køen

channel.BasicConsume(queue: "hello",
					 autoAck: true,
					 consumer: consumer);

Sammenfatning

Med denne opsætning kan du vise, hvordan RabbitMQ fungerer som message broker i en microservices-arkitektur, og hvordan producer- og consumer-tjenester kommunikerer asynkront.