生产者向RabbitMQ服务发送消息,消费者从RabbitMQ服务中获取消息。
单生产者单消费者模式
使用程序演示单生产者和单消费者模型:
项目结构为两个.net Core 控制台程序应用程序
程序需要添加引用 RabbitMQ.Client
AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer(消费者)
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer
{
public class ProductionConsumer
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//声明队列
channel.QueueDeclare(queue: "OnlyProducerMessage", durable: true, exclusive: false, autoDelete: false, arguments: null);
//声明路由
channel.ExchangeDeclare(exchange: "OnlyProducerMessageExChange", type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
//绑定队列和路由
channel.QueueBind(queue: "OnlyProducerMessage", exchange: "OnlyProducerMessageExChange", routingKey: string.Empty, arguments: null);
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"消费者01 接收消息:{message}");
};
channel.BasicConsume(queue: "OnlyProducerMessage", autoAck: true, consumer: consumer);
Console.WriteLine("按下回车退出啊");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
}
Main程序中调用下Show方法
class Program
{
static void Main(string[] args)
{
ProductionConsumer.Show();
}
}
namespace AspNetCore.RabbitMQ.MessageProducer.MessageProducer(生产者)
using RabbitMQ.Client;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageProducer.MessageProducer
{
/// <summary>
/// 生产者
/// </summary>
public class ProductionConsumer
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("生产者已准备就绪......");
int i = 1;
{
while (true)
{
IBasicProperties basicProperties = channel.CreateBasicProperties();
basicProperties.Persistent = true;
string message = $"消息{i}";
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "OnlyProducerMessageExChange", routingKey: string.Empty, basicProperties: basicProperties, body: body);
Console.WriteLine($"消息{message}已发送");
i++;
}
}
}
}
}
}
}
Main程序中调用下Show方法
class Program
{
static void Main(string[] args)
{
ProductionConsumer.Show();
}
}
启动两个程序:
启动消费者,在项目目录中进入命令窗口执行dotnet 启动命令
以同样的方式,启动生产者
消费者和生产者都启动以后,可以看到两个命令窗口打印如下信息:
多生产者多消费者模式
模拟多个生产者和多个消费者的情况
AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer(消费者)
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer
{
public class MultiProductionConsumer
{
public static void Show1()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (var connection = factory.CreateConnection())
{
//创建信道
using (var channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//声明队列
//channel.QueueDeclare(queue: "OnlyProducerMessage", durable: true, exclusive: false, autoDelete: false, arguments: null);
//声明路由
//channel.ExchangeDeclare(exchange: "OnlyProducerMessageExChange", type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
//绑定队列和路由
//channel.QueueBind(queue: "OnlyProducerMessage", exchange: "OnlyProducerMessageExChange", routingKey: string.Empty, arguments: null);
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"消费者01 接收消息:{message}");
};
channel.BasicConsume(queue: "MultiProducerMessage", autoAck: true, consumer: consumer);
Console.WriteLine("按下回车退出啊");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
public static void Show2()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (var connection = factory.CreateConnection())
{
//创建信道
using (var channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//声明队列
//channel.QueueDeclare(queue: "OnlyProducerMessage", durable: true, exclusive: false, autoDelete: false, arguments: null);
//声明路由
//channel.ExchangeDeclare(exchange: "OnlyProducerMessageExChange", type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
//绑定队列和路由
//channel.QueueBind(queue: "OnlyProducerMessage", exchange: "OnlyProducerMessageExChange", routingKey: string.Empty, arguments: null);
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"消费者02 接收消息:{message}");
};
channel.BasicConsume(queue: "MultiProducerMessage", autoAck: true, consumer: consumer);
Console.WriteLine("按下回车退出啊");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
public static void Show3()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (var connection = factory.CreateConnection())
{
//创建信道
using (var channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//声明队列
//channel.QueueDeclare(queue: "OnlyProducerMessage", durable: true, exclusive: false, autoDelete: false, arguments: null);
//声明路由
//channel.ExchangeDeclare(exchange: "OnlyProducerMessageExChange", type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
//绑定队列和路由
//channel.QueueBind(queue: "OnlyProducerMessage", exchange: "OnlyProducerMessageExChange", routingKey: string.Empty, arguments: null);
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"消费者03 接收消息:{message}");
};
channel.BasicConsume(queue: "MultiProducerMessage", autoAck: true, consumer: consumer);
Console.WriteLine("按下回车退出啊");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
}
Main程序中调用下Show方法
class Program
{
static void Main(string[] args)
{
//ProductionConsumer.Show();
//多消费者
{
Task.Run(() => { MultiProductionConsumer.Show1(); });
Task.Run(() => { MultiProductionConsumer.Show2(); });
Task.Run(() => { MultiProductionConsumer.Show3(); });
}
Console.ReadLine();
}
}
AspNetCore.RabbitMQ.MessageProducer.MessageProducer(生产者)
using RabbitMQ.Client;
using System;
using System.Text;
using System.Threading;
namespace AspNetCore.RabbitMQ.MessageProducer.MessageProducer
{
/// <summary>
/// 生产者
/// </summary>
public class MultiProductionConsumer
{
public static void Show(string No)
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
//声明队列
channel.QueueDeclare(queue: "MultiProducerMessage", durable: true, exclusive: false, autoDelete: false, arguments: null);
//声明路由
channel.ExchangeDeclare(exchange: "MultiProducerMessageExChange", type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
//绑定队列和路由
channel.QueueBind(queue: "MultiProducerMessage", exchange: "MultiProducerMessageExChange", routingKey: string.Empty, arguments: null);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"生产者{No}已准备就绪......");
int i = 1;
{
while (true)
{
string message = $"生产者{No},消息{i}";
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "MultiProducerMessageExChange", routingKey: string.Empty, basicProperties: null, body: body);
Console.WriteLine($"消息{message}已发送");
i++;
Thread.Sleep(200);
}
}
}
}
}
}
}
Main程序中调用下Show方法
class Program
{
static void Main(string[] args)
{
//ProductionConsumer.Show();
//多生产者
{
//这是添加命令行功能
IConfigurationRoot config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddCommandLine(args)
.Build();
string strMinute = config["minute"];//什么时间开始执行
string No = config["no"];//生产者编号
int minute = Convert.ToInt32(strMinute);
bool flag = true;
while (flag)
{
if (DateTime.Now.Minute == minute)
{
Console.WriteLine($"到{strMinute}分钟,开始写入消息...");
flag = false;
MultiProductionConsumer.Show(No);
}
}
}
}
}
同时启动三个生产者服务,命令中的minute参数代表程序执行的分钟数字,从几分钟开始执行(表示当前时间的分钟数,13代表21:13开始执行)。no参数表示服务的编号,用于方便观察打印信息。
接着启动消费者服务
可以看到三个生产者同时向消息队列中发送消息。消费者服务开启三个线程,模拟三个消费者同时接收不同生产者发送的消息。
应用案例:商品秒杀实现
一共有10个商品,实现10个商品卖出后不再调用数据库进行操作(过滤无效请求,减少数据库压力)。
下面程序中写的生成者和消费者是从消息队列的角度出发的,发送数据的为生产者,接收数据的为
消费者。
AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer(消费者)
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer
{
public class SeckillConsumer
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//声明队列
channel.QueueDeclare(queue: "SeckillProducerMessage", durable: true, exclusive: false, autoDelete: false, arguments: null);
//声明路由
channel.ExchangeDeclare(exchange: "SeckillProducerMessageExChange", type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
//绑定队列和路由
channel.QueueBind(queue: "SeckillProducerMessage", exchange: "SeckillProducerMessageExChange", routingKey: string.Empty, arguments: null);
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
int count = 0;
consumer.Received += (model, ea) =>
{
if (count >= 10)
{
Console.WriteLine("商品秒杀结束,已经不再调用数据库操作");
}
else
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"{message} 秒杀成功");
count++;
}
};
channel.BasicConsume(queue: "SeckillProducerMessage", autoAck: true, consumer: consumer);
Console.WriteLine("按下回车退出啊");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
}
main方法:
class Program
{
static void Main(string[] args)
{
SeckillConsumer.Show();
Console.ReadLine();
}
}
AspNetCore.RabbitMQ.MessageProducer.MessageProducer(生产者)
using RabbitMQ.Client;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageProducer.MessageProducer
{
/// <summary>
/// 单生产者
/// </summary>
public class ProductionConsumer
{
/// <summary>
/// 秒杀商品
/// </summary>
public static void SkillShow()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("秒杀已准备就绪......");
int i = 1;
{
while (true)
{
IBasicProperties basicProperties = channel.CreateBasicProperties();
basicProperties.Persistent = true;
string message = $"粉丝{i}";
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "SeckillProducerMessageExChange", routingKey: string.Empty, basicProperties: basicProperties, body: body);
Console.WriteLine($"{message}开始抢购");
i++;
}
}
}
}
}
}
}
main方法:
class Program
{
static void Main(string[] args)
{
ProductionConsumer.SkillShow();
}
}
启动服务:
从打印信息可以看出,前10个用户请求处理完成后,后面的请求就不再调用数据库进行处理。达到了数据库限流的目的。
队列优先级
通过设置Priority的值来控制消息队列中消息被处理的优先级。
应用案例:VIP学员和普通学员同时向老师请教问题,老师优先解答VIP学员的提问。
AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer(消费者)
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageConsumer_01.MessageConsumer
{
public class PriorityQueue
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Green;
try
{
//基于当前信道创建事件
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body.ToArray());
Console.WriteLine($"{message}");
};
Console.WriteLine("消费者准备就绪......");
//处理消息
channel.BasicConsume(queue: "PriorityQueue", autoAck: false, consumer: consumer);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
}
}
main方法:
class Program
{
static void Main(string[] args)
{
//优先级队列
PriorityQueue.Show();
Console.ReadLine();
}
}
AspNetCore.RabbitMQ.MessageProducer.MessageProducer(生产者)
using RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.Text;
namespace AspNetCore.RabbitMQ.MessageProducer.MessageProducer
{
public class PriorityQueue
{
public static void Show()
{
ConnectionFactory factory = new ConnectionFactory();
factory.HostName = "localhost";//rabbitmq服务在本地运行
factory.UserName = "guest";//用户名
factory.Password = "guest";//密码
//创建链接
using (IConnection connection = factory.CreateConnection())
{
//创建信道
using (IModel channel = connection.CreateModel())
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("生产者已准备就绪......");
channel.QueueDeclare(queue: "PriorityQueue", durable: true, exclusive: false, autoDelete: false, arguments: new Dictionary<string, object>()
{
//最大级别255
{ "x-max-priority",10} //指定队列要支持优先级设置
});
//声明交换机exchange
channel.ExchangeDeclare(exchange: "PriorityQueueExchange", type: ExchangeType.Direct, durable: true, autoDelete: false,
arguments: null);
//绑定exchange和queue
channel.QueueBind(queue: "PriorityQueue", exchange: "PriorityQueueExchange", routingKey: "PriorityKey");
//待发送的消息
{
string[] questionList = { "vip学员1 来请教", "甲同学 来请教", "乙同学 来请教", "丙同学 来请教", "丁同学 来请教", "vip学员2 来请教" };
//设置消息优先级
IBasicProperties props = channel.CreateBasicProperties();
foreach (string questionMsg in questionList)
{
if (questionMsg.StartsWith("vip"))
{
props.Priority = 9;
}
else
{
props.Priority = 1;
}
channel.BasicPublish(exchange: "PriorityQueueExchange", routingKey: "PriorityKey", basicProperties: props, body: Encoding.UTF8.GetBytes(questionMsg));
Console.WriteLine($"{questionMsg}已发送");
}
}
}
}
}
}
}
main方法:
class Program
{
static void Main(string[] args)
{
//队列优先级
PriorityQueue.Show();
Console.ReadLine();
}
}
启动服务:
从运行结果可以看出,虽然 vip学员2 最后一个进行提问(消息最后添加到队列中),但是因为设置了props.Priority = 9,非VIP学员props.Priority = 1,所以会优先于非VIP学员处理。