一、序言
在DDD领域驱动设计中,有领域事件和集成事件。领域事件是微服务(进程)内部的消息通信,我们可以选用MeditR进行消息通信。集成事件可以理解成是服务之间的消息通信,需要借助消息中间件进行信息交换,常见的消息中间件有Kafka、RabbitMQ、ActiveMQ等,这里主要记录RabbitMQ Routing模式的基本使用。
二、基本概念
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件),Routing模式的好处是生产者消费者宕机,消息只要发送了都在队列中,不会存在消息的丢失。
2.1信道(Channel)
信道是消息的生产者、消费者和服务器进行通信的虚拟连接。TCP连接的建立是非常消耗资源的,所以RabbitMQ在TCP连接的基础上构建了虚拟的信道。我们尽量重复使用TCP连接,而信道则可以用完了就关闭。
2.2队列(Queue)
用来进行消息收发的地方,生产者讲消息放到队列中,消费者从队列中获取数据。
2.3交换机(exchange)
把消息路由到一个或多个队列中。
2.4绑定(binding)
把交换机和队列按照路由规则绑定起来。
2.5路由关键字(Routing Key)
交换机根据这个关键字进行消息投递。
三、基本使用
3.1安装RabbitMQ服务器
linux和windows服务器安装方式不一样,网上很多教程,在此略过。
3.2创建消息生产者项目
- 通过nuget装RabbitMQ.Client
- 编写发送消息代码
var factory = new ConnectionFactory();
factory.HostName="127.0.0.1";//RabbitMQ服务器地址
factory.DispatchConsumersAsync = true;//允许异步
var connection = factory.CreateConnection();//创建连接
string exchangeName = "Exchange1";//交换机名字
string routingKey = "routingKey";//路由关键字
while(true)
{
using var channel = connection.CreateModel();//创建信道
var prop = channel.CreateBasicProperties();//创建属性
prop.DeliverMode = 2;
channel.ExchangeDeclare(exchange:exchangeName,type:"direct");//声明交换机
byte[] body = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
channel.BasicPublish(exchangeName,routingKey,mandatory:true,basicProperties:prop,body:body);
Thread.Sleep(1000);
}
3.3创建消息消费者项目
- 通过nuget装RabbitMQ.Client
- 编写消费消息代码
var factory = new ConnectionFactory();
factory.HostName="127.0.0.1";//RabbitMQ服务器地址
factory.DispatchConsumersAsync = true;//允许异步
var connection = factory.CreateConnection();//创建连接
string exchangeName = "Exchange1";//交换机名字
string routingKey = "routingKey";//路由关键字
string queueName="queue1";//队列名
using var channel = connection.CreateModel();//创建信道
channel.ExchangeDeclare(exchange:exchangeName,type:"direct");//声明交换机
//消费者需要知道routingKey和exchangeName
channel.QueueDeclare(queue:queueName,durable:true,exclusive:false,autoDelete:false,arguments:null);//声明队列
channel.QueueBind(queue:queueName,exchange:exchangeName,routingKey:routingKey);//把交换机和队列按照路由规则绑定(生产者发送消息时没有找到routingKey绑定的队列的消息会被舍弃掉)
var consumer = new AsyncEventingBasicConsumer(channel);
consumer.Received+=Consumer_Received;
channel.BasicConsume(queueName,false,consumer);
//received事件
async Task Consumer_Recieved(object sender,BasicDeliverEventArgs args)
{
try
{
var bytes = args.Body.ToArray();
string msg = Encoding.UTF8.GetString(bytes);
Console.WriteLine("收到了消息"+msg);
channel.BasicAck(args.DeliveryTag,multiple:false);//消息确认,(处理到一半宕机)对于没有确认的消息,会重发。
await Task.Delay(1000);
}
catch(Exception ex)
{
channel.BasicReject(args.DeliveryTag,true);//失败重发
Console.WriteLine("处理收到的消息失败"+ex);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下