RabbitMQ unfair distribution and prefetching (channel.basicQos)

Posted by ajfton on Sun, 13 Feb 2022 10:17:55 +0100

Qos (Quality of Service) concept:

When the network is congested, all data streams may be discarded; In order to meet the requirements of users for different applications and different service quality, the network needs to be able to allocate and schedule resources according to the requirements of users, and provide different service quality for different data streams: give priority to the processing of real-time and important data packets; For ordinary data packets with weak real-time performance, it provides lower processing priority and even discards them in case of network congestion. QoS came into being. Devices supporting QoS function can provide transmission quality service; For a certain type of data flow, it can be given a certain level of transmission priority to identify its relative importance, and use various priority forwarding strategies, congestion avoidance and other mechanisms provided by the device to provide special transmission services for these data flows. The network environment configured with QoS increases the predictability of network performance, effectively allocates network bandwidth and makes more rational use of network resources.

Why set Qos:

In RabbitMQ, the queue sends messages to consumers. If the QoS value is not set, the number of messages in the queue will be sent to consumers, regardless of whether consumers can consume them or not. In this way, a large number of messages without ack may accumulate in the cache. Because these messages have not received the ACK sent by consumers, they can only be temporarily stored in the cache, Wait for ACK and delete the corresponding message. In this case, we hope that developers can limit the size of this buffer to avoid the problem of unlimited unconfirmed messages in the buffer. At this time, you can use basic The QoS method sets the "prefetch count" value to complete. This value defines the maximum number of unacknowledged messages allowed on the channel. Once the number reaches the configured number, RabbitMQ will stop delivering more messages on the channel unless at least one unprocessed message is confirmed. For example, suppose there are unacknowledged messages 5, 6, 7 and 8 on the channel and the prefetch count of the channel is set to 4, At this time, RabbitMQ will not deliver any messages on this channel unless at least one unanswered message is acked. For example, if the message tag=6 has just been confirmed as ACK, RabbitMQ will sense the situation and send another message. Message response and QoS pre value have a significant impact on user throughput. Generally, increasing prefetching will improve the speed of message delivery to consumers. Although the automatic response transmission message rate is the best, in this case, the number of messages delivered but not processed will also increase, which increases the RAM consumption of consumers (random access memory). Care should be taken to use the automatic confirmation mode or manual confirmation mode with infinite preprocessing. Consumers consume a large number of messages if there is no confirmation, The optimal value of 300 can be found by the consumer repeatedly, so the optimal value of 300 can not be found by the consumer repeatedly. The preset value of 1 is the most conservative. Of course, this will make the throughput very low, especially when the consumer connection delay is very serious, especially in the environment where the consumer connection waiting time is long. For most applications, a slightly higher value will be the best.

Qos value:

Make a balance between transmission efficiency and consumer consumption speed. This value needs to be tried constantly because it is too low and the efficiency of channel message transmission is too low. If it is too high, consumers will not have time to confirm the message, resulting in message accumulation and increasing memory consumption.

Unfair distribution

Concept:
If the default message distribution policy is adopted, the message is sent by polling. However, consumers have the problem of processing speed before. If A processes slowly and B processes fast, it is obviously unreasonable for them to accept the same number of messages.
Unfair distribution:
It is under such circumstances that unfair distribution has emerged. In short, those who can do more work, those who can handle faster deal with more, and those who are slow deal with less.
How to achieve unfair distribution:
So how to achieve it? Basic qos is introduced above. If we set the value of qos to 1, what will happen? Only one message is allowed to be transmitted in the channel, so when this message is processed, the queue will immediately send the next message, so at this time, it will be processed quickly and slowly, and then the next message will be processed after the current processing. In this way, those who can do more work are realized.

Code implementation:
producer:

public class Producer {
    public static final String QUEUE_NAME = "test_basic_qos";

    public static final String EXCHANGE_NAME = "test_basic_qos";

    public static void main(String[] args) throws IOException, TimeoutException {
        Channel channel = RabbitMqUtils.getChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"basic.qos");
        Scanner scanner = new Scanner(System.in);
        while(scanner.hasNext()) {
            String message = scanner.next();
            System.out.println("The message sent is:" + message);
            channel.basicPublish(EXCHANGE_NAME,"basic.qos",null,message.getBytes(StandardCharsets.UTF_8));
        }
    }
}

C1 (fast consumer):

public class Consumer02 {
    public static final String QUEUE_NAME = "test_basic_qos";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            try {
                SleepUtils.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("High performance server acceptance:" + new String(message.getBody()));
            channel.basicAck(message.getEnvelope().getDeliveryTag(),false);
        };
        CancelCallback cancelCallback = consumerTag -> {};
        channel.basicConsume(QUEUE_NAME,false,deliverCallback,cancelCallback);
    }
}

C2 (slow consumer):

public class Consumer01 {

    public static final String QUEUE_NAME = "test_basic_qos";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        channel.basicQos(1);
        DeliverCallback deliverCallback = (consumerTag,message) -> {
            try {
                SleepUtils.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Low performance server acceptance:" + new String(message.getBody()));
            channel.basicAck(message.getEnvelope().getDeliveryTag(),true);
        };
        CancelCallback cancelCallback = consumerTag -> {};
        channel.basicConsume(QUEUE_NAME,false,deliverCallback,cancelCallback);
    }
}

result:


Pre value

Concept:
Set the maximum number of messages transmitted by the consumer channel.
Test:
We take the preCount value of slow consumers as 5 and the preCount value of fast consumers as 2, and then send 7 messages (in order to ensure that fast consumers can only process 2 messages, we need to send 7 pieces of data within 2s, so as to ensure that all subsequent messages are sent to slow consumers, so as to prevent fast consumers from sending subsequent messages after processing messages.)
code:
Refer to the above code, but modify the qos value.
result:



analysis:
Because the fast consumer channel is full and can no longer send messages, messages can only be sent to slow servers. This is the usage of basicQos.

Topics: Java network RabbitMQ