这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
消息队列
异步
例如,现在有一个订单系统,下单基本都在一个方法里面完成(扣完余额、创建完订单就可)
后来产品加了一个需求。需要在用户点击的下单的时候,发个APP通知一下对方。然后呢,还需要占用商品呀、结算鸭...
总之,现在的代码经过改造后变的十分卡顿。以前下单只需一秒。现在使用下单要等上个4~5秒。
嗯嗯...我们只能通过异步来实现了,现在用户再次下单时,我们先是按以往的流程走,然后将耗时的操作丢到队列里面...队列里的消费者会去慢慢处理(反正一定会处理的吧🤣)。
解耦
上线了订单系统后,由于我们消息服务都是集中放在了一个项目,这天。需求要改一下其中一条短信的参数。改好啦,发布啦。挺容易的... 5分钟后,小x啊,在把刚刚那个短信的参数在改回去吧...
这可不妙,频繁发布项目会导致先生用户体验下降鸭...你一沉思。咦,可以用队列来解决这个问题啊,每次发送消息都只是发给队列,就算是需要更新项目消息内容也能存储下来,上线后继续发送未发送完的短信...nice鸭
Queue
在熟悉消息队列之前,我们先来了解一下C#中的队列:
public record ChatMsg(string Content, string UserId);
public static void Main()
{
Queue<ChatMsg> chatMsgs = new Queue<ChatMsg>();
chatMsgs.Enqueue(new ChatMsg("hello wrold...", $"用户{new Random().Next(1, 10)}"));
chatMsgs.Enqueue(new ChatMsg("hello C#", $"用户{new Random().Next(2, 20)}"));
Task.Factory.StartNew(() =>
{
while (chatMsgs.TryDequeue(out var chat))
{
Console.WriteLine("{0} 说:{1}", chat.UserId, chat.Content);
}
});
Console.WriteLine("干别的事...");
Console.ReadKey();
//output:
//干别的事...
//用户5 说:hello wrold...
//用户14 说:hello C#
}
芜湖,感觉还行。开启了一个新线程在Queue里面取值,如果外界又新增了新消息的话。他还能继续运作
RabbitMQ
其实,简单理解RabbitMQ 的话,它就是在Queue上加了一个储存。以便消费者(取消息的那一方)可以正确的读到消息(不丢失消息)
📢 3.1 通过EasyNetQ(NuGet包)来使用RabbitMQ
PM> Install-Package EasyNetQ
配置中间件:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
using var bus = RabbitHutch.CreateBus(Configuration.GetConnectionString("MQ"));
var subscriber = new AutoSubscriber(bus, "appId");
subscriber.SubscribeAsync(new[] { Assembly.GetExecutingAssembly() });
services.AddSingleton(bus);
}
消息实体:
public record ChatMsg(string Content, string UserId);
消费者:
public class ChatMsgConsumer : IConsumeAsync<ChatMsg>
{
private readonly ILogger<ChatMsgConsumer> _logger;
public ChatMsgConsumer(ILogger<ChatMsgConsumer> logger)
{
_logger = logger;
}
[AutoSubscriberConsumer(SubscriptionId = "message.consumer")]
public Task ConsumeAsync(ChatMsg message, CancellationToken cancellationToken = default)
{
_logger.LogInformation("用户{0} 说:{1}", message.UserId, message.Content);
return Task.CompletedTask;
}
}
发布者:
[ApiController]
[Route("[controller]/[action]")]
public class HomeController : ControllerBase
{
private readonly IBus _bus;
public HomeController(IBus bus)
{
_bus = bus;
}
[HttpGet]
public bool SendMessage()
{
_bus.PubSub.Publish(new ChatMsg("hello rabbitmq", "用户张三"));
return true;
}
}