使用 RabbitMQ 和 MassTransit 在 .NET Core 中实现强大的微服务:处理订阅者故障和消息恢复

在本文中,我们将探讨如何在 .NET Core 中构建微服务,并使用 MassTransit 将 RabbitMQ 作为消息代理。我们将重点介绍如何实现发布-订阅模式,并重点强调如何确保订阅服务器能够从故障中恢复。具体来说,我们将演示订阅服务器如何在重启后重新连接、恢复正常运行,以及如何处理 RabbitMQ 停机期间排队的未处理消息。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

第 1 节:微服务和 RabbitMQ 简介

微服务架构是一种将应用程序构建为松散耦合服务集合的方法。每个服务负责一项特定的功能,并且可以独立开发、部署和扩展。RabbitMQ 是一个消息代理,用于促进这些微服务之间的通信,支持各种消息传递模式,包括发布-订阅模式。

第 2 部分:设置环境

先决条件

确保已安装 .NET Core SDK 和 RabbitMQ。您可以使用 Docker 简化 RabbitMQ 和 .NET Core 微服务的设置。

设置新的 .NET Core 项目

dotnet new webapi -n PublisherService

dotnet new webapi -n SubscriberService

使用 MassTransit 配置 RabbitMQ

将 MassTransit 和 RabbitMQ 客户端库添加到您的项目中:

dotnet add package MassTransit

dotnet add package MassTransit.RabbitMQ

第 3 节:实现发布者服务

创建发布者服务

public class PublisherService

{

private readonly IBusControl _bus;

public PublisherService(IBusControl bus)

{

_bus = bus;

}

public async Task PublishMessage(Guid orderId)

{

await _bus.Publish(new SubmitOrder { OrderId = orderId });

Console.WriteLine(" [x] Sent order: {0}", orderId);

}

}

public class SubmitOrder

{

public Guid OrderId { get; set; }

}

在中配置 MassTransitProgram.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddMassTransit(x =>

{

x.UsingRabbitMq((context, cfg) =>

{

cfg.Host("localhost", "/", h =>

{

h.Username("guest");

h.Password("guest");

});

});

});

builder.Services.AddMassTransitHostedService();

var app = builder.Build();

var publisher = app.Services.GetRequiredService<PublisherService>();

await publisher.PublishMessage(Guid.NewGuid());

app.Run();

第 4 节:实施订户服务

创建订阅者服务

public class SubmitOrderConsumer : IConsumer<SubmitOrder>

{

public async Task Consume(ConsumeContext<SubmitOrder> context)

{

Console.WriteLine("Processing order: " + context.Message.OrderId);

// Process the message

}

}

在中配置 MassTransitProgram.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddMassTransit(x =>

{

x.AddConsumer<SubmitOrderConsumer>();

x.UsingRabbitMq((context, cfg) =>

{

cfg.Host("localhost", "/", h =>

{

h.Username("guest");

h.Password("guest");

});

cfg.ReceiveEndpoint("submit_order_queue", e =>

{

e.ConfigureConsumer<SubmitOrderConsumer>(context);

});

});

});

builder.Services.AddMassTransitHostedService();

var app = builder.Build();

app.Run();

第 5 节:确保用户弹性

处理用户重启和断开连接

MassTransit 会自动处理重新连接。请确保您的消费者能够幂等地处理消息重新传递。

消息确认

MassTransit 自动处理消息确认。请确保您的消费者逻辑稳健,并能够处理重试。

配置指数重试策略

builder.Services.AddMassTransit(x =>

{

x.AddConsumer<SubmitOrderConsumer>(configurator =>

{

configurator.UseMessageRetry(r => r.Exponential(5, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(2)));

});

x.UsingRabbitMq((context, cfg) =>

{

cfg.Host("localhost", "/", h =>

{

h.Username("guest");

h.Password("guest");

});

cfg.ReceiveEndpoint("submit_order_queue", e =>

{

e.ConfigureConsumer<SubmitOrderConsumer>(context);

});

});

});

第 6 节:测试和调试

测试解决方案

模拟订阅者故障并确保系统可以恢复和处理未处理的消息。

public void SimulateFailure()

{

// Simulate failure by stopping the bus

_bus.Stop();

Console.WriteLine("Simulated failure. Reconnecting...");

_bus.Start();

}

调试常见问题

使用 RabbitMQ 的管理插件来监控队列和交换。

第 7 节:处理死信队列

设置死信队列

var factory = new ConnectionFactory() { HostName = "localhost" };

using var connection = factory.CreateConnection();

using var channel = connection.CreateModel();

channel.ExchangeDeclare(exchange: "dlx_exchange", type: ExchangeType.Direct);

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

channel.QueueBind(queue: "dead_letter_queue", exchange: "dlx_exchange", routingKey: "dlx_key");

var args = new Dictionary<string, object>

{

{ "x-dead-letter-exchange", "dlx_exchange" },

{ "x-dead-letter-routing-key", "dlx_key" }

};

channel.QueueDeclare(queue: "main_queue", durable: true, exclusive: false, autoDelete: false, arguments: args);

处理死信消息

var consumer = new EventingBasicConsumer(channel);

consumer.Received += (model, ea) =>

{

var body = ea.Body.ToArray();

var message = Encoding.UTF8.GetString(body);

Console.WriteLine(" [x] Received from DLQ: {0}", message);

// Process the dead-lettered message

};

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

通过设置死信队列,可以确保无法处理的消息不会丢失,并能得到适当的处理

拉动模型

优势

控制处理

  • 优点:消费者可以控制何时提取消息,从而更好地管理处理负载。
  • 示例:消费者可以在非高峰时段提取消息以平衡负载。

简化的错误处理

  • 优点:由于消费者控制何时提取下一条消息,因此更容易处理错误。
  • 示例:如果消费者遇到错误,它可以延迟拉取下一条消息,直到问题解决为止。

资源管理

  • 优点:可以设计消费者仅在资源可用时才提取消息,从而防止过载。
  • 示例:消费者可以在拉取下一条消息之前检查系统资源的可用性,以确保不会使系统过载。

缺点

轮询开销

  • 缺点:持续轮询队列中的消息可能会导致不必要的开销并增加延迟。
  • 示例:每秒轮询队列的消费者可能会导致消息处理延迟并消耗更多资源。

资源利用效率低下

  • 缺点:轮询可能导致资源使用效率低下,因为消费者在等待消息时可能会处于空闲状态。
  • 示例:轮询队列但未发现消息的消费者仍将消耗 CPU 周期。

扩展的复杂性

  • 缺点:与推送模型相比,在拉动模型中扩展消费者可能更为复杂。
  • 示例:管理轮询队列的多个消费者可能会导致竞争条件并增加负载平衡的复杂性。

结论

本文介绍了如何使用 .NET Core、RabbitMQ 和 MassTransit 实现强大的微服务架构,重点关注用户弹性和消息恢复。我们讨论了推送和拉取模型的优缺点,并提供了处理死信队列和配置重试策略的示例。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

相关推荐
vb2008112 小时前
Ubuntu 系统下 AMQP 协议 RabbitMQ服务器部署
服务器·ubuntu·rabbitmq
杨大枫16 小时前
Minio数据下载
.netcore
小股虫18 小时前
分布式事务:在增长中台,我们如何做到“发出去的内容”和“记录的数据”不打架?
分布式·微服务·云原生·架构·团队建设·方法论
用户917439653920 小时前
从单系统架构到微服务架构:软件现代化的转型综述
微服务·架构·系统架构
Code知行合壹1 天前
Kubernetes微服务DevOps
微服务·kubernetes·devops
Coder_Boy_1 天前
分布式系统设计经验总结:金融vs电商的核心差异与决策思路
java·运维·微服务·金融·电商
Coder_Boy_1 天前
基于SpringAI的智能AIOps项目:微服务与DDD多模块融合设计概述
java·运维·人工智能·微服务·faiss