事务消息与数据库的事务类似,只是MQ的消息是要保证消息是否会全部发送成功,防止消息丢失的一种策略。
RabbitMQ有两种策略来解决这个问题:
1.通过AMQP的事务机制实现
2.使用生产者确认模式实现
本文讲生产者确认模式。
1. 生产者
using RabbitMQMsgProducer.MessageProducer; using Microsoft.Extensions.Configuration; using System; using System.IO; using RabbitMQMsgProducer.ExchangeDemo; using RabbitMQMsgProducer.MessageConfirm; namespace RabbitMQMsgProducer { class Program { static void Main(string[] args) { try { { // 消息确认模式 ProducerMsgConfirm.Send(); } Console.ReadLine(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } }
using RabbitMQ.Client; using System; using System.Collections.Generic; using System.Text; namespace RabbitMQMsgProducer.MessageConfirm { public class ProducerMsgConfirm { public static void Send() { ConnectionFactory factory = new ConnectionFactory(); factory.HostName = "localhost";//服务地址 factory.UserName = "guest";//用户名 factory.Password = "guest";//密码 string queueName = "MsgConfirmQueue01"; string exchangeName = "MsgConfirmExchange"; string routingKeyName = "MsgConfirmRoutingKey"; using (var connection = factory.CreateConnection()) { using (var channel = connection.CreateModel()) { Console.WriteLine("the producer is ready . GO !"); channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null); //声明交换机exchange channel.ExchangeDeclare(exchange: exchangeName, type: ExchangeType.Direct, durable: true, autoDelete: false, arguments: null); //绑定exchange和queue channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: routingKeyName); string message = ""; while (true) { message = Console.ReadLine(); bool isOk = message.Equals("quit", StringComparison.CurrentCultureIgnoreCase); if (isOk) { break; } var body = Encoding.UTF8.GetBytes(message); try { //开启消息确认模式 channel.ConfirmSelect(); //发送消息 channel.BasicPublish(exchange: exchangeName, routingKey: routingKeyName, basicProperties: null, body: body); if (channel.WaitForConfirms()) //如果一条消息或多消息都确认发送 { Console.WriteLine($"the msg : _ {message} _ is send to broker . success ."); } else { //可以记录个日志,重试一下,找个重试代码或者中间件; } channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行;如果有消息发送失败;就抛出异常; } catch (Exception) { Console.WriteLine($"the msg : _ {message} _ is send to broker . fail ."); } } Console.Read(); } } } } }
2. 结果