RabbitMQ-简单的生产者-消费者模式
RabbitMQ 是一个消息代理:它接受并转发消息。可以把它看成是一个邮局:当你把你想要邮寄的邮件放在一个邮筒里时,你可以确信信使最终会把邮件送到您的收件人手中。在这里,RabbitMQ 充当了邮筒,邮局,信使的角色。
RabbitMQ 与邮局的主要区别在于它不处理纸张,他所做的仅仅只是接收、转发消息。
下面是RabbitMQ中使用到的几个术语
生产者(P):消息的发送方,一个程序如果发送消息,那么他就是生产者
队列(Queue):队列相当于RabbitMQ里面的一个邮筒,尽管消息流经过RabbitMQ和你的应用程序,但是他们只能被存储在队列中。一个队列只受到主机的内存和硬盘限制,队列在本质上是一个大型的消息缓冲区。大量生产者可以发送消息到一个队列,同时大量消费者也可以尝试从队列中获取数据
消费者(C):消费者有类似接收的含义,一个消费者就是一段主要等待接收消息的程序
需要注意的是,消费者、生产者、代理不一定要在同一台主机上,实际上,在大多数应用中,他们都在同一台主机上,一个应用程序可以既是生产者又是消费者
下面将实际编码,以便了解生产者-消费者模式的概念:
我们将使用C#编写两个程序,一个是生产者,一个是接受消息并打印出来的消费者(笔者使用的环境是Windows 10,VS2022,.net core 6.0)
- 首先在VS中,创建两个控制台应用程序,一个代表生产者(Send),一个代表消费者(Receive)
- 然后通过Nuget分别在两个项目中引入RabbitMQ的插件
RabbitMQ.Client
- Send代码
using RabbitMQ.Client;
using System.Text;
//该连接抽象了套接字连接,并为我们处理协议版本协商和认证等事宜
//这里我们连接到本地机器上的 RabbitMQ 节点,因此是 localhost。如果我们想连接到不同机器上的一个节点,我们只需在这里指定它的主机名或 IP 地址。
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
Console.WriteLine("生产者开始发送消息");
//声明一个队列,以便我们发送,队列声明是幂等的,只有当它不存在的时候才会被创建
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
for (int i = 0; i < 30; i++)
{
string message = $"[{i}]:Hello World!";
var body = Encoding.UTF8.GetBytes(message);
//向队列发布一个消息。
channel.BasicPublish(exchange: "",
routingKey: "hello",
basicProperties: null,
body: body);
Console.WriteLine($"{DateTime.Now:mm:ss:fff} Send Message: [{message}]");
Thread.Sleep(100);
}
}
Console.ReadLine();
- Receive代码
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
Console.WriteLine("消费者开始接收消息");
//请注意,在这里也声明了队列。因为我们可能会在发布者之前启动消费者,所以我们想在尝试消费队列中的消息之前确保队列存在。
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
//告诉服务器将队列中的消息传递给我们
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (send, data) =>
{
var body = data.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine($"{DateTime.Now:mm:ss:fff} Received: [{message}]");
};
channel.BasicConsume(queue: "hello",
autoAck: true,
consumer: consumer);
Console.ReadLine();
}
- 将两个项目编译后运行
消费者将打印它通过 RabbitMQ 从发布者那里获得的消息,消费者将持续运行,一收到消息就打印出来
从运行结果来看,生产者发送了30条消息,消费者全部接收到并打印了出来