RabbitMQ——常见的函数介绍



在前面的案例中,如果开启两个Receive,消息被平均发送给了2个Receive。
然而,很多情况下,我们并不希望消息平均分配,可以对代码做如下修改。
场景:a侦听器处理快,b侦听器处理的慢,我们希望能将更多的消息分配给a。

import cn.swsk.springboot.rgyx.jx.test.ConnectionUtil;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * @author Mr.css
 * @date 2020-11-12 9:31
 */
public class Receive {
    private static final String QUEUE_NAME = "queue_name";

    public static void main(String[] args) {
        try {
            Connection connection = ConnectionUtil.getConnection();
            Channel channel = connection.createChannel();
            channel.queueDeclare(QUEUE_NAME, false, false, false, null);

            //限制消息接收的数量
            channel.basicQos(0,1,false);

            DefaultConsumer consumer = new DefaultConsumer(channel) {

                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                           byte[] body) {
                    String message = new String(body, StandardCharsets.UTF_8);
                    System.out.println("[Receive]:" + message);

                    try {
                        Thread.sleep(500);
                        //手动应答
                        channel.basicAck(envelope.getDeliveryTag(), false);
                    } catch (InterruptedException | IOException e) {
                        e.printStackTrace();
                    }
                }
            };
            //自动应答设置为false
            channel.basicConsume(QUEUE_NAME, false, consumer);
        } catch (IOException | ShutdownSignalException | ConsumerCancelledException e) {
            e.printStackTrace();
        }
    }
}


basicQos()

These settings impose limits on the amount of data the server will deliver to consumers before requiring acknowledgements.Thus they provide a means of consumer-initiated flow control.
这些设置限制了服务器在请求确认之前将发送给消费者的数据量。因此,它们提供了一种消费者发起的流量控制方法。

Qos(Quality of Service)直译是:服务质量,但是感觉,理解为带宽分配、流量控制会更加合理

参数:

prefetchSize:服务器将提供的最大内容量(以字节为单位),如果没有限制则为0,似乎必须为0,程序执行到此报错,说还没有实现不为0的情况。
maximum amount of content (measured in octets) that the server will deliver, 0 if unlimited

prefetchCount:服务器将发送的最大消息数,如果没有限制,则为0。
maximum number of messages that the server will deliver, 0 if unlimited

global:设置是否应用于整个Connection,一个Connection可以有多个Channel,false则只对当前Channel有效。
true if the settings should be applied to the entire channel rather than each consumer

basicConsume()

第二个参数的作用:
如果是true消息一经发送,服务器就认为消息已经收到;如果是false,表示服务器期望取得明确的结果。
true if the server should consider messages acknowledged once delivered; false if the server should expect explicit acknowledgements。


basicAck()

ACK(Acknowledge character) 确认消息、确认字符,详细可收索词条 “ACK应答”。

这个函数可以应答一个或多个消息,第二个参数,true表示截止至目前的所有tag(包括当前tag);false表示只包含当前的tag。
true to acknowledge all messages up to and including the supplied delivery tag; false to acknowledge just the supplied delivery tag.

Envelope

的直译是信封,这个名称非常形象,记录了消息的来源、去向、唯一编码、是否重新投递过。


private final long _deliveryTag;
private final boolean _redeliver;
private final String _exchange;
private final String _routingKey;

_deliveryTag每个channel对应一个tag,每次消息投递或者重新投递,tag都会增加

消息的拒绝策略

与basicAck()功能相反的函数,消息拒绝的两个函数的参数是一样的,basicNack可以一次性拒绝多个
channel.basicNack();
channel.basicReject();

其它需要考虑的问题:
在消息处理过程中,如果发生异常,需要考虑服务降级的策略。
常见的做法,是将消息重新放进队列,当然,这样会产生问题,第二次处理的时候,可能会触发完全相同的异常。
在队列的相关设计中,很容易遇到这种问题,需要根据自己的业务需求进行定制。
(这种问题也会发生在:线程池)