Introduction, installation and use of RabbitMQ

RabbitMQ

RabbitMQ

1.MQ introduction

MQ is called Message Queue. Message Queue (MQ) is an application to application communication method.

2. Use scenario

2.1. Peak shaving

The origin of flow peak shaving

It mainly comes from the business scenarios of the Internet, for example, the Spring Festival train ticket rush to start soon, a large number of users need to rush to buy at the same time; and the well-known Alibaba double 11 seconds kill, In a short time, hundreds of millions of users swarmed in, and the instantaneous flow was huge (high concurrency). For example, 2 million people were ready to rush to buy a product at 12:00 in the morning, but the number of products was limited to about 100-500.

In this way, there are only a few hundred users who can actually buy this product. But in terms of business, seckill hopes more people to participate in it, that is to say, more and more people are expected to come to see and buy the product before rush buying.

However, when the time of rush to buy is up and the user starts to place an order, the lack of back-end server of seckill doesn't want millions of people to launch rush to buy at the same time.

We all know that the processing resources of the server are limited, so when there is a peak, it is easy to cause server downtime and users can not access the situation.

2.2 log processing

2.3 Application decoupling

2.4 asynchronous processing

3. Introduction to rabbitmq

Introduction

RabbitMQ, developed in Erlang, is an open-source message middleware that implements AMQP advanced message queuing protocol.

Advantages:

  • Very good performance, low latency
  • Throughput to 10000
  • Good management interface management tools
  • The community is relatively active

Disadvantages:

  • Relatively low throughput

4. AMQP agreement

Advanced Message Queuing Protocol

5. Single node installation in Windows Environment

Download the installation package

Click to jump to download RabbitMQ page

View the Erlang version required for this RabbitMQ

Download erlang

To install erlang:

Double click the default installation and select the installation directory. The directory cannot have Chinese characters, and the computer name cannot have Chinese characters

Configure erlang environment variables

Open cmd input erl

Install rabbitmq

Activate the rabbitMQ UI management interface:

Run in the sbin directory of rabbit

D:\work\java\rabbitMQ\rabbitmq_server-3.8.3\sbin> rabbitmq-plugins.bat enable rabbitmq_management

Restart service:

Browser access: http://localhost:15672/
Enter username: guest
input password:guest

6. Use of rabbitmq management interface

Browser address bar input: localhost:15672

User name: guest password: Guest

Add user

​ Tags

Admin: Super Administrator

Monitoring: monitor, which can view node information

Policymaker: policy maker (mirror)

​ Management:

​ Impersonator:

​ None

Added an admin password 123456, Tags: Administrator

Add Virtual Host

Virtual Host is equivalent to mysql db

Add: usually starts with "/"


After adding:

to grant authorization:

Set admin to access vhost01

Click user name

Select Virtual Host and Set permission

7.RabbitMQ message type

7.1 simple queue

P: Message producer

Red: queue

C: Consumers

Three objects: producer queue consumer

7.1.1 get ConnectionUtil:

import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class ConnectionUtil {


    /**
     * Get MQ connection
     * @return
     */
    public static Connection getConnection() throws IOException, TimeoutException {
        // Define a connection factory
        ConnectionFactory factory = new ConnectionFactory();

        // Set service address
        factory.setHost("localhost");

        // AMQP 5672
        factory.setPort(5672);

        // vhost
        factory.setVirtualHost("/vhost01");

        // user name
        factory.setUsername("admin");

        // password
        factory.setPassword("123456");

        return factory.newConnection();
    }
}

7.1.2 message producer: Send

public class Send {
    private static final String QUERE_NAME="test_simple_queue";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get a connection
        Connection connection = ConnectionUtil.getConnection();

        // Get a channel from the connection
        Channel channel = connection.createChannel();

        // Declare a queue
        channel.queueDeclare(QUERE_NAME, false, false, false, null);

        String message = "hello simple !";

        channel.basicPublish("", QUERE_NAME, null, message.getBytes());

        System.out.println("send message");

        channel.close();
        connection.close();

    }
}

7.1.3 consumer: Recv

public class Recv {
    private static final String QUERE_NAME="test_simple_queue";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();

        // Create channel
        Channel channel = connection.createChannel();

        // Queue declaration
        channel.queueDeclare(QUERE_NAME, false, false,false, null);

        // Define consumers for the queue
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            // Get arrival message
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

                super.handleDelivery(consumerTag, envelope, properties, body);
                String msgString = new String(body,"utf-8");
                System.out.println("new api recv: " + msgString);
            }
        };

        // listen queue 
        channel.basicConsume(QUERE_NAME, true, defaultConsumer);
    }
}

7.1.4 disadvantages of simple queues:

The coupling is high. The producer corresponds to the consumer one by one (if I want to have multiple messages in the consumer consumption queue, this is not the case). When the queue name is changed, it must be changed at the same time

7.2 work queues, fair distribution polling distribution

7.2.1 why the work queue appears:

simple queues are one-to-one correspondence, and in our actual development, it is effortless for producers to send messages, while consumers generally need to integrate with business. Consumers need to process after receiving messages, which may take time. At this time, there will be a lot of messages in the queues

7.2.2 distribute polling

7.2.2.1 message producer: Send
public class Send {

    public static final String QUEUE_NAME = "test_work_queue";
    /**
     *                  |--> C2
     * P ---> Queue ----|
     *                  |--> C1
     * @param args
     * @throws IOException
     * @throws TimeoutException
     */
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();

        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // send message
        for (int i = 0; i < 50; i++) {
            String msg= "send hello " + i;
            channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
            System.out.println("[WQ] send msg = " + msg);
            Thread.sleep(i*20);
        }
        // close resource
        channel.close();
        connection.close();

    }
}
7.2.2.2 consumer: Recv1:
public class Recv1 {
    public static final String QUEUE_NAME = "test_work_queue";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();
        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);

        // Define a consumer
        Consumer consumer = new DefaultConsumer(channel) {
            // Message arrival, trigger this method
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //super.handleDelivery(consumerTag, envelope, properties, body);
                String msg = new String(body, "utf-8");
                System.out.println("Recv [1] msg = " + msg);
                try{
                    Thread.sleep(2000);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    System.out.println("Recv [1] done!");
                }
            }
        };

        // listen queue 
        boolean autoAck = true;
        channel.basicConsume(QUEUE_NAME, autoAck, consumer);
    }
}
7.2.2.3 consumer: Recv2
public class Recv2 {
    public static final String QUEUE_NAME = "test_work_queue";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();
        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);

        // Define a consumer
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            // Message arrival, trigger this method
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                String msg = new String(body, "utf-8");
                System.out.println("Recv [2] msg = " + msg);
                try{
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally{
                    System.out.println("Recv [2] done!");
                }
            }
        };

        // listen queue 
        boolean autoAck = true;
        channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);
    }
}
7.2.2.4 phenomenon:

Consumer 1 and consumer 2 handle the same number of messages

Consumer 1: even
Consumer 2: odd
This method is called round robin, and the result is that no matter who is busy or who is idle, no more messages will be sent. The task is always one for you and one for me

7.2.3 fair dispatch

Manual receipt required

// MQ sends only one request to the consumer at a time. When the consumer finishes processing the message, it will manually receive the receipt, and then MQ sends another message to the consumer
channel.basicQos(1);

boolean autoAck = false; //false manual receipt, after processing the message, tell MQ
        channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);
7.2.3.1 producers
public class Send {

    public static final String QUEUE_NAME = "test_work_queue";
    /**
     *                  |--> C2
     * P ---> Queue ----|
     *                  |--> C1
     * @param args
     * @throws IOException
     * @throws TimeoutException
     */
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();

        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        /**
         * Before each consumer sends a confirmation message, the message queue does not send the next message to the consumer, and only processes one message at a time
         * Limit sending more than one message to the same consumer
         */
        channel.basicQos(1);

        // send message
        for (int i = 0; i < 50; i++) {
            String msg= "send hello " + i;
            channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
            System.out.println("[WQ] send msg = " + msg);
            Thread.sleep(i*5);
        }
        // close resource
        channel.close();
        connection.close();

    }
}
7.2.3.2 consumer 1
public class Recv1 {
    public static final String QUEUE_NAME = "test_work_queue";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();
        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);

		//  MQ sends only one request to the consumer at a time. When the consumer finishes processing the message, it will manually receive the receipt, and then MQ sends another message to the consumer
        channel.basicQos(1);

        // Define a consumer
        Consumer consumer = new DefaultConsumer(channel) {
            // Message arrival, trigger this method
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //super.handleDelivery(consumerTag, envelope, properties, body);
                String msg = new String(body, "utf-8");
                System.out.println("Recv [1] msg = " + msg);
                try{
                    Thread.sleep(2000);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    System.out.println("Recv [1] done!");

                    // Manual receipt
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };

        // listen queue 
//        boolean autoAck = true; / / auto answer
        boolean autoAck = false; //Manual response
        channel.basicConsume(QUEUE_NAME, autoAck, consumer);
    }
}
7.2.3.3 consumers 2
public class Recv2 {
    public static final String QUEUE_NAME = "test_work_queue";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();
        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);
		//  MQ sends only one request to the consumer at a time. When the consumer finishes processing the message, it will manually receive the receipt, and then MQ sends another message to the consumer
        channel.basicQos(1);
        // Define a consumer
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
            // Message arrival, trigger this method
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                String msg = new String(body, "utf-8");
                System.out.println("Recv [2] msg = " + msg);
                try{
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally{
                    System.out.println("Recv [2] done!");
                    // Manual receipt
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };

        // listen queue 
        boolean autoAck = false; //false manual receipt
        channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);

    }
}
7.2.3.4 phenomenon:

Consumer 2 processes more messages than consumer 1, and has more to offer

7.3 publish/subscribe


1. One producer, multiple consumers
2. Each consumer has its own queue
3. The producer does not send the message directly to the queue, but to the exchange converter exchange
4. Each queue must be bound to the switch
5. The message sent by the producer passes through the switch and reaches the queue. Can realize a message to be consumed by multiple consumers

producer

public class Send {
    public static final String EXCHANGE_NAME = "test_exchange_fanout";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        // Claim switch
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); //distribute

        // send message
        String msg = "hello ps";
        channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes());
        System.out.println("Send msg = " + msg);
        channel.close();
        connection.close();
    }
}

Where's the news?? Lost, because the switch does not have the storage capacity, in rabbitmq only the queue has the storage capacity.
Because there is no queue bound to the switch after declaring the switch, the data is lost

Registration - "email -" SMS "

Consumer 1: Recv1

public class Recv1 {
    public static final String QUEUE_NAME = "test_queue_fanout_email";
    public static final String EXCHANGE_NAME = "test_exchange_fanout";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();
        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);

        // Ensure that only one is distributed at a time
        channel.basicQos(1);

        // Bind to switch forwarder
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

        // Define a consumer
        Consumer consumer = new DefaultConsumer(channel) {
            // Message arrival, trigger this method
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //super.handleDelivery(consumerTag, envelope, properties, body);
                String msg = new String(body, "utf-8");
                System.out.println("Recv [1] msg = " + msg);
                try{
                    Thread.sleep(2000);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    System.out.println("Recv [1] done!");
                    // Manual receipt
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };

        // listen queue 
        boolean autoAck = false;
        channel.basicConsume(QUEUE_NAME, autoAck, consumer);
    }
}

Consumer 2: Recv2

public class Recv2 {
    public static final String QUEUE_NAME = "test_queue_fanout_sms";
    public static final String EXCHANGE_NAME = "test_exchange_fanout";
    public static void main(String[] args) throws IOException, TimeoutException {
        // Get connection
        Connection connection = ConnectionUtil.getConnection();
        // Get channel
        Channel channel = connection.createChannel();
        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);

        // Bind to switch forwarder
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        // Ensure that only one is distributed at a time
        channel.basicQos(1);
        // Define a consumer
        Consumer consumer = new DefaultConsumer(channel) {
            // Message arrival, trigger this method
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //super.handleDelivery(consumerTag, envelope, properties, body);
                String msg = new String(body, "utf-8");
                System.out.println("Recv [2] msg = " + msg);
                try{
                    Thread.sleep(2000);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    System.out.println("Recv [2] done!");
                    // Manual receipt
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };

        // listen queue 
        boolean autoAck = false;
        channel.basicConsume(QUEUE_NAME, autoAck, consumer);
    }
}

7.4. Routing wildcard mode

producer

public class Send {
    public static final String EXCHANGE_NAME = "test_exchange_direct";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        // exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");

        String msg = "hello direct !";
        // routing key
        String routingKey = "info";
        channel.basicPublish(EXCHANGE_NAME, routingKey, null, msg.getBytes());

        System.out.println("send :" + msg);

        channel.close();
        connection.close();

    }
}

Consumer 1: Recv1

public class Recv1 {
    public static final String EXCHANGE_NAME = "test_exchange_direct";
    public static final String QUEUE_NAME = "test_queue_direct_1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        // Declaration queue
        channel.queueDeclare(QUEUE_NAME, false, false, false,null);

        // Bind queue to switch and routingKey
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "error");

        // Ensure that only one is distributed at a time
        channel.basicQos(1);

        // Define a consumer
        Consumer consumer = new DefaultConsumer(channel){
            // Message arrival, trigger this method
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body, "utf-8");
                System.out.println("Recv [1] msg = " + msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally{
                    // Message receipt
                    channel.basicAck(envelope.getDeliveryTag(), false);
                    System.out.println("Recv [1] done!");
                }
            }
        };

        // Listen to queue autoack: false manual receipt (message receipt channel.basicAck(envelope.getDeliveryTag(), false);)
        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

Consumer 2: Recv2

public class Recv2 {
    public static final String EXCHANGE_NAME = "test_exchange_direct";
    public static final String QUEUE_NAME = "test_queue_direct_2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false,null);

        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "error");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "info");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "waring");

        channel.basicQos(1);

        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body, "utf-8");
                System.out.println("Recv [2] msg = " + msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally{
                    channel.basicAck(envelope.getDeliveryTag(), false);
                    System.out.println("Recv [2] done!");
                }
            }
        };

        channel.basicConsume(QUEUE_NAME, false, consumer);
    }
}

7.5.Topics

​ Topic exchange
Match route to a pattern
To match one or more characters
* match one character
For example: Goods#

Products: publish, delete, modify, query

producer

public class Send {
    public static final String EXCHANGE_NAME = "test_exchange_topic";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        // Claim switch
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        String message = "commodity...";

        channel.basicPublish(EXCHANGE_NAME, "goods.delete", null, message.getBytes());

        System.out.println("send message = " + message);

        channel.close();
        connection.close();

    }

}

consumer:

public class Recv1 {
    public static final String EXCHANGE_NAME = "test_exchange_topic";
    public static final String QUEUE_NAME = "test_queue_topic_1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false,false,false,null);

        //Binding:
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.add");

        channel.basicQos(1);

        //Defining consumers
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body, "utf-8");
                System.out.println("[1] recv msg: " + msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally{
                    System.out.println("[1] recv done!");
                    // Manual receipt
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };

        // listen queue 
        channel.basicConsume(QUEUE_NAME, false, consumer);


    }
}

Consumer 2

public class Recv2 {
    public static final String EXCHANGE_NAME = "test_exchange_topic";
    public static final String QUEUE_NAME = "test_queue_topic_2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false,false,false,null);

        //Binding:
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.#");

        channel.basicQos(1);

        //Defining consumers
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body, "utf-8");
                System.out.println("[2] recv msg: " + msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally{
                    System.out.println("[2] recv done!");
                    // Manual receipt
                    channel.basicAck(envelope.getDeliveryTag(), false);
                }
            }
        };

        // listen queue 
        channel.basicConsume(QUEUE_NAME, false, consumer);


    }
}

7.6 RPC manual and automatic message acknowledgment (message acknowledgment mechanism transaction - confirm)

In rabbitmq, we can solve the problem of abnormal data loss of rabbitmq server by persisting data
Question: after the producer sends the message, whether the message has arrived at the rabbitmq server or not is unknown by default
There are two ways:

AMQP implements transaction mechanism

confirm mode

Transaction mechanism:

txSelect txCommit txRollback

txSelect: the user sets the current channel to transaction mode
txCommit: used to commit transactions
txRollback: rollback transaction

producer
public class TxSend {
    public static final String QUEUE_NAME = "test_queue_tx";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        String msg = "hello tx message";

        try{
            // Open transaction
            channel.txSelect();
            channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
            System.out.println(1/0);
            //Commit transaction
            channel.txCommit();
        } catch(Exception e){
            // Rollback transaction
            channel.txRollback();
            System.out.println("send message txRollback");
        } finally{
            channel.close();
            connection.close();
        }
    }

consumer:

public class TxRecv {
    public static final String QUEUE_NAME="test_queue_tx";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        channel.basicConsume(QUEUE_NAME, true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String msg = new String(body, "utf-8");
                System.out.println("recv[tx] msg:" + msg);
            }
        });

    }
}

This mode is still time-consuming, which reduces the message throughput of Rabbitmq

Confirm mode

Implementation principle of producer mode

The producer sets the channel to confirm mode. Once the channel enters confirm mode, all messages published on the channel will be assigned a unique ID (starting from 1). Once the message is delivered to all matching queues, the broker sends an acknowledgement to the producer (containing the unique ID of the message). This enables the producer to know that the message has arrived at the destination queue correctly. If the message and queue are persistent, the acknowledgement message will be sent after the message is written to the disk. The delivery tag field of the acknowledgement message returned by the broker to the producer contains the serial number of the acknowledgement message. In addition, the broker can also set the basic.ack The multiple domain of. Indicates that all messages before this serial number have been processed.

The biggest advantage of Confirm mode is that it is asynchronous

Nack

Turn on confirm mode
channel.confirmSelect();

Programming mode:

1. General waitForCOnfirms()

  1. Send a batch of waitForConfirms in batch
  2. Asynchronous confirm mode: provides a callback

General confirm single general

send

/**
 * Normal mode
 */
public class Send1 {
    public static final String QUEUE_NAME = "test_queue_confirm1";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // The producer calls confirm select to set chancel to confirm mode. Note (an exception will occur if the transaction mechanism is changed to this)
        channel.confirmSelect();

        String msg = "hello confirm message";

        channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());
        System.out.println("send message txRollback");

        // Judge whether the transmission is successful
        if(!channel.waitForConfirms()){
            System.out.println("message send failed");
        } else {
            System.out.println("message send ok");
        }

        channel.close();
        connection.close();
    }
}

Send a batch of waitForConfirms in batch

/**
 * Batch mode
 */
public class Send2 {
    public static final String QUEUE_NAME = "test_queue_confirm2";

    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // The producer calls confirm select to set chancel to confirm mode. Note (an exception will occur if the transaction mechanism is changed to this)
        channel.confirmSelect();

        // Bulk send
        for (int i = 0; i < 10; i++) {
            String msg = "hello confirm message";

            channel.basicPublish("", QUEUE_NAME, null, msg.getBytes());

        }

       System.out.println("send message txRollback");

        // Confirm whether it is sent successfully
        if(!channel.waitForConfirms()){
            System.out.println("message send failed");
        } else {
            System.out.println("message send ok");
        }

        channel.close();
        connection.close();
    }
}

Asynchronous mode

The ConfirmListener() callback method provided by the Channel object contains only deliveryTag (the sequence number of the message issued by the current Channel). We need to maintain an unconfirm message sequence number set for each Channel by ourselves. For each data publish ed, add 1 to the element in the set. Each time the handleAck method is called back, the unconfirm set deletes a corresponding (multiple=false) or multiple (multiple=true) record. From the perspective of program running efficiency, this unconfirm set is better to adopt the ordered set SortedSet storage structure.

producer:

/**
 * asynchronous
 */
public class Send3 {
    public static final String QUEUE_NAME = "test_queue_confirm3";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = ConnectionUtil.getConnection();

        Channel channel = connection.createChannel();

        channel.queueDeclare(QUEUE_NAME, false,false,false, null);

        // The producer calls confirm select to set the channel to confirm mode
        channel.confirmSelect();

        // Store unconfirmed message ID
        final SortedSet<Long> confirmSet = Collections.synchronizedSortedSet(new TreeSet<Long>());

        // Monitor channel
        channel.addConfirmListener(new ConfirmListener(){

            // No problem handleAck
            @Override
            public void handleAck(long deliveryTag, boolean multiple) throws IOException {
                if(multiple){
                    System.out.println("[handleAck]-----multiple true");
                    confirmSet.headSet(deliveryTag+1).clear();
                } else {
                    System.out.println("[handleAck]-----multiple false");
                    confirmSet.remove(deliveryTag);
                }
            }

            // handleNack has a problem
            @Override
            public void handleNack(long deliveryTag, boolean multiple) throws IOException {

                if(multiple){
                    System.out.println("[N]handleNack-----multiple");
                    confirmSet.headSet(deliveryTag + 1).clear();
                } else {
                    System.out.println("[N]handleNack-----multiple false");
                    confirmSet.remove(deliveryTag);
                }
            }
        });

        String msgStr = "ssss";

        while(true){
            long seqNo = channel.getNextPublishSeqNo();
            channel.basicPublish("", QUEUE_NAME, null, msgStr.getBytes());
            confirmSet.add(seqNo);
        }

    }
}

Message response and message persistence

Message response

boolean autoAck = false; //false manual receipt

channel.basicConsume(QUEUE_NAME, autoAck, defaultConsumer);

boolean autoAck =true; (auto ack mode) once rabbitmq distributes the message to the consumer, it will be removed from memory
In this case: if the executing consumer is killed, the processing message will be lost.

boolean autoAck =false; (manual mode). If one consumer hangs up, it will be delivered to other consumers. Rabbitmq supports message response. The consumer sends a message response to tell rabbitmq that I have finished processing this message. You can delete it, and then rabbitmq will delete the message in memory.

Message response is on by default and false by default

Message acknowledgment:

If rabbitmq hangs, the message will still be lost

Message persistence

Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,                             Map<String, Object> arguments) throws IOException;

boolean durable = false;

channel.queueDeclare(QUEUE_NAME, false, false, false,null);

We can't change the boolean durable = false to true in the program. Even if the code is correct, it won't run successfully! Because we have defined a test_work_queue. This queue is persistent. rabbitmq does not allow redefining (different parameters) an existing queue

Exchange (switch forwarder)

On the one hand, it receives messages from producers, and on the other hand, it pushes messages to queues

open relay

void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;

String exchange: switch name

channel.basicPublish("", QUERE_NAME, null, message.getBytes());

Type:

fanout (do not process route key)

Direct (process route key)

Routing mode:

Tags: RabbitMQ Erlang Windows Spring

Posted on Sun, 21 Jun 2020 06:42:52 -0400 by yes3no2