【RabbitMQ】Consumer之消费模式、消息确认与拒绝 - 基于AMQP 0-9-1

这篇文章主要和大家分享RabbitMQ Consumer端的知识点,主要包括Consumer的消费模式,消息是如何确认以及如何拒绝的,当消息拒绝之后,如何让消息重新进入队列。

推模式

RabbitMQ支持推和拉两种消费模式,推模式就是由Broker向Consumer端推送消息。

下面是示例代码,可以比较直观的看到使用方式。

String queueName = "";
boolean autoAck = false; // 关闭自动确认
String consumerTag = "myConsumerTag"; // 消费者标签,区分同一Channel中的不同消费者
channel.basicQos(64); // 消费端能保持的最大未确认消息数

Consumer consumer = new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println(Thread.currentThread().getName() + " -> consumer : " + consumerTag + " , receive message : " + new String(body));


        // 手动确认消息,envelope.getDeliveryTag()表示消息的编号,确认哪条消息
        // 第二参数:false确认单挑消息,true确认当前deliveryTag之前所有的消息
        channel.basicAck(envelope.getDeliveryTag(), false);
    }
};


channel.basicConsume(queueName, autoAck, consumerTag, consumer);

上面的代码将autoAck设置为false,即手动确认,这样设置很重要,因为可以有效防止消息丢失的问题发生。

手动ack的逻辑是在DefaultConsumer的handleDelivery方法中,当然,在这个方法中还可以处理一些其它逻辑,比如拒绝消息,将消息重新入队等。 这个方法还有几个重载方法,使用方式一样,支持参数不同,但都很简单,小伙伴看一下接口就明白了。

推模式的优点就是消费消息的实时性比较高,但是需要评估消费能力,来控制未确认消息的缓存数量,防止客户端内存溢出。

拉模式

RabbitMQ Consumer客户端的拉模式则是主动从Borker上拉取消息,目前RabbitMQ提供的API只有get方法,而且一次只能拉取一条消息,使用方式也很简单,看下面的示例代码。

GetResponse response = channel.basicGet(QUEUE_NAME , false) ;
System.out.println(new String(response.getBody()));
channel.basicAck(response.getEnvelope().getDeliveryTag(), false);

拉模式中也有autoAck的参数,最好也设置成false,采用手动ack的方式。

拉模式的优点就是自己可以根据当前的负载控制何时可以消费消息,缺点就是消费消息的实时性低,而且有可能造成消息在Broker上的堆积。

消息确认

为保证消息正确的到达Consumer,RabbitMQ提供了Consumer端的确认机制,如何使用在上面的代码示例中已有体现,就是设置autoAck参数控制。设置为false,Broker会等收到Consumer的ack之后,才会将消息打上删除标记,然后从磁盘或者内存中删除。设置为true,Broker发出消息之后,就会把消息移除,不管Consumer是否消费到了消息。

建议autoAck设为false的另外一点,RabbitMQ会一直保存未收到ack的消息,除非消费此消息的Consumer断开连接,RabbitMQ会把消息重新投入队列。RabbitMQ不会给未确认的消息设置TTL,判断消息是否需要重新投递给Consumer的唯一依据就是消费改消息的Consumer已经断开连接。

消息拒绝

Consumer有可能收到错误的消息或者无法处理的消息,而拒绝此消息,RabbitMQ也为此场景提供了相应的API。channel.basicReject 告诉Broker,拒绝消费此消息。来看代码示例。

Consumer consumer = new DefaultConsumer(channel) {
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("consumer : " + consumerTag + " , receive message : " + new String(body));

        // 拒绝消息,重新入队               
        channel.basicReject(envelope.getDeliveryTag(), true);
    }
};

从使用上来看,和消息确认一样,只需将回调函数中的 channel.basicAck 换成 channel.basicReject ,第一个参数的含义和上面channel.basicAck一样,第二个参数表示是否重新入队,true:重新入队,false:直接从队列中移除,不再发送给Consumer。

注意,channel.basicReject 方法一次只能拒绝一条消息。

消息批量拒绝

如果Consumer端需要批量拒绝消息,可以使用channel.nack 方法,它的multiple参数可以控制拒绝单条消息还是批量拒绝消息。具体用法和参数含义参考下面示例代码。

Consumer consumer = new DefaultConsumer(channel) {
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("consumer : " + consumerTag + " , receive message : " + new String(body));

               
        // 第一个参数:当前消息的标识
        // 第二个参数:拒绝之后,是否重新进入队列
        // 第三个参数:是否批量拒绝,true:deliveryTag之前所有的消息都会被拒绝
        channel.basicNack(envelope.getDeliveryTag(), false, false);

    }
};

消息可重入队列

上面消息拒绝和消息批量拒绝的方法提供了参数,控制被拒绝的消息是否重新进入队列,RabbitMQ还提供了一个接口,用于直接将消息重新入队,channal.recover,它的参数默认就是true。使用的时候,需要注意,避免因为代码逻辑的问题造成消息循环入队。

下面的示例代码中重写了handleRecoverOk回调函数,当消息recover成功后,回调此函数。

Consumer consumer = new DefaultConsumer(channel) {
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("consumer : " + consumerTag + " , receive message : " + new String(body));

        // 让消息重新入队
        channel.basicRecover(true);

    }

    // 监听消息recover是否成功
    @Override
    public void handleRecoverOk(String consumerTag) {
        System.out.println(consumerTag);
    }
};

好了,以上Consumer端关于消费模式,消息确认,消息拒绝,消息重新入队的内容了。

RabbitMQ系列文章会陆续更新,欢迎各位小伙伴关注后面的技术分享。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值