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);

浙公网安备 33010602011771号