概述
这边文章接上一篇文章:RabbitMQ——RabbitMQ的六种工作模式详解,以.net core 作为实现方式进行RabbitMQ的六种工作模式实战
简单队列(点对点)
最简单的工作队列,其中一个消息生产者(P),一个消息消费者(C),一个队列。也称为点对点模式
生产者
public static void SendMessage()
{
string queueName = "simplest";
using (var connection = RabbitMQHelper.GetConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
while (true)
{
string message = "Simplest Message";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "", routingKey: queueName, null, body);
Thread.Sleep(1000);
Console.WriteLine("Sended Simplest message");
}
}
}
}
我们使用的是默认交换机((AMQP default)direct),在发布(
BasicPublish
)的时候routingKey
需和queue
名称一致,否则会丢失消息
消费者
public static void ReceiveMessage()
{
string queueName = "simplest";
var connection = RabbitMQHelper.GetConnection();
var channel = connection.CreateModel();
channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
Console.WriteLine("Simplest Received:{0}", message);
};
channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
}
工作队列
一个消息生产者,一个交换器,一个消息队列,多个消费者。同样也称为点对点模式
生产者
public static void SendMessage()
{
string queueName = "Worker_Queue";
using (var connection = RabbitMQHelper.GetConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
for (int i = 0; i < 20; i++)
{
string message = $"Worker Queue Message {i}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "", routingKey: queueName, null, body);
Console.WriteLine($"Sended Message {i}");
}
}
}
}
消费者
public static void ReceiveMessage()
{
string queueName = "Worker_Queue";
var connection = RabbitMQHelper.GetConnection();
{
var channel = connection.CreateModel();
{
channel.QueueDeclare(queueName, false, false, false, null);
var consumer = new EventingBasicConsumer(channel);
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
consumer.Received += (model, ea) => {
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
Console.WriteLine(" Worker Queue Received:{0}", message);
};
channel.BasicConsume(queueName, true, consumer);
}
}
}
公平性队列
通过prefetchCount = 1
设置BasicQos
,这告诉RabbitMQ,一次不要给一个消费者多条消息。或者换句话说,在未收到消费端的消息确认时,不再分发消息,也就确保了当消费端处于忙碌状态时,不再分配任务。也可以解释为能者多劳
发布订阅
将消息发送给不同类型的消费者。做到发布一次,多个消费者来消费。
生产者
public static void SendMessage()
{
using (var connection = RabbitMQHelper.GetConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare("fanout_exchange", "fanout", durable: false, autoDelete: false, arguments: null);
for (int i = 0; i < 3; i++)
{
string queueName = $"fanout_queue_{i + 1}";
channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
channel.QueueBind(queue: queueName, exchange: "fanout_exchange", routingKey: "", arguments: null);
}
for (int i = 0; i < 10; i++)
{
string message = $"Fanout Message {i}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "fanout_exchange", routingKey: "", false, null, body);
Console.WriteLine($"Sended Fanout Message:{i}");
}
}
}
消费者
public static void ReceiveMessage()
{
var connection = RabbitMQHelper.GetConnection();
var channel = connection.CreateModel();
channel.ExchangeDeclare("fanout_exchange", "fanout", durable: false, autoDelete: false, arguments: null);
for (int i = 0; i < 3; i++)
{
string queueName = $"fanout_queue_{i + 1}";
channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
channel.QueueBind(queue: queueName, exchange: "fanout_exchange", routingKey: "", arguments: null);
}
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
Console.WriteLine("Fanout Received:{0}", message);
};
channel.BasicConsume("fanout_queue_1", autoAck: true, consumer);
}
路由模式
在发布/订阅模式的基础上,有选择的接收消息,也就是通过 routing 路由进行匹配条件是否满足接收消息
生产者
分别往direct_queue_1
、direct_queue_2
、direct_queue_3
三个队列里各放入10条
public static void SendMessage()
{
using (var connection = RabbitMQHelper.GetConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare("direct_exchange", "direct", durable: false, autoDelete: false, arguments: null);
for (int i = 0; i < 3; i++)
{
string queueName = $"direct_queue_{i + 1}";
channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
channel.QueueBind(queue: queueName, exchange: "direct_exchange", routingKey: $"direct_key_{i + 1}", arguments: null);
}
for (int i = 0; i < 3; i++)
{
var tempRoutingKey = $"direct_key_{i + 1}";
for (int j = 0; j < 10; j++)
{
string message = $"Direct Message {j} and RoutingKey:direct_key_{i + 1}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "direct_exchange", routingKey: tempRoutingKey, false, null, body);
Console.WriteLine($"Sended Message:{j} ****** RoutingKey:direct_key_{i + 1}");
}
}
}
}
注意
队列绑定QueueBind
和发送消息BasicPublish
的时候需要指定routingKey发送
消费者
消费direct_queue_1
的消息
public static void ReceiveMessage()
{
var connection = RabbitMQHelper.GetConnection();
var channel = connection.CreateModel();
channel.ExchangeDeclare("direct_exchange", "direct", durable: false, autoDelete: false, arguments: null);
for (int i = 0; i < 3; i++)
{
string queueName = $"direct_queue_{i + 1}";
channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
channel.QueueBind(queue: queueName, exchange: "direct_exchange", routingKey: $"direct_key_{i + 1}", arguments: null);
}
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
var routingKey = ea.RoutingKey;
Console.WriteLine("Direct Received {0} ****** RoutingKey:{1}", message, routingKey);
channel.BasicAck(ea.DeliveryTag, true);
};
channel.BasicConsume(queue: "direct_queue_1", autoAck: false, consumer: consumer);
}
主题模式
同样是在发布/订阅模式的基础上,根据主题匹配进行筛选是否接收消息。topics 主题模式跟 routing 路由模式类似,只不过路由模式是指定固定的路由键 routingKey,而主题模式是可以模糊匹配路由键routingKey,类似于SQL中 = 和 like 的关系。
生产者
分别往topic_queue1
、topic_queue2
、topic_queue3
三个队列里各放入10条
public static void SendMessage()
{
using (var connection = RabbitMQHelper.GetConnection())
{
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare("topic_exchange", "topic");
string queueName1 = "topic_queue1";
channel.QueueDeclare(queueName1, false, false, false, null);
string queueName2 = "topic_queue2";
channel.QueueDeclare(queueName2, false, false, false, null);
string queueName3 = "topic_queue3";
channel.QueueDeclare(queueName3, false, false, false, null);
channel.QueueBind(queue: queueName1, exchange: "topic_exchange", routingKey: "user.data.#");
channel.QueueBind(queue: queueName2, exchange: "topic_exchange", routingKey: "user.data.delete");
channel.QueueBind(queue: queueName3, exchange: "topic_exchange", routingKey: "user.data.update");
// routingKey:user.data.abc
for (int i = 0; i < 10; i++)
{
string message = $"Topic abc Message {i + 1}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("topic_exchange", "user.data.abc", null, body);
Console.WriteLine($"Sended Topic abc Message {i}");
}
// routingKey:user.data.abc
for (int i = 0; i < 10; i++)
{
string message = $"Topic delete Message {i + 1}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("topic_exchange", "user.data.delete", null, body);
Console.WriteLine($"Sended Topic delete Message {i}");
}
// routingKey:user.data.update
for (int i = 0; i < 10; i++)
{
string message = $"Topic update Message {i + 1}";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("topic_exchange", "user.data.update", null, body);
Console.WriteLine($"Sended Topic update Message {i}");
}
}
}
}
消费者
消费topic_queue1
队列的消息,不管routingKey
是什么。
public static void ReceiveMessage()
{
var queueName = "topic_queue1";
var connection = RabbitMQHelper.GetConnection();
var channel = connection.CreateModel();
channel.ExchangeDeclare("topic_exchange", "topic", durable: false, autoDelete: false, arguments: null);
channel.QueueDeclare(queueName, false, false, false, null);
channel.QueueBind(queue: queueName, exchange: "topic_exchange", routingKey: "user.data.insert");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var message = Encoding.UTF8.GetString(ea.Body.ToArray());
var routingKey = ea.RoutingKey;
Console.WriteLine("Topic Received:{0} ****** RoutingKey:{1}", message, routingKey);
};
channel.BasicConsume(queueName, autoAck: true, consumer);
}