RabbitMQ成长篇之如何保证消息的可靠性是(三)

上一遍我们学会了怎么使用RabbitMQ发送消息和消费消息,在文章末尾给大家了留下了许多问题,这一章咱们就去一一解决那些问题,还没有去看的同学可以去看看哦!此篇也是在上一遍基础进行改造!RabbitMQ之入门篇(二)_想成为大佬的小卒!的博客-CSDN博客

一.发送方确认机制

        1.1单条确认机制

                首先发送方调用channel.confirmSelect()方法, 调用channel.waitForConfirms()方法,等待确认,代码如下

        

​

package rabbitmq.demo.controller;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
/**
 * 相当于生产者
 * @Author sj
 * @Date: 2022/04/18/ 10:58
 * @Description
 */
@RestController
@Slf4j
public class ProducerController {
    /**
     * 序列化类
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 模拟MQ发送消息
     * @param userPo
     */
    @PostMapping("/send")
    public void sendNews(@RequestBody UserPo userPo) throws JsonProcessingException {
        // 获取连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置端口
         connectionFactory.setHost("localhost");
         // 获取于Broker的TCP连接connection
        Connection connection;
        // 序列化对象
        String body = objectMapper.writeValueAsString(userPo);
        // 获取字节码,因为MQ底层是使用字节码传输,方便下面使用
        byte[] bytes = body.getBytes();
        try {
            connection = connectionFactory.newConnection();
            // 创建信道
            Channel channel = connection.createChannel();
            // 启用发送方确认机制
            channel.confirmSelect();
            // 向交换机发送消息
            channel.basicPublish(
                    // 发送到那个交换机
                    "consumer.exchange",
                    // routingKye是那个
                    "key.send",
                    // 是否有特殊参数
                    null,
                    // 消息体
                    bytes
                    );
            // 发送方发送消息成功
            log.info("消息发送成功");
            // 发送方确认机制
            if (channel.waitForConfirms()){
                 // 此处我们就可以进行一些相应的业务处理
                log.info("RabbitMQ confirm success");
            }else {
                log.info("RabbitMQ confirm smessage");
            }
            // 关闭连接
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
 
}

​

启动项目访问接口,由图可以看到消息发送成功了,确认机制也的确返回了是否发送成功的信息,我们就可以根据自己的业务进行相应的处理

         1.2多条确认机制(不太建议使用)

                首先发送方调用channel.confirmSelect()方法, 调用channel.waitForConfirms()方法,等待确认,代码如下

    我们修改代码,以达到多条消息发送的情况

package rabbitmq.demo.controller;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
/**
 * 相当于生产者
 * @Author sj
 * @Date: 2022/04/18/ 10:58
 * @Description
 */
@RestController
@Slf4j
public class ProducerController {
    /**
     * 序列化类
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 模拟MQ发送消息
     * @param userPo
     */
    @PostMapping("/send")
    public void sendNews(@RequestBody UserPo userPo) throws JsonProcessingException {
        // 获取连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置端口
         connectionFactory.setHost("localhost");
         // 获取于Broker的TCP连接connection
        Connection connection;
        // 序列化对象
        String body = objectMapper.writeValueAsString(userPo);
        // 获取字节码,因为MQ底层是使用字节码传输,方便下面使用
        byte[] bytes = body.getBytes();
        try {
            connection = connectionFactory.newConnection();
            // 创建信道
            Channel channel = connection.createChannel();
            // 启用发送方确认机制
            channel.confirmSelect();
            for (int i=0 ; i<10;i++) {
                // 向交换机发送消息
                channel.basicPublish(
                        // 发送到那个交换机
                        "consumer.exchange",
                        // routingKye是那个
                        "key.send",
                        // 是否有特殊参数
                        null,
                        // 消息体
                        bytes
                );
                // 发送方发送消息成功
                log.info("消息发送成功");
            }
                // 发送方确认机制
                if (channel.waitForConfirms()){
                    log.info("RabbitMQ confirm success");
                }else {
                    log.info("RabbitMQ confirm smessage");
                }

            // 关闭连接
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
 
}

 由图可见多条消息发送成功,但是我想大家也感觉到问题的所在,如果消息都发送成功了还好,但是如果其中有一条消息失败了,返回false,就出问题了,我们怎么知道是那一条消息失败了,怎么去排查勒,怎么去处理,不可能我们全部重发吧,所以不太建议大家使用

         1.3异步确认消息机制

                首先配置channel,channel.confirmSelect()方法,然后new ConfirmLisnener,覆写方法,成功调用addConfirmListnener,发送消息后,会回调此方法通知是否发送成功,异步确有可能单条,也可能是多条,取绝于MQ

修改代码如下:

package rabbitmq.demo.controller;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
/**
 * 相当于生产者
 * @Author sj
 * @Date: 2022/04/18/ 10:58
 * @Description
 */
@RestController
@Slf4j
public class ProducerController {
    /**
     * 序列化类
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 模拟MQ发送消息
     * @param userPo
     */
    @PostMapping("/send")
    public void sendNews(@RequestBody UserPo userPo) throws JsonProcessingException {
        // 获取连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置端口
         connectionFactory.setHost("localhost");
         // 获取于Broker的TCP连接connection
        Connection connection;
        // 序列化对象
        String body = objectMapper.writeValueAsString(userPo);
        // 获取字节码,因为MQ底层是使用字节码传输,方便下面使用
        byte[] bytes = body.getBytes();
        try {
            connection = connectionFactory.newConnection();
            // 创建信道
            Channel channel = connection.createChannel();
            ConfirmListener confirmListener = new ConfirmListener() {
                // 成功回调此方法
                @Override
                public void handleAck(long deliveryTag, boolean multiple) throws IOException {
                    log.info("ACK, deliveryTag:{} multiple:{}",deliveryTag,multiple);
                }

                // 失败回调此方法
                @Override
                public void handleNack(long deliveryTag, boolean multiple) throws IOException {
                    log.info("NACK, deliveryTag:{} multiple:{}",deliveryTag,multiple);
                }
            };
            // 启用发送方确认机制
            channel.confirmSelect();
            channel.addConfirmListener(confirmListener);
            for (int i=0 ; i<10;i++) {
                // 向交换机发送消息
                channel.basicPublish(
                        // 发送到那个交换机
                        "consumer.exchange",
                        // routingKye是那个
                        "key.send",
                        // 是否有特殊参数
                        null,
                        // 消息体
                        bytes
                );
                // 发送方发送消息成功
                log.info("消息发送成功");
            }
            Thread.sleep(1000000);
            // 发送方确认机制
            if (channel.waitForConfirms()){
                log.info("RabbitMQ confirm success");
            }else {
                log.info("RabbitMQ confirm message");
            }

            // 关闭连接
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
 
}

图中的deliveryTag代表消息序号,multiple代表消息是否发送成功,怎么看出是异步的了,看前面的线程编号是不是不一样?

 二.消息返回机制(消息是否正确被路由)

        1.消息返回机制的原理:消息发送后,中间件会对消息进行路由,如果没有发现目标队列,中间件会通知方式方,此时会回调ReturenLisnener方法,

        2.如何开启?

                在RabbitMQ基础配置中有一个关键配置想;mandtory,弱为false,RabbitMQ将直接丢弃无法路由的消息,若为ture,则不会

修改代码

package rabbitmq.demo.controller;
 
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.*;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
/**
 * 相当于生产者
 * @Author sj
 * @Date: 2022/04/18/ 10:58
 * @Description
 */
@RestController
@Slf4j
public class ProducerController {
    /**
     * 序列化类
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 模拟MQ发送消息
     * @param userPo
     */
    @PostMapping("/send")
    public void sendNews(@RequestBody UserPo userPo) throws JsonProcessingException {
        // 获取连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置端口
         connectionFactory.setHost("localhost");
         // 获取于Broker的TCP连接connection
        Connection connection;
        // 序列化对象
        String body = objectMapper.writeValueAsString(userPo);
        // 获取字节码,因为MQ底层是使用字节码传输,方便下面使用
        byte[] bytes = body.getBytes();
        try {
            connection = connectionFactory.newConnection();
            // 创建信道
            Channel channel = connection.createChannel();
            ConfirmListener confirmListener = new ConfirmListener() {
                // 成功回调此方法
                @Override
                public void handleAck(long deliveryTag, boolean multiple) throws IOException {
                    log.info("ACK, deliveryTag:{} multiple:{}",deliveryTag,multiple);
                }

                // 失败回调此方法
                @Override
                public void handleNack(long deliveryTag, boolean multiple) throws IOException {
                    log.info("NACK, deliveryTag:{} multiple:{}",deliveryTag,multiple);
                }
            };
            // 启用发送方确认机制
            channel.confirmSelect();
            channel.addConfirmListener(confirmListener);
            channel.addReturnListener(new ReturnListener() {
                // 消息路由失败会调用此方法
                @Override
                public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    log.info("Message Return:replyCode:{},replyText:{},exchange:{},routingKey:{},properties:{},body:{body}"
                    ,replyCode,replyText,exchange,properties,body);
                }
            });
            for (int i=0 ; i<10;i++) {
                // 向交换机发送消息
                channel.basicPublish(
                        // 发送到那个交换机
                        "consumer.exchange",
                        // routingKye是那个
                        "key.send",
                        true,
                        // 是否有特殊参数
                        null,
                        // 消息体
                        bytes
                );
                // 发送方发送消息成功
                log.info("消息发送成功");
            }
            Thread.sleep(1000);
            // 发送方确认机制
            if (channel.waitForConfirms()){
                log.info("RabbitMQ confirm success");
            }else {
                log.info("RabbitMQ confirm message");
            }

            // 关闭连接
            channel.close();
            connection.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
 
}

由图可以看出,我们的消息返回机制回调方法了,我们就可以在消息没有被正确路由的时候,在回调方法里面进行相应的业务处理

 当然也就new ReturnCallback覆写handle方法,小编就不写了,他们的区别就是一个返回的对像,一个返回的参数!

三.消费端确认机制

        消息一般默认是为自动签收ack,然后我们把ack改为false,就是手动签收,去消费者方修改代码

package rabbitmq.demo.controller;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
 
import java.io.IOException;
import java.util.concurrent.TimeoutException;
 
/**
 * 消费者 监听消息
 * @Author sj
 * @Date: 2022/04/18/ 11:13
 * @Description
 */
@Service
@Slf4j
public class Consumer {
    /**
     *序列化类
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    Channel channel;
    /**
     * 异步线程
     * 声明消息对列、交换机、绑定消息的处理
     * 监听对列
     */
    @Async
    public  void handleMessage() throws IOException, TimeoutException, InterruptedException {
        // 创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置端口
         connectionFactory.setHost("localhost");
         // 创建于broker的Tcp连接
        try(Connection connection = connectionFactory.newConnection()){
            // 创建信道
            this.channel = connection.createChannel();
            // 创建交换机
            channel.exchangeDeclare(
                    // 交换机名字
                    "consumer.exchange",
                    // 交换机类型
                    BuiltinExchangeType.DIRECT,
                    // 数据是否持久化
                    true,
                    // 不用了是否删除
                    false,
                    // 是否需要特殊参数
                    null
            );
            channel.queueDeclare(
                    // 对列名
                    "key.consumer",
                    // 数据持久化
                    true,
                    // 是否独占吃列
                    false,
                    // 不用了是否删除
                    false,
                    // 是否需要特殊参数
                    null
            );
            // 对列和交换机进行绑定
            channel.queueBind(
                    "key.consumer",
                    "consumer.exchange",
                    "key.send"
 
            );
            // 监听对列
            channel.basicConsume(
                    // 监听那个对列
                    "key.consumer",
                    // 手动签收
                    false,
                    // 消息处理
                    deliverCallback,
                    consumerTag -> {}
 
            );
            while (true){
                Thread.sleep(1000000);
            }
        }
 
    }
 
    /**
     * 接收消息的处理
     */
    DeliverCallback deliverCallback = (consumerTag, message) -> {
        //multiple为false表示接收单条消息
        channel.basicAck(message.getEnvelope().getDeliveryTag(),false);
        System.out.println("n1");
        log.info("consumerTag是:{}",consumerTag);
        // 转成String
        String messageBody=new String(message.getBody());
        // 序列化成对象
        UserPo user = objectMapper.readValue(messageBody, UserPo.class);
        // 然后接下来就对对象进行操作,我这里就打印一下就好了
        log.info("接收到的对象是:{}",user);
    };
}

可以看到代码中我把ack改为false了,然后在处理消息的时候添加了如下代码,这里也叫表示为手动签收了,如果想签收多条就把multiple改为ture,然后大家可以把字段代码注释叼,然后在访问,然后去看MQ可视化界面,就会看到消息未被消费,

//multiple为false表示接收单条消息
channel.basicNack(message.getEnvelope().getDeliveryTag(),false);

 

四.重回对列(不建议)

        在手动签收时,添加requeue为true代表重回对列

//multiple为false表示接收单条消息,requeue表示重回对列
channel.basicNack(message.getEnvelope().getDeliveryTag(),false,true);

五.消费端限流机制

        实际场景;业务高峰期,有个微服务崩溃了,崩溃期间堆压了大量消息,微服务上线后,突然收到大量并发消息,所以RabbitMQ开发了Qos功能,前提是手动签收

消费端限流机制参数:

如何开启:在channel监听对列前开启,代码如下: 好处就是避免,服务崩溃,重起时,消息堆积在一个消费端处等待消费;这样其他的消费者就没办法分担压力

// 同时只能处理2条消息
channel.basicQos(2);

 

六:消息过期机制

        对列爆满怎么办:

                默认情况下,消息进入对列,会永远存在,直到被消费,如果大量消息堆积就会给RabbitMQ产生很大的压力,所以就需要使用到RabbitMQ(TTL)的消息过期时间,防止消息大量积压。

        RabbitMQ的过期时间称为TTL,生存时间,过期又分为消息TTL和对列TTL,TTL设置应该长于服务的重启时间

单条消息过期时间:修改代码如下:先设置过期时间,发送对列把特殊参数改为过期时间

AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10S").build();
for (int i=0 ; i<10;i++) {
    // 向交换机发送消息
    channel.basicPublish(
            // 发送到那个交换机
            "consumer.exchange",
            // routingKye是那个
            "key.send",
            true,
            // 是否有特殊参数
            properties,
            // 消息体
            bytes
    );

设置队列里消息过期时间:声明队列时添加如下代码

   // 设置统一队列消息过期时间
            HashMap<String, Object> args= new HashMap<>(16);
            args.put("x-message-ttl",15000);
            channel.queueDeclare(
                    // 对列名
                    "key.consumer",
                    // 数据持久化
                    true,
                    // 是否独占吃列
                    false,
                    // 不用了是否删除
                    false,
                    // 是否需要特殊参数
                    args
            );

也可以设置设置队列的过期时间,一般不用当队列在这段时间没有消息来时M队列会被删除,很严重的

args.put("x-expire",1500)

七.死信队列

        消息设置了过期时间,到时间我们就要移入死信队列

       什么是死信队列:

                对列被配置了DLX属性,当一个消息变成死信后,可以重新被发布到liwai一个Exchange,这个也是一个普通的交换机,然后会进入一个固定的队列

怎么样成为死信:

        消息被拒绝,且requeue=false

        消息过期

        队列达到最大的长度

 准备一个新的对列 和交换机并且进行绑定,,对以前的设置了TTL对列,设置死信属性,当过期时间到了,就会重新路由到我们准备的固定处理过期的死信

package rabbitmq.demo.controller;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
 
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.TimeoutException;
 
/**
 * 消费者 监听消息
 * @Author sj
 * @Date: 2022/04/18/ 11:13
 * @Description
 */
@Service
@Slf4j
public class Consumer {
    /**
     *序列化类
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    Channel channel;
    /**
     * 异步线程
     * 声明消息对列、交换机、绑定消息的处理
     * 监听对列
     */
    @Async
    public  void handleMessage() throws IOException, TimeoutException, InterruptedException {
        // 创建工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 设置端口
         connectionFactory.setHost("localhost");
         // 创建于broker的Tcp连接
        try(Connection connection = connectionFactory.newConnection()){
            // 创建信道
            this.channel = connection.createChannel();
            // 创建交换机
            channel.exchangeDeclare(
                    // 交换机名字
                    "exchange.dlx",
                    // 交换机类型
                    BuiltinExchangeType.TOPIC,
                    // 数据是否持久化
                    true,
                    // 不用了是否删除
                    false,
                    // 是否需要特殊参数
                    null
            );
            channel.queueDeclare(
                    // 对列名
                    "queue.dlx",
                    // 数据持久化
                    true,
                    // 是否独占吃列
                    false,
                    // 不用了是否删除
                    false,
                    // 是否需要特殊参数
                    null
            );
            // 对列和交换机进行绑定
            channel.queueBind(
                    "exchange.dlx",
                    "queue.dlx",
                    "#"

            );
            // 创建交换机
            channel.exchangeDeclare(
                    // 交换机名字
                    "consumer.exchange",
                    // 交换机类型
                    BuiltinExchangeType.DIRECT,
                    // 数据是否持久化
                    true,
                    // 不用了是否删除
                    false,
                    // 是否需要特殊参数
                    null
            );
            // 设置统一队列消息过期时间
            HashMap<String, Object> args= new HashMap<>(16);
            args.put("x-message-ttl",15000);
            // 设置死信属性
            args.put("x-dead-letter-exchange","exchange.dlx");
            channel.queueDeclare(
                    // 对列名
                    "key.consumer",
                    // 数据持久化
                    true,
                    // 是否独占吃列
                    false,
                    // 不用了是否删除
                    false,
                    // 是否需要特殊参数
                    args
            );
            // 对列和交换机进行绑定
            channel.queueBind(
                    "key.consumer",
                    "consumer.exchange",
                    "key.send"
 
            );
            // 同时只能处理2条消息
            channel.basicQos(2);
            // 监听对列
            channel.basicConsume(
                    // 监听那个对列
                    "key.consumer",
                    // 手动签收
                    false,
                    // 消息处理
                    deliverCallback,
                    consumerTag -> {}
 
            );
            while (true){
                Thread.sleep(1000000);
            }
        }
 
    }
 
    /**
     * 接收消息的处理
     */
    DeliverCallback deliverCallback = (consumerTag, message) -> {
        //multiple为false表示接收单条消息,requeue表示重回对列
        channel.basicNack(message.getEnvelope().getDeliveryTag(),false,true);
        System.out.println("n1");
        log.info("consumerTag是:{}",consumerTag);
        // 转成String
        String messageBody=new String(message.getBody());
        // 序列化成对象
        UserPo user = objectMapper.readValue(messageBody, UserPo.class);
        // 然后接下来就对对象进行操作,我这里就打印一下就好了
        log.info("接收到的对象是:{}",user);
    };
}

如果有同学启动报错,记得去可视化界面删除对列,然后在启动,其他情况小编就不测试了,有兴趣的朋友可以试试哦!后面会持续更新更多RabbitMQ的使用;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RabbitMQ中可以通过持久化和确认机制来保证消息可靠性。 1. 持久化:通过将消息标记为持久化,可以确保消息RabbitMQ重启后不会丢失。可以在发送消息时设置消息的delivery_mode属性为2,表示将消息标记为持久化。同时,还需要将队列和交换机都设置为持久化,以确保它们在RabbitMQ重启后不会丢失。 2. 确认机制:RabbitMQ提供了确认机制来确保消息可靠性。生产者在发送消息后,可以等待RabbitMQ的确认回执。如果收到了确认回执,表示消息已经被正确地投递到了队列中。如果没有收到确认回执,生产者可以选择重新发送消息。确认机制可以通过设置channelconfirm_select属性来启用。 下面是一个示例代码,演示了如何在RabbitMQ保证消息可靠性: ```python import pika # 连接到RabbitMQ服务器 connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) channel = connection.channel() # 创建一个持久化的队列 channel.queue_declare(queue='my_queue', durable=True) # 发送一条持久化的消息 channel.basic_publish(exchange='', routing_key='my_queue', body='Hello, RabbitMQ!', properties=pika.BasicProperties( delivery_mode=2 # 设置消息的delivery_mode属性为2,表示持久化 )) # 启用确认机制 channel.confirm_select() # 等待确认回执 if channel.wait_for_confirms(): print("消息已成功投递到队列中") else: print("消息投递失败") # 关闭连接 connection.close() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值