Ana içeriğe geç

RabbitMQ

RabbitMQ, servisler arası asenkron mesajlaşma sağlar; yanlış yapılandırma mesaj kaybına ve performans sorunlarına yol açar.


1. Mesaj Kalıcılığını Sağlamamak

Yanlış Kullanım: Mesajları kalıcı olmayan kuyrukta tutmak.

channel.QueueDeclare("orders", durable: false, exclusive: false, autoDelete: false);
channel.BasicPublish("", "orders", null, body);
// RabbitMQ restart olduğunda tüm mesajlar kaybolur

İdeal Kullanım: Durable queue ve persistent mesajlar kullanın.

channel.QueueDeclare("orders", durable: true, exclusive: false, autoDelete: false);

var properties = channel.CreateBasicProperties();
properties.Persistent = true;

channel.BasicPublish("", "orders", properties, body);

2. Manuel Ack Yapmamak

Yanlış Kullanım: AutoAck ile mesaj işlenmeden onaylamak.

channel.BasicConsume("orders", autoAck: true, consumer); // Mesaj alınır alınmaz ack
// İşlem sırasında hata olursa mesaj kaybolur

İdeal Kullanım: Manuel ack ile mesajı işlendikten sonra onaylayın.

channel.BasicConsume("orders", autoAck: false, consumer);

consumer.Received += async (sender, args) =>
{
    try
    {
        var message = Encoding.UTF8.GetString(args.Body.ToArray());
        await ProcessOrderAsync(message);
        channel.BasicAck(args.DeliveryTag, multiple: false);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Mesaj işlenemedi");
        channel.BasicNack(args.DeliveryTag, multiple: false, requeue: true);
    }
};

3. MassTransit Kullanmamak

Yanlış Kullanım: RabbitMQ client’ı doğrudan kullanarak her şeyi manuel yazmak.

var factory = new ConnectionFactory { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
channel.QueueDeclare("orders", true, false, false);
var body = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(order));
channel.BasicPublish("", "orders", null, body);
// Connection yönetimi, serialization, retry, error handling hep manuel

İdeal Kullanım: MassTransit ile mesajlaşma altyapısını soyutlayın.

builder.Services.AddMassTransit(x =>
{
    x.AddConsumer<OrderCreatedConsumer>();

    x.UsingRabbitMq((context, cfg) =>
    {
        cfg.Host("localhost", "/", h =>
        {
            h.Username("guest");
            h.Password("guest");
        });
        cfg.ConfigureEndpoints(context);
    });
});

// Publisher
public class OrderService
{
    private readonly IPublishEndpoint _publishEndpoint;

    public async Task CreateAsync(Order order)
    {
        await _repository.AddAsync(order);
        await _publishEndpoint.Publish(new OrderCreatedEvent { OrderId = order.Id });
    }
}

// Consumer
public class OrderCreatedConsumer : IConsumer<OrderCreatedEvent>
{
    public async Task Consume(ConsumeContext<OrderCreatedEvent> context)
    {
        var orderId = context.Message.OrderId;
        await _emailService.SendConfirmationAsync(orderId);
    }
}

4. Dead Letter Queue Kullanmamak

Yanlış Kullanım: Başarısız mesajları sonsuz döngüde tekrar deneyerek kuyruğu tıkamak.

consumer.Received += async (sender, args) =>
{
    try
    {
        await ProcessAsync(args);
        channel.BasicAck(args.DeliveryTag, false);
    }
    catch
    {
        channel.BasicNack(args.DeliveryTag, false, requeue: true); // Sürekli tekrar kuyruğa girer
    }
};

İdeal Kullanım: Dead Letter Queue ile başarısız mesajları ayırın.

// MassTransit ile otomatik DLQ
builder.Services.AddMassTransit(x =>
{
    x.AddConsumer<OrderConsumer>(cfg =>
    {
        cfg.UseMessageRetry(r => r.Intervals(
            TimeSpan.FromSeconds(5),
            TimeSpan.FromSeconds(15),
            TimeSpan.FromSeconds(60)));
    });

    x.UsingRabbitMq((context, cfg) =>
    {
        cfg.ConfigureEndpoints(context);
        // Başarısız mesajlar otomatik olarak _error kuyruğuna taşınır
    });
});

5. Prefetch Count Ayarlamamak

Yanlış Kullanım: Varsayılan prefetch ile tüm mesajları tek consumer’a yüklemek.

channel.BasicConsume("orders", false, consumer);
// Varsayılan prefetch sınırsız, tüm mesajlar tek consumer'a gider
// Diğer consumer'lar boşta kalır

İdeal Kullanım: Prefetch count ile yük dağılımını dengeleyin.

// Manuel RabbitMQ
channel.BasicQos(prefetchSize: 0, prefetchCount: 10, global: false);

// MassTransit
x.UsingRabbitMq((context, cfg) =>
{
    cfg.PrefetchCount = 16;

    cfg.ReceiveEndpoint("order-processing", e =>
    {
        e.PrefetchCount = 10;
        e.ConcurrentMessageLimit = 5;
        e.ConfigureConsumer<OrderConsumer>(context);
    });
});