RabbitMQ初识及使用场景

这篇文章比较全面详细的介绍了RabbitMQ中涉及的相关概念及组件,推荐阅读 超详细的RabbitMQ入门,看这篇就够了!-阿里云开发者社区 (aliyun.com).

1. 生产者:

 1 //1、创建连接工厂
 2 var factory = new ConnectionFactory()
 3  {
 4     HostName = "localhost",
 5     Port = 5672,
 6     Password = "guest",
 7     UserName = "guest",
 8     VirtualHost = "/"
 9 };
10 using (var connection = factory.CreateConnection())
11 {
12     var channel = connection.CreateModel();
13     // 2、定义队列
14     channel.QueueDeclare(queue: "test",
15                     durable: false,
16                     exclusive: false,
17                     autoDelete: false,
18                     arguments: null);
19 
20     string message = "Hello World!";
21     var body = Encoding.UTF8.GetBytes(message);
22 
23     // 3、发送消息
24     var properties = channel.CreateBasicProperties();
25     properties.Persistent = true; // 设置消息持久化
26     channel.BasicPublish(exchange: "",
27     routingKey: "test",
28     basicProperties: properties,
29     body: body);
30 }
31 _logger.LogInformation("成功发送消息");

2. 消费者:

 1     // 1、创建连接
 2     var factory = new ConnectionFactory()
 3     {
 4         HostName = "localhost",
 5         Port = 5672,
 6         Password = "guest",
 7         UserName = "guest",
 8         VirtualHost = "/"
 9      };
10      var connection = factory.CreateConnection();
11      var channel = connection.CreateModel();
12      channel.QueueDeclare(queue: "test", durable: false, exclusive: false, autoDelete: false, arguments: null);
13      var consumer = new EventingBasicConsumer(channel);
14      consumer.Received += (model, ea) =>
15                 {
16                     Console.WriteLine($"model:{model}");
17                     var body = ea.Body;
18                     //业务逻辑
19                     var message = Encoding.UTF8.GetString(body.ToArray());
20                     Console.WriteLine(message);
21                 };
22       channel.BasicConsume(queue: "test",
23                                      autoAck: true,//避免重复消费的问题
24                                      consumer: consumer);

代码为 最简单的单生产者,单消费者模式。

3. 添加主机服务

针对需要长连接的消费者,可以将RabbitMQ的Helper类继承IHostedService, 添加为主机服务,这样主机启动时,就会加载RabbitMQ的消费者端

 1 public class RabbitmqHostService : IHostedService
 2     {
 3         public Task StartAsync(CancellationToken cancellationToken)
 4         {
 5             // 创建rabbitmq的连接
 6             throw new NotImplementedException();
 7         }
 8 
 9         public Task StopAsync(CancellationToken cancellationToken)
10         {
11             // 关闭rabbitmq的连接
12             throw new NotImplementedException();
13         }
14     }            

在Startup.cs类的ConfigureServices中添加以下配置代码

services.AddHostedService<RabbitmqHostService>();

 

4. 设置的适用场景

4.1. RabbitMQ接收消息后 宕机,导致RabbitMQ内的消息丢失

解决办法:① 生产者端 channel.QueueDeclare() 的 durable 设置为 true,将消息持久化到磁盘,防止消息丢失 (持久化所有的消息);

     ②生产者端 利用如下方式 将消息持久化 (建议这种)

1 var properties = channel.CreateBasicProperties();
2 properties.Persistent = true; // 设置消息持久化

 

4.2. RabbitMQ将消息发送给消费者时,消费者服务宕机,可能会导致重复消费

解决办法: 利用RabbitMQ的消息应答机制,进行ack确认,channel.BasicConsume()的  autoAck 设置为 true.

4.3. RabbitMQ将消息发送给消费者,消费者ack,将结果返回给RabbitMQ时,消费者执行业务逻辑失败了

解决办法:手动ack, 消费者代码做如下改动

 1   consumer.Received += (model, ea) =>
 2                 {
 3 
 4                     Console.WriteLine($"model:{model}");
 5                     var body = ea.Body;
 6                     // 业务逻辑
 7                     var message = Encoding.UTF8.GetString(body.ToArray());
 8                     Console.WriteLine("message);
 9 
10                     // 自动确认机制缺陷:
11                     //确保消息正常消费了,所以需要使用手工确认
12                     channel.BasicAck(ea.DeliveryTag, true);
13                 };
14                 channel.BasicConsume(queue: "test",
15                                      autoAck: false, //消息确认
16                                      consumer: consumer);

4.3.1. 业务逻辑执行成功,但是BasicAck 手动确认失败(小概率事件),解决方案:将消息insert到本地消息表或文件中,设置一个定时器来处理相关的消息

4.4. RabbitMQ中接收到大量的消息,导致消息堆积

解决办法:使用消费者集群来解决,创建多个消费者来消费信息,RabbitMQ会均衡的将消息发送给不同的消息者。

4.4.1. 消费者集群中,不同消费者的处理能力不一致,导致处理消息延迟处理

解决办法:使用RabbitMQ提供的QOS来解决,代码如下所示

 1  consumer.Received += (model, ea) =>
 2                 {
 3                     Console.WriteLine($"model:{model}");
 4                     var body = ea.Body;
 5                     var message = Encoding.UTF8.GetString(body.ToArray());
 6                     Console.WriteLine("message);
 7 
 8                     channel.BasicAck(ea.DeliveryTag, true);
 9                 };
10                 // 消费消息
11                 channel.BasicQos(0, 1, false); // Qos(防止多个消费者,能力不一致,导致的系统质量问题。
12                                                // 每一次一个消费者只成功消费一个)
13                 channel.BasicConsume(queue: "test",
14                                      autoAck: false, 
15                                      consumer: consumer);

 

posted @ 2022-03-03 22:26  鲁燕云端  阅读(18)  评论(0编辑  收藏  举报