Quick start RabbitMQ

Posted by mverrier on Tue, 21 Dec 2021 23:39:59 +0100

1.MQ introduction

1.1 what is MQ

MQ (message queue): translated into message queue. Through the typical producer and consumer model, producers continuously produce messages to the message queue, and consumers continuously obtain messages from the queue. Because the production and consumption of messages are asynchronous, and only care about the sending and receiving of messages, without the intrusion of business logic, it is easy to realize the decoupling between systems. The alias is message middleware, which uses efficient and reliable message passing mechanism for platform independent data exchange, and integrates distributed systems based on data communication.

There are many mainstream message middleware in the market today, such as the old ActiveMQ and RabbitMQ, the hot Kafka, and RocketMQ independently developed by Alibaba.

1.2 different MQ characteristics

1.2.1 ActiveMQ

ActiveMQ is the most popular and powerful open source message bus produced by Apache. It is a message oriented middleware that fully supports the JMS specification. Rich API s and a variety of cluster architecture modes make ActiveMQ an old message middleware in the industry and popular in small and medium-sized enterprises!

  • Advantages: single machine throughput of 10000 class, timeliness of ms class, high availability, high availability based on master-slave architecture, and low message reliability
    Low probability of data loss,

  • Disadvantages: the official community now supports ActiveMQ 5 X maintenance is less and less, and high throughput scenarios are less used

1.2.2 Kafka

Kafka is an open-source distributed publish subscribe messaging system of LinkedIn, and currently belongs to the top project of Apache. Kafka's main feature is to handle message consumption based on Pull mode Kafka pursues high throughput. At the beginning, it was used for log collection and transmission. Version 0.8 supports replication, does not support transactions, and has no strict requirements on message duplication, loss and error,
Data collection business suitable for Internet services that generate a large amount of data.

1.2.3 RocketMQ

RocketMQ is Alibaba's open source message middleware. It is developed in pure Java. It has the characteristics of high throughput, high availability and is suitable for large-scale distributed system applications. RocketMQ originated from Kafka, but it is not a Copy of Kafka. It optimizes the reliable transmission and transaction of messages. At present, it is widely used in transaction, recharge, stream computing, message push, log streaming, binglog distribution and other scenarios in Alibaba group.

  • Advantages: single machine throughput is 100000, availability is very high, distributed architecture, message loss can be achieved, MQ function is relatively perfect, or points
    It is distributed and has good scalability. It supports 1 billion level message accumulation and will not lead to performance degradation due to accumulation.

  • Disadvantages: there are not many supported client languages. At present, java and c + +, of which c + + is immature; Community activity is average, not in MQ
    To implement JMS and other interfaces in the core, some systems need to modify a lot of code to migrate

1.2.4 RabbitMQ

RabbitMQ is an open source message queue system developed in Erlang language and implemented based on AMQP protocol. The main features of AMQP are message oriented, queue oriented, routing (including point-to-point and publish / subscribe), reliability and security. AMQP protocol is more used in scenarios with high requirements for data consistency, stability and reliability in enterprise systems.

RabbitMQ is more reliable than Kafka. Kafka is more suitable for IO high throughput processing. It is generally used in big data log processing or scenarios with slightly lower requirements for real-time (a small amount of delay) and reliability (a small amount of data loss), such as ELK log collection.

1.3 application scenarios of MQ

1.3. 1 asynchronous processing

Scenario Description: after registering, users need to send registration email and registration SMS. There are two traditional methods. 1 Serial mode 2 Parallel mode

  • Serial mode: after the registration information is written into the database, send the registration email, and then send the registration SMS. Only after the above three tasks are completed can it be returned to the client. One problem is that e-mail and SMS are not necessary. It is just a notification, which makes the client wait for things that are unnecessary

  • Parallel mode: after the registration information is written into the database, SMS is sent while sending email. After the above three tasks are completed, it is returned to the client. The parallel mode can improve the processing time.

  • Message queue: it is assumed that the three service nodes use 50ms, 150ms in serial mode and 100ms in parallel. Although the parallel processing time has been improved, as mentioned earlier, e-mail and SMS have no impact on my normal use of the website. The client does not need to wait for its sending to show that the registration is successful. It should return after writing to the database Message queue: after the message queue is introduced, the business logic that is not necessary for sending e-mails and short messages is processed asynchronously


It can be seen that after the introduction of message queue, the user's response time is equal to the time to write to the database + the time to write to the message queue (negligible). After the introduction of message queue post-processing, the response time is three times that of serial and two times that of parallel.

1.3. 2 application decoupling

Scenario: Double 11 is the shopping crazy festival. After the user places an order, the order system needs to notify the inventory system. The traditional practice is that the order system calls the interface of the inventory system

This approach has a disadvantage: when the inventory system fails, the order will fail. Order system and inventory system are highly coupled Import message queue

  • Order system: after the user places an order, the order system completes the persistence processing, writes the message to the message queue, and returns the success of the user's order.

  • Inventory system: subscribe to order messages, obtain order messages, and perform library operations. Even if the inventory system fails, message queuing can ensure the reliable delivery of messages without message loss

1.3. 3. Flow peak shaving

Scenario: the second kill activity usually causes the application to hang up due to excessive traffic. In order to solve this problem, the message queue is usually added to the front end of the application.

effect:

​ 1. The number of active people can be controlled and orders exceeding this certain threshold can be directly discarded (why haven't I succeeded in killing every second ^ ^)

​ 2. It can alleviate the crushing application caused by high traffic in a short time (the application obtains orders according to its maximum processing capacity)

1. After receiving the user's request, the server will first write to the message queue. If the length of the added message queue exceeds the maximum value, the user's request will be discarded directly or jump to the error page

2. The second kill service performs subsequent processing according to the request information in the message queue

2. Introduction and installation of rabbitmq

2.1 basic introduction

RabbitMQ is based on AMQP protocol and developed in erlang language. It is the most widely deployed open source message middleware and one of the most popular open source message middleware.

Official website: https://www.rabbitmq.com/

Official tutorial: https://www.rabbitmq.com/#getstarted

AMQP (advanced message queuing protocol) ` was proposed in 2003. It was first used to solve the problem of message passing interaction between different platforms in the financial field. As the name suggests, AMQP is a protocol, more accurately a binary wire level
protocol.
This is the essential difference between AMQP and JMS. AMQP does not limit from the API layer, but directly defines the data format of network exchange. This makes the provider nature of AMQP cross platform. The following is the AMQP protocol model:


Basic introduction to the working principle of RabbitMQ:

  • Broker: an application that receives and distributes messages. RabbitMQ Server is the Message Broker
  • Virtual host: designed for multi tenant and security reasons, the basic components of AMQP are divided into a virtual group, similar to
    The concept of namespace in network. When multiple different users use the services provided by the same RabbitMQ server, they can be divided into
    Multiple vhosts. Each user creates exchange / queue in his own vhost
  • Connection: TCP connection between publisher / consumer and broker
  • Channel: if a Connection is established every time RabbitMQ is accessed, TCP is established when the message volume is large
    The overhead of connection will be huge and the efficiency will be low. Channel is a logical connection established within the connection. If the application
    The sequence supports multithreading. Usually, each thread creates a separate channel for communication. The AMQP method contains the channel id helper
    The client and message broker recognize channels, so channels are completely isolated. Channel as a lightweight
    Connection greatly reduces the overhead of establishing TCP connection by the operating system
  • Exchange: message arrives at the first stop of the broker and matches the routing key in the query table according to the distribution rules
    Send the message to the queue. Common types are: direct (point-to-point), topic (publish subscribe) and fan out
    (multicast)
  • Queue: the message is finally sent here to wait for the consumer to pick it up
  • Binding: the virtual connection between exchange and queue. The binding can contain routing key, and the binding information is protected
    Stored in the query table in exchange for the distribution basis of message

2.2 download

Official website download address: https://www.rabbitmq.com/download.html


The installation packages to be downloaded are as follows:

Note: the installation package here is CentOS 7 installation package

2.3 installation

# 1. Upload rabbitmq installation package to linux system
	erlang-22.0.7-1.el7.x86_64.rpm
	rabbitmq-server-3.7.18-1.el7.noarch.rpm

# 2. Install Erlang dependency package
	rpm -ivh erlang-22.0.7-1.el7.x86_64.rpm

# 3. Install RabbitMQ installation package (Networking required)
	yum install -y rabbitmq-server-3.7.18-1.el7.noarch.rpm
		be careful:After the default installation is completed, the profile template is displayed in the:/usr/share/doc/rabbitmq-server-3.7.18/rabbitmq.config.example In the directory,need	
				Copy profile to/etc/rabbitmq/In the directory,And change the name to rabbitmq.config
# 4. Copy configuration file
	cp /usr/share/doc/rabbitmq-server-3.7.18/rabbitmq.config.example /etc/rabbitmq/rabbitmq.config

# 5. View profile location
	ls /etc/rabbitmq/rabbitmq.config

# 6. Modify the configuration file (see the figure below:)
	vim /etc/rabbitmq/rabbitmq.config 

Remove%%, and the last comma from the configuration file in the above figure, and modify it to the following figure:

# 7. Execute the following command to start the plug-in management in rabbitmq
	rabbitmq-plugins enable rabbitmq_management
	
	The following description appears:
		Enabling plugins on node rabbit@localhost:
    rabbitmq_management
    The following plugins have been configured:
      rabbitmq_management
      rabbitmq_management_agent
      rabbitmq_web_dispatch
    Applying plugin configuration to rabbit@localhost...
    The following plugins have been enabled:
      rabbitmq_management
      rabbitmq_management_agent
      rabbitmq_web_dispatch

    set 3 plugins.
    Offline change; changes will take effect at broker restart.

# 8. Start the RabbitMQ service
	systemctl start rabbitmq-server
	systemctl restart rabbitmq-server
	systemctl stop rabbitmq-server
	

# 9. Check the service status (see the following figure:)
	systemctl status rabbitmq-server
  ● rabbitmq-server.service - RabbitMQ broker
     Loaded: loaded (/usr/lib/systemd/system/rabbitmq-server.service; disabled; vendor preset: disabled)
     Active: active (running) since III. 2019-09-25 22:26:35 CST; 7s ago
   Main PID: 2904 (beam.smp)
     Status: "Initialized"
     CGroup: /system.slice/rabbitmq-server.service
             ├─2904 /usr/lib64/erlang/erts-10.4.4/bin/beam.smp -W w -A 64 -MBas ageffcbf -MHas ageffcbf -
             MBlmbcs...
             ├─3220 erl_child_setup 32768
             ├─3243 inet_gethost 4
             └─3244 inet_gethost 4
      .........
      
# 10. Turn off the firewall service
	systemctl disable firewalld
    Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
    Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
	systemctl stop firewalld   

# 11. Access the web management interface
	http://10.15.0.8:15672/
# 12. Log in to the management interface. The default user name and password are:
	username:  guest
	password:  guest

2.4 install using Docker

# for RabbitMQ 3.9, the latest series
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.9-management
# for RabbitMQ 3.8,
# 3.8.x support timeline: https://www.rabbitmq.com/versions.html
docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.8-management

3. RabiitMQ configuration

3.1 rabbitmq management command line

# 1. Service startup
	systemctl start|restart|stop|status rabbitmq-server

# 2. The management command line is used to operate RabbitMQ without using the web management interface
	rabbitmqctl  help  You can view more commands

# 3. Plug in management command line
	rabbitmq-plugins enable|list|disable 

3.2 introduction to web management interface

3.2. 1 Overview

  • connections: both producers and consumers need to establish a connection with RabbitMQ before they can complete the production and consumption of messages. You can view the connection here

  • channels: channel. After a connection is established, a channel will be formed. The delivery of messages depends on the channel.

  • Exchanges: a switch used to route messages

  • Queues: queue, that is, message queue. Messages are stored in the queue and wait for consumption. After consumption, they are removed from the queue.

3.2.2 Admin user and virtual host management

1. Add user

The Tags option above actually specifies the user's role. The following options are available:

  • Super administrator

    You can log in to the management console, view all information, and operate user policies.

  • Monitoring

    You can log in to the management console and view the related information of rabbitmq node (number of processes, memory usage, disk usage, etc.)

  • Policy maker

    You can log in to the management console and manage policies at the same time. However, you cannot view the relevant information of the node (the part identified by the red box in the above figure).

  • General manager

    You can only log in to the management console. You cannot see node information or manage policies.

  • other

    Unable to log in to the management console, usually ordinary producers and consumers.

2. Create a virtual host

RabbitMQ adds the concept of Virtual Hosts to enable users to work without interference. In fact, RabbitMQ is an independent access path. Different users use different paths and have their own queues and switches, which will not affect each other.

3. Bind virtual host and user

After creating the virtual host, we also need to add access rights to users. Click add virtual host:

Enter the virtual machine setting interface:

4.RabbitMQ message model

Official DEMO: https://www.rabbitmq.com/getstarted.html

4.1 construction environment

Create Maven project and introduce dependencies:

<dependency>
    <groupId>com.rabbitmq</groupId>
    <artifactId>amqp-client</artifactId>
    <version>5.7.2</version>
</dependency>

Create a tool class RabbitMQUtils to connect RabbitMQ. Because the connection factory is lightweight, repeated creation will reduce performance.

public class RabbitMQUtils {
    private static ConnectionFactory connectionFactory;
    static {
        connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("");
        connectionFactory.setPassword("");
        connectionFactory.setVirtualHost("/");
    }

    //Get connection
    public static Connection getConnection() throws IOException, TimeoutException {
        return connectionFactory.newConnection();
    }
    //Close connections and channels
    public static void closeConnnectionAndChannel(Connection connection, Channel channel){
        try {
            channel.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.2 hello world model

hello world model role description:

  • P: The producer is the program that sends the message
  • C: Consumer: the receiver of the message will always wait for the message to arrive.
  • Queue: message queue, shown in red. Similar to a mailbox, messages can be cached; The producer delivers the message to it, and the consumer takes the message out of it.
1. Developing producers
public class Producer{
    public static void main(String[] args) {
        Connection connection = null;
        Channel channel=null;
        try {
            connection = RabbitMQUtils.getConnection();
            //Create channel
            channel= connection.createChannel();
            //Defines the queue for channel connections
            /**
         Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,Map<String, Object> arguments) 
         
             * queueDeclare Method: bind a queue. If the queue does not exist, create a new one
             * Parameters:
             *   1.queue Queue name
             *   2.durable: Whether to persist the queue. If true, the queue still exists after restarting the RabbitMQ service. Whether to persist messages in the queue needs to be set separately
             *   3.exclusive: Does the queue allow only one Channel to establish a connection
             *   4.autoDelete: Whether to delete the queue automatically after the messages in the queue are consumed
             *   5.arguments: Other parameters
             */
            channel.queueDeclare("hello",true,false,false,null);
            /**
             * basicPublish Method: publish message
             * Parameters:
             * 1. exchange: Defined switch
             * 2.routingKey: Queue name
             * 3.props: Set the properties of the message, such as messageproperties PERSISTENT_ TEXT_ Plan, defining persistent messages
             * 4.body: Message content
             */
            //Release news
            channel.basicPublish("","hello", MessageProperties.PERSISTENT_TEXT_PLAIN,"hello rabbitmq".getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }finally {
            //Close channels and connections
            RabbitMQUtils.closeConnnectionAndChannel(connection,channel);
        }
    }
}
2. Develop consumers
public class Consumer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //Create connection factory
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Queue connected to
        channel.queueDeclare("hello",true,false,false,null);
        //Use DefaultConsumer to get the message content. autoAck: turn on the automatic confirmation mechanism of the message
        channel.basicConsume("hello",true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("String Body:"+new String(body));
            }
        });
        //channel.close();
        //connection.close();

    }
}

Description of the queueDeclare method:

 Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,Map<String, Object> arguments) 
  channel.queueDeclare("hello",true,false,false,null);
	'Parameter 1':Used to declare the queue corresponding to the channel
  'Parameter 2':Used to specify whether to persist the queue
  'Parameter 3':Used to specify whether the queue is exclusive
  'Parameter 4':Used to specify whether the queue is automatically deleted
  'Parameter 5':Additional configuration of queues

4.3 work queue model

Work queues, Also known as (Task queues), task model. When message processing is time-consuming, the speed of message production may be much faster than that of message consumption. In the long run, more and more messages will accumulate and cannot be processed in time. At this time, you can use the work model: let multiple consumers bind to a queue and consume messages in the queue together. In the queue under the automatic response mechanism Once consumed, the message will disappear, so the task will not be repeated.

Role description of work queue model:

  • P: Producer: publisher of the task
  • C1: consumer - 1, get the task and complete it. It is assumed that the completion speed is slow
  • C2: consumer-2: get the task and complete the task. It is assumed that the completion speed is fast
1. Developing producers
public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("work", false, false, false, null);
        for (int i = 0; i < 100; i++) {
            channel.basicPublish("","work",null,(i+"====>Hello!!!I am coming").getBytes());
        }
        RabbitMQUtils.closeConnnectionAndChannel(connection,channel);
    }
}
2. Developing consumers - 1
public class Consumer01 {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("work",false,false,false,null);
        //Set to consume only one message at a time
        channel.basicQos(1);
        /*
         *Those who can do more work:
         * Cancel automatic determination mechanism
         * Set to consume only one message at a time
         * Manual confirmation message
         */
        channel.basicConsume("work",false,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.1 Consumer01 has handled message:"+new String(body));
                //Manual confirmation message
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }
}
3. Consumer development - 2
public class Consumer02 {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare("work",false,false,false,null);
        channel.basicQos(1);
        channel.basicConsume("work",false,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("No.2 Consumer01 has handled message:"+new String(body));
                channel.basicAck(envelope.getDeliveryTag(),false);
            }
        });
    }
}
4. Test results


When automatic message confirmation is turned off and manual message confirmation is turned on, it can be seen that consumer 1 has consumed more messages.

Without turning off RabbitMQ's automatic message confirmation mechanism, that is, by default, RabbitMQ will send each message to the next consumer in order. On average, each consumer receives the same number of messages. This way of distributing messages is called a loop`

4.4 broadcast model (fanout)

fanout is also called broadcast

In broadcast mode, the message sending process is as follows:

  • There can be multiple consumers
  • Each consumer has its own queue
  • Each queue is bound to an Exchange (switch)
  • The message sent by the producer can only be sent to the switch. The switch determines which queue to send, but the producer cannot decide.
  • The switch sends messages to all queues that have been bound
  • Consumers in the queue can get the message. Realize that a message is consumed by multiple consumers
1. Developing producers
public class Producer{
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Declared exchange rate
        /*
        Parameters: exchange - name of switch, fanout - type of switch
         */
        channel.exchangeDeclare("logs","fanout");
        channel.basicPublish("logs","",null,"Hello EveryOne!".getBytes());
        RabbitMQUtils.closeConnnectionAndChannel(connection,channel);

    }
}
2. Developing consumers - 1
public class Consumer01 {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Binding switch
        channel.exchangeDeclare("logs","fanout");
        //Create temporary queue
        String queue = channel.queueDeclare().getQueue();
        //Bind temporary queues to exchange switches
        channel.queueBind(queue,"logs","");
        //Processing messages
        channel.basicConsume(queue,true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.1 Consumer Handler the message:"+new String(body));
            }
        });

    }
}

3. Consumer development - 2
public class Consumer02 {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Binding switch
        channel.exchangeDeclare("logs","fanout");
        //Create temporary queue
        String queue = channel.queueDeclare().getQueue();
        //Bind temporary queues to exchange switches
        channel.queueBind(queue,"logs","");
        //Processing messages
        channel.basicConsume(queue,true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.2 Consumer Handler the message:"+new String(body));
            }
        });
    }
}
4. Consumer development - 3
public class Consumer03 {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Binding switch
        channel.exchangeDeclare("logs","fanout");
        //Create temporary queue
        String queue = channel.queueDeclare().getQueue();
        //Bind temporary queues to exchange switches
        channel.queueBind(queue,"logs","");
        //Processing messages
        channel.basicConsume(queue,true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.3 Consumer Handler the message:"+new String(body));
            }
        });
    }
}

Start three consumer tests, you can see the message sent by the producer, and all three consumers can accept it.

4.5 routing model

4.5. 1. Subscription model of Routing - Direct

In Fanout mode, a message will be consumed by all subscribed queues. However, in some scenarios, we want different messages to be consumed by different queues. In this case, Exchange of Direct type will be used.

Under the Direct model:

  • The binding between the queue and the switch cannot be arbitrary, but a routing key should be specified
  • When sending a message to Exchange, the sender of the message must also specify the RoutingKey of the message.
  • Exchange will no longer deliver messages to each bound queue, but will judge according to the Routing key of the message. Messages will be received only if the Routing key of the queue is completely consistent with the Routing key of the message

technological process:

Description of Direct model:

  • P: The producer sends messages to Exchange. When sending messages, a routing key will be specified.
  • 10: Exchange (exchange) receives the producer's message, and then submits the message to the queue that exactly matches the routing key
  • C1: consumer, whose queue specifies the message whose routing key is error
  • C2: consumer, whose queue specifies the messages whose routing key needs to be info, error and warning
1. Developing producers
public class Producer{
    private static final String exchange_name="logs_channel";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Claim switch
        channel.exchangeDeclare(exchange_name,"direct");
        //Publish a message and specify the Routing Key
        channel.basicPublish(exchange_name,"error",null,("This is a [error] message").getBytes());
        channel.basicPublish(exchange_name,"info",null,("This is a [info] message").getBytes());
        channel.basicPublish(exchange_name,"debug",null,("This is a [debug] message").getBytes());
        channel.basicPublish(exchange_name,"warn",null,("This is a [warn] message").getBytes());
        //Release resources
        RabbitMQUtils.closeConnnectionAndChannel(connection,channel);
    }
}
2. Developing consumers - 1
public class Consumer01 {
    private static final String exchange_name="logs_channel";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Claim switch
        channel.exchangeDeclare(exchange_name,"direct");
        //Create temporary queue
        String queue = channel.queueDeclare().getQueue();
        //Bind queue and switch
        channel.queueBind(queue,exchange_name,"error");
        //Consumption news
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.1 Consumer handle :"+new String(body));
            }
        });
    }
}

3. Consumer development - 2
public class Consumer02 {
    private static final String exchange_name="logs_channel";

    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Claim switch
        channel.exchangeDeclare(exchange_name,"direct");
        //Create temporary queue
        String queue = channel.queueDeclare().getQueue();
        //Bind queue and switch
        channel.queueBind(queue,exchange_name,"error");
        channel.queueBind(queue,exchange_name,"info");
        channel.queueBind(queue,exchange_name,"debug");
        //Consumption news
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.2 Consumer handle :"+new String(body));
            }
        });
    }
}
4. Test results

The test producer sends the message that the Route key is error, info, debug and warn. The test results are as follows:

4.5. 2. Subscription model of routing Topic

Compared with Direct, Topic Exchange can route messages to different queues according to the Routingkey. However, Topic Exchange allows the queue to use wildcards when Binding routing keys! This kind of model Routingkey is generally composed of one or more words with "." between them Split, for example: item insert

# Uniform character
		* (star) can substitute for exactly one word.   Only 0 or 1 words can be matched
		# (hash) can substitute for zero or more words.   Match zero, one or more words
# For example:
		audit.#    Match audit irs. Corporate or audit IRS et al
    audit.*   Only match audit.irs
1. Developing producers
public class Producer{
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Declare the switch type as topic and use dynamic routing
        channel.exchangeDeclare("topics","topic");
        //Release news
        channel.basicPublish("topics","user.save",null,"I am [user.save] routingKey".getBytes());
        channel.basicPublish("topics","user.save.id",null,"I am [user.save.id] routingKey".getBytes());
        channel.basicPublish("topics","user",null,"I am [user] routingKey".getBytes());
        channel.basicPublish("topics","user.",null,"I am [user.] routingKey".getBytes());
        channel.basicPublish("topics","username",null,"I am [username] routingKey".getBytes());
        channel.basicPublish("topics","user logout",null,"I am [user logout] routingKey".getBytes());
        RabbitMQUtils.closeConnnectionAndChannel(connection,channel);
    }
}
2. Developing consumers - 1

The * wildcard is used in the bound Routing Key

public class Consumer01 {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Claim switch
        channel.exchangeDeclare("topics","topic");
        //Create temporary queue
        String queue = channel.queueDeclare().getQueue();
        //Bind the queue to the switch and set the dynamic route in the switch
        channel.queueBind(queue,"topics","user.*");
        //Consumption news
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.1 Consumer have consume message:"+new String(body));
            }
        });
    }
}
3. Consumer development - 2

Use # wildcard in the bound Routing Key

public class Consumer02 {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitMQUtils.getConnection();
        Channel channel = connection.createChannel();
        //Claim switch
        channel.exchangeDeclare("topics","topic");
        //Create temporary queue
        String queue = channel.queueDeclare().getQueue();
        //Bind the queue to the switch and set the dynamic route in the switch
        channel.queueBind(queue,"topics","user.#");
        //Consumption news
        channel.basicConsume(queue,true,new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("No.2 Consumer have consume message:"+new String(body));
            }
        });
    }
}
4. Test results

5. Message response mechanism

5.1 concept

A consumer may take some time to complete a task if one of the consumers processes a long task and only completes it
What happens when part of it suddenly hangs up. Once RabbitMQ sends a message to the consumer, it immediately cancels the message
The message is marked for deletion. In this case, a consumer suddenly hangs up, and we will lose the message being processed. And follow-up
A message was sent to the consumer because it could not be received.

In order to ensure that messages are not lost during sending, RabbitMQ introduces a message response mechanism. The message response is that the consumer is receiving
After receiving and processing the message, tell RabbitMQ that it has been processed and RabbitMQ can delete the message.

5.2 automatic response

Once the message is sent, it is considered to have been successfully transmitted. This mode requires the right in terms of high throughput and data transmission security
In this mode, if the connection or channel is closed on the consumer side before the message is received, the message will be lost
No, of course. On the other hand, this model allows consumers to deliver overloaded messages without limiting the number of messages delivered,
Of course, this may cause consumers to receive too many messages that are too late to process, resulting in the backlog of these messages and eventually
This makes the memory run out, and eventually these consumer threads are killed by the operating system, so this mode is only applicable when consumers can efficiently and
Used when these messages can be processed at a certain rate.

5.3 manual response

The relevant methods of message manual response are as follows:

   /**
       Used to acknowledge one or more messages received.
       deliverTag Delivery label of the message
       
     */
    void basicAck(long deliveryTag, boolean multiple) throws IOException;

    /**
     * Reject one or more received messages
     *
     */
    void basicNack(long deliveryTag, boolean multiple, boolean requeue)
            throws IOException;

    /**
     * Reject a received message
     */
    void basicReject(long deliveryTag, boolean requeue) throws IOException;

Description of true and false of multiple:

  • true: it represents batch response to messages not answered on the channel
    For example, if there are messages 5, 6, 7, and 8 transmitting tags on the channel, and the current tag is 8, then at this time
    The unacknowledged messages in 5-8 will be acknowledged
  • false: compared with the above, only messages 5, 6 and 7 with tag=8 will be answered, and the three messages will not be confirmed to receive the message response

The message is answered manually. If the message consumption fails, it will automatically rejoin the queue

If the consumer loses the connection for some reason (its channel is closed, the connection is closed, or the TCP connection is lost), the message will be sent
If an ACK acknowledgement is not sent, RabbitMQ will know that the message has not been fully processed and will re queue it. If other consumers
Yes, it will soon redistribute it to another consumer. In this way, even if a consumer dies occasionally, it can be confirmed
No messages will be lost

6. Use RabbitMQ in springboot

6.1 setting up initial environment

1. Introduce dependency
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2. Configuration file
spring:
  application:
    name: springboot_rabbitmq
  rabbitmq:
    host: 10.15.0.9
    port: 5672
    username: 
    password: 
    virtual-host: /learn

The RabbitTemplate provided by the spring boot starter AMQP package is used to simplify the operation. It can be directly injected into the project

6.2 hello world model

Development producer

   @Autowired
   private RabbitTemplate rabbitTemplate;
   
   @Test
   public void testHello(){
     rabbitTemplate.convertAndSend("hello","hello world");
   }

Develop consumers

   @Component
   @RabbitListener(queuesToDeclare = @Queue("hello"))
   public class HelloCustomer {
   
       @RabbitHandler
       public void receive1(String message){
           System.out.println("message = " + message);
       }
   }

6.2 work model

Development producer

   @Autowired
   private RabbitTemplate rabbitTemplate;
   
   @Test
   public void testWork(){
     for (int i = 0; i < 10; i++) {
       rabbitTemplate.convertAndSend("work","hello work!");
     }
   }

Develop consumers

   @Component
   public class WorkCustomer {
       @RabbitListener(queuesToDeclare = @Queue("work"))
       public void receive1(String message){
           System.out.println("work message1 = " + message);
       }
   
       @RabbitListener(queuesToDeclare = @Queue("work"))
       public void receive2(String message){
           System.out.println("work message2 = " + message);
       }
   }

Note: by default, in the Spring AMQP implementation, Work is fair scheduling. If you need to implement it, you need additional configuration

6.3 Fanout broadcast model

Development producer

   @Autowired
   private RabbitTemplate rabbitTemplate;
   
   @Test
   public void testFanout() throws InterruptedException {
     rabbitTemplate.convertAndSend("logs","","This is a log broadcast");
   }

Develop consumers

   @Component
   public class FanoutCustomer {
   
       @RabbitListener(bindings = @QueueBinding(
               value = @Queue,
               exchange = @Exchange(name="logs",type = "fanout")
       ))
       public void receive1(String message){
           System.out.println("message1 = " + message);
       }
   
       @RabbitListener(bindings = @QueueBinding(
               value = @Queue, //Create temporary queue
               exchange = @Exchange(name="logs",type = "fanout")  //Binding switch type
       ))
       public void receive2(String message){
           System.out.println("message2 = " + message);
       }
   }

6.4 Route routing model

Development producer

   @Autowired
   private RabbitTemplate rabbitTemplate;
   
   @Test
   public void testDirect(){
     rabbitTemplate.convertAndSend("directs","error","error Log information for");
   }

Develop consumers

   @Component
   public class DirectCustomer {
   
       @RabbitListener(bindings ={
               @QueueBinding(
                       value = @Queue(),
                       key={"info","error"},
                       exchange = @Exchange(type = "direct",name="directs")
               )})
       public void receive1(String message){
           System.out.println("message1 = " + message);
       }
   
       @RabbitListener(bindings ={
               @QueueBinding(
                       value = @Queue(),
                       key={"error"},
                       exchange = @Exchange(type = "direct",name="directs")
               )})
       public void receive2(String message){
           System.out.println("message2 = " + message);
       }
   }

6.5 Topic subscription model (dynamic routing model)

Development producer

   @Autowired
   private RabbitTemplate rabbitTemplate;
   
   //topic
   @Test
   public void testTopic(){
     rabbitTemplate.convertAndSend("topics","user.save.findAll","user.save.findAll News of");
   }

Develop consumers

 @Component
   public class TopCustomer {
       @RabbitListener(bindings = {
               @QueueBinding(
                       value = @Queue,
                       key = {"user.*"},
                       exchange = @Exchange(type = "topic",name = "topics")
               )
       })
       public void receive1(String message){
           System.out.println("message1 = " + message);
       }
   
       @RabbitListener(bindings = {
               @QueueBinding(
                       value = @Queue,
                       key = {"user.#"},
                       exchange = @Exchange(type = "topic",name = "topics")
               )
       })
       public void receive2(String message){
           System.out.println("message2 = " + message);
       }
   }

reference resources:
1.https://www.bilibili.com/video/BV1cb4y1o7zz
2.https://www.bilibili.com/video/BV1dE411K7MG
3.RabbitMQ Tutorials

Topics: Java RabbitMQ Spring Boot message queue