消息中间件RabbitMq如何保证消息的可靠性
关于保证消息的可靠性,可以从rabbitmq的组成部分来分析,第一部分发送方,第二部分服务端,第三部分消费方,第四部分兜底部分
1.生产者发送确认机制,当生产者发送消息到rabbitmq后,rabbitmq会给生产者一个确认,告诉生产者这个消息我收到且保存
java代码
1 | channel.confirmSelect(); // 启用生产者确认 |
1 2 3 4 5 | if (channel.waitForConfirms()) { System.out.println( "Message successfully delivered!" ); } else { System.out.println( "Message delivery failed!" ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import com.rabbitmq.client.*; public class PublisherConfirmProducer { private final static String QUEUE_NAME = "persistent_queue" ; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost( "localhost" ); try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { // 声明持久化队列 channel.queueDeclare(QUEUE_NAME, true , false , false , null ); // 启用发布者确认模式 channel.confirmSelect(); String message = "Hello RabbitMQ with Publisher Confirms!" ; // 发布消息 channel.basicPublish( "" , QUEUE_NAME, new AMQP.BasicProperties.Builder().deliveryMode( 2 ).build(), message.getBytes()); // 等待确认 if (channel.waitForConfirms()) { System.out.println( "Message successfully delivered!" ); } else { System.out.println( "Message delivery failed!" ); } } } } |
2.服务端方面,消息持久化,也就是把消息保存到磁盘中,即rabbitmq重启后,队列依旧存在,未消费的消息依旧存在
java代码方面创建持久化队列,可以消息持久化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import com.rabbitmq.client.*; public class Producer { private final static String QUEUE_NAME = "persistent_queue" ; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost( "localhost" ); try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { // 声明一个持久化的队列 channel.queueDeclare(QUEUE_NAME, true , false , false , null ); String message = "Hello RabbitMQ!" ; // 发布持久化消息 channel.basicPublish( "" , QUEUE_NAME, new AMQP.BasicProperties.Builder().deliveryMode( 2 ).build(), // 设置消息持久化 message.getBytes()); System.out.println( "Sent: " + message); } } } |
3.从消费方设计,消息消费后进行一个手动的确认,取代原有的自动确认
java代码方面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import com.rabbitmq.client.*; public class Consumer { private final static String QUEUE_NAME = "persistent_queue" ; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost( "localhost" ); try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { // 声明持久化队列(即便消费者已经运行,这里仍然要声明队列) channel.queueDeclare(QUEUE_NAME, true , false , false , null ); // 设置消费者回调,手动确认消息 DeliverCallback deliverCallback = (consumerTag, delivery) -> { String message = new String(delivery.getBody(), "UTF-8" ); System.out.println( "Received: " + message); // 发送确认,表示已成功处理该消息 channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false ); }; // 开始消费消息,设置自动确认为 false,开启手动确认 channel.basicConsume(QUEUE_NAME, false , deliverCallback, consumerTag -> {}); } } } |
4.兜底方案,即死信队列,你可能会问"消费者未能消费的,不做确认不就好了,消息依旧在rabbitmq啊,为啥要使用死信队列呢",这里使用死信队列,是为了这些失败的消息避免被重复消息,因为不可控制的原因,消费失败的问题短时间会持续存在,使用死信队列为了给正常的
消息腾空间,同时使用死信队列,也是为了更好的分析失败原因,总体来说就是好坑位要留给需要的人
java代码使用死信队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import com.rabbitmq.client.*; public class DeadLetterProducer { private final static String QUEUE_NAME = "main_queue" ; private final static String DLQ_NAME = "dead_letter_queue" ; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost( "localhost" ); try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) { // 创建死信队列 channel.queueDeclare(DLQ_NAME, true , false , false , null ); // 创建主队列并设置死信交换机和路由键 channel.queueDeclare(QUEUE_NAME, true , false , false , Map.of( "x-dead-letter-exchange" , "" , "x-dead-letter-routing-key" , DLQ_NAME)); String message = "Message for Dead Letter Queue" ; // 发布消息 channel.basicPublish( "" , QUEUE_NAME, new AMQP.BasicProperties.Builder().deliveryMode( 2 ).build(), message.getBytes()); System.out.println( "Sent to main queue: " + message); } } } |
以上从四个方面介绍保证rabbitmq消息可靠性措施
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
2024-02-28 查询postman版本号
2023-02-28 Vue简单使用
2023-02-28 使用StringRedisTemplate实现redis分布式锁
2022-02-28 java.io.FileNotFoundException: class path resource [templates/] cannot be resolved to absolute file path because it does not reside in the file system
2022-02-28 idea整合简单的oauth2认证服务器和资源认证服务器
2022-02-28 idea整合mybatis实现简单分页(一)