How to ensure the RabbitMQ message queue is 99.99% of consumption?

1. Benpian Summary

In fact, there is one kind of scenarios to consider: When the consumer receives the message, not finished processing business logic, consumers hung up, the news can be considered lost? Such as user orders, the order center sends a message to the RabbitMQ in the queue, the integration center receives this message, ready to give the orders of users increased by 20 points, but the points do not increase the success, the integration center hung himself the resulting data problems.

So how to solve this problem?

To ensure the message is successful consumer spending, RabbitMQ provides a message confirmation mechanism (the Message Acknowledgment) , mainly on the RabbitMQ this article, how to use the message acknowledgment mechanism to ensure the message is successful consumer spending, as consumers avoid sudden and downtime the news caused the loss.

2. Open Ack mode Explicit

We open a consumer code like this:

// 创建队列消费者
com.rabbitmq.client.Consumer consumer = new DefaultConsumer(channel) {
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope,
                               AMQP.BasicProperties properties, byte[] body) throws IOException {
        String message = new String(body, "UTF-8");
        System.out.println("Received Message '" + message + "'");
    }
};
channel.basicConsume(QUEUE_NAME, true, consumer);

The focus here is the channel.basicConsume(QUEUE_NAME, true, consumer);second parameter of the method, let us look at basicConsume () source code:

public String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException {
    return this.basicConsume(queue, autoAck, "", callback);
}

Here autoAck parameter refers to whether automatic confirmation, if set to ture, RabbitMQ will automatically send out a message set to confirm, and then deleted from the memory (or disk), the consumer receives a message regardless of whether the process is successful; if after the set to false, RabbitMQ will wait for the consumer explicitly reply to the confirmation signal will be removed from memory (or disks).

Recommended that autoAck set to false, so consumers have enough time to process the message, do not worry about processing the message during the downtime caused by the consumer message is lost.

At this time, the message on the queue is divided into two parts:

  1. Waiting message delivered to the consumer (Ready lower portion in the drawing)
  2. It has been delivered to the consumer, but has not yet received (UNACKED lower portion in the drawing) message consumer acknowledgment signal

How to ensure the RabbitMQ message queue is 99.99% of consumption?

If RabbitMQ consumers never received a confirmation signal, and the consumption of this message consumers have been disconnected, RabbitMQ will arrange for the message to re-enter the queue, waiting for the next delivery to the consumer, of course, also possible that the consumer or the original By.

RabbitMQ will not set an expiration time of the unconfirmed news that the sole basis for determining whether the message needs to be re-delivered to the consumer is the consumer the message consumer connection is disconnected, the reason for this design is to allow consumers to consume a RabbitMQ time messages can be long, long time.

For ease of understanding, we give a concrete example, if the extension of the producers in our above DurableProducer by:

package com.zwwhnly.springbootaction.rabbitmq.durable;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class DurableProducer {
    private final static String EXCHANGE_NAME = "durable-exchange";
    private final static String QUEUE_NAME = "durable-queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接
        ConnectionFactory factory = new ConnectionFactory();
        // 设置 RabbitMQ 的主机名
        factory.setHost("localhost");
        // 创建一个连接
        Connection connection = factory.newConnection();
        // 创建一个通道
        Channel channel = connection.createChannel();
        // 创建一个Exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "direct", true);
        channel.queueDeclare(QUEUE_NAME, true, false, false, null);
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

        // 发送消息
        String message = "durable exchange test";
        AMQP.BasicProperties props = new AMQP.BasicProperties().builder().deliveryMode(2).build();
        channel.basicPublish(EXCHANGE_NAME, "", props, message.getBytes());

        // 关闭频道和连接
        channel.close();
        connection.close();
    }
}

Then create a new consumer AckConsumer categories:

package com.zwwhnly.springbootaction.rabbitmq.ack;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class AckConsumer {
    private final static String QUEUE_NAME = "durable-queue";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 创建连接
        ConnectionFactory factory = new ConnectionFactory();
        // 设置 RabbitMQ 的主机名
        factory.setHost("localhost");
        // 创建一个连接
        Connection connection = factory.newConnection();
        // 创建一个通道
        Channel channel = connection.createChannel();
        // 创建队列消费者
        com.rabbitmq.client.Consumer consumer = new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body, "UTF-8");
                int result = 1 / 0;
                System.out.println("Received Message '" + message + "'");
            }
        };
        channel.basicConsume(QUEUE_NAME, true, consumer);
    }
}

We first autoAck parameter is set to ture, automatically recognized and deliberately write exceptions in the consumer message, and then run the producer client to write messages to the queue, and then run the consumer client, the message is not found success but consumption It had disappeared:

How to ensure the RabbitMQ message queue is 99.99% of consumption?

How to ensure the RabbitMQ message queue is 99.99% of consumption?

Then we will autoAck to false:

channel.basicConsume(QUEUE_NAME, false, consumer);

Run producer client to write messages to the queue, and then run the consumer client, although this time the consumer client code is still abnormal again, but the message remains in the queue:

How to ensure the RabbitMQ message queue is 99.99% of consumption?

Then we delete the consumer client exception code, restart consumer clients, found that news consumption was successful, but the message has not been Ack:

How to ensure the RabbitMQ message queue is 99.99% of consumption?

How to ensure the RabbitMQ message queue is 99.99% of consumption?

Manually turning off the consumer client found the message went to the Ready state, ready to re-delivery:

How to ensure the RabbitMQ message queue is 99.99% of consumption?

The reason why consume news, but it has still Unacked state, because we did not add explicit Ack codes in the code:

String message = new String(body, "UTF-8");
//int result = 1 / 0;
System.out.println("Received Message '" + message + "'");

long deliveryTag = envelope.getDeliveryTag();
channel.basicAck(deliveryTag, false);

deliveryTag can be seen as a message ID, which is a 64-bit value of length ×××.

At this time, consumers run the client found the message consumer success, and is removed in the queue:

How to ensure the RabbitMQ message queue is 99.99% of consumption?

How to ensure the RabbitMQ message queue is 99.99% of consumption?

End the eggs

Java learning, interviews; documentation, free access to video resources

How to ensure the RabbitMQ message queue is 99.99% of consumption?

Guess you like

Origin blog.51cto.com/14230003/2405277