Last time I took you to see the basic concept of RabbitMQ. Today we will explain the five kinds of queues of RabbitMQ in detail, which is also a note. Later I forget it. You can review it. If you think my brother's article is helpful to you, pay attention to my little brother, and your support is my greatest encouragement.
@[toc]
1. Simple queue
The producer sends the message to the "hello" queue. Consumers receive messages from this queue.
① pom file
rabbitmq dependency package must be imported
<dependency> <groupId>com.rabbitmq</groupId> <artifactId>amqp-client</artifactId> <version>3.4.1</version> </dependency>
②. Tools
package com.spiritmark.rabbitmq.util; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; public class RabbitUtil { public static Connection getConnection(String virtual,String username,String password,int port) throws IOException { ConnectionFactory factory = new ConnectionFactory(); // Set virtual host address factory.setVirtualHost(virtual); //Set login user factory.setUsername(username); //Set password factory.setPassword(password); //Set port number factory.setPort(port); return factory.newConnection(); } }
③ Producer
package com.spiritmark.simple; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Producer { private final static String QUEUE_NAME = "hello"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration (creation) queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Define message content String message = "hello rabbitmq "; //5. Release information channel.basicPublish("",QUEUE_NAME,null,message.getBytes()); System.out.println("[x] Sent'"+message+"'"); //6. Close the channel channel.close(); //7. Close the connection connection.close(); } }
④. Consumer
package com.spiritmark.simple; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer { private final static String QUEUE_NAME = "hello"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //5. Listening queue /* true:Indicates automatic confirmation. As long as the message is obtained from the queue, the message will be considered to have been successfully consumed no matter whether the consumer has successfully consumed the message or not. false:Indicates manual confirmation. After the consumer obtains the message, the server will mark the message as unavailable and wait for the consumer's feedback. If the consumer has not responded, the message will remain unavailable, and the server will think that the consumer has hung up and will not give it again Send a message until the consumer gives feedback. */ channel.basicConsume(QUEUE_NAME,true,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" [x] Received '" + message + "'"); } } }
Note that there are two modes for consumers to confirm messages automatically and manually.
2. work mode
One producer corresponds to more than one consumer, but only one consumer can get the message!
Competitive consumer model.
①. Producers
package com.spiritmark.workqueue; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Producer { private final static String QUEUE_NAME = "work_queue"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration (creation) queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Define message content (publish multiple messages) for(int i = 0 ; i < 10 ; i++){ String message = "hello rabbitmq "+i; //5. Release information channel.basicPublish("",QUEUE_NAME,null,message.getBytes()); System.out.println("[x] Sent'"+message+"'"); //Simulate the delay of sending messages, so as to demonstrate multiple consumers' competitive acceptance of messages Thread.sleep(i*10); } //6. Close the channel channel.close(); //7. Close the connection connection.close(); } }
②. Consumers
Create two consumers here
Consumer 1: sleep 10 ms after receiving a message
package com.spiritmark.workqueue; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer1 { private final static String QUEUE_NAME = "work_queue"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //At the same time, the server will send only one message to the consumer //channel.basicQos(1); //4. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //5. Listen to the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" [x] Received '" + message + "'"); //Consumer 1 sleeps for 10 ms after receiving a message Thread.sleep(10); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
Consumer 2: sleep 1000 ms after receiving a message
package com.spiritmark.workqueue; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer2 { private final static String QUEUE_NAME = "work_queue"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //At the same time, the server will send only one message to the consumer //channel.basicQos(1); //4. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //5. Listen to the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" [x] Received '" + message + "'"); //Consumer 2 sleeps for 1000 milliseconds after receiving a message Thread.sleep(1000); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
③ test results
First, the producer prints 0-9 messages at a time. Next let's look at consumer 1: the result is to print even messages
Consumer 2: the result is to print an odd number of messages
④ analysis results
The message content obtained by consumers 1 and 2 is different, that is to say, the same message can only be obtained by one consumer.
Consumer 1 and consumer 2 get odd messages and even messages respectively, and the number of messages obtained is the same.
As we said earlier, this mode is a competitive consumer mode. A queue is monitored by multiple consumers. Here, two consumers, consumer 1 and consumer 2, sleep for 10 and 1000 milliseconds respectively after getting messages. That is to say, the efficiency of the two consumers to get messages is different, but the result is that the number of messages they get is the same, which is basically the same. It doesn't form a competitive relationship, so what can we do to make consumers with high efficiency get more information, that is, consumers 1 get more information?
PS: in addition to a consumer, the number of messages obtained is the same. Consumer 1 gets 0, 3, 6, 9, consumer 2 gets 1, 4, 7, consumer 3 gets 2, 5, 8.
⑤. There are many talents
channel.basicQos(1);
Add the above code to indicate that the server will send only one message to the consumer at the same time. Consumer 1 and consumer 2 get the message results as follows: ⑥ application scenario
Efficient consumers consume a lot of information. It can be used for load balancing.
3. Publish / subscribe mode
A consumer first sends a message to a switch, which binds to multiple queues, and then is received and consumed by consumers listening to the queues.
Note: X refers to the switch. In RabbitMQ, there are four types of switches: direct, fanout, topic, and headers. The switch here is fanout. We will introduce these switches in detail.
①. Producers
package com.spiritmark.workqueue; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Producer { private final static String QUEUE_NAME = "work_queue"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251", 5672, "/", "guest", "guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration exchange channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); //4. Create message String message = "hello rabbitmq"; //5. Release information channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes()); System.out.println("[x] Sent'" + message + "'"); //6. Close the channel channel.close(); //7. Close the connection connection.close(); } }
②. Consumers
Create two consumers here
Consumer 1: sleep 10 ms after receiving a message
package com.spiritmark.workqueue; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer1 { private final static String QUEUE_NAME = "work_queue"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Bind queue to switch channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,""); //At the same time, the server will send only one message to the consumer channel.basicQos(1); //5. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6. Monitor the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" Consumer 1:" + message + "'"); //Consumer 1 sleeps for 10 ms after receiving a message Thread.sleep(10); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
Consumer 2: sleep 1000 ms after receiving a message
package com.spiritmark.workqueue; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer2 { private final static String QUEUE_NAME = "work_queue"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Bind queue to switch channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,""); //At the same time, the server will send only one message to the consumer channel.basicQos(1); //5. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6. Monitor the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" Consumer 2:" + message + "'"); //Consumer 2 sleeps for 10 ms after receiving a message Thread.sleep(1000); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
Note: the queue names monitored by consumer 1 and consumer 2 are different. We can see from the foreground management system: ③ test results
Both consumer 1 and consumer 2 consumed the message.
ps: This is because both consumer 1 and consumer 2 listen to queues bound by the same switch. If a message is sent to a switch that does not have a queue binding, the message is lost because the switch does not have the ability to store the message and the message can only be stored in the queue.
④ application scenario
For example, when an administrator uploads a new picture of a commodity in a mall system, the foreground system must update the picture, and the log system must record the corresponding log. Then two queues can be bound to the picture upload switch, one for the foreground system to update the picture, and the other for the log system to record the log.
4. Routing mode
①. Producers
package com.spiritmark.routing; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Producer { private final static String EXCHANGE_NAME = "direct_exchange"; public static void main(String[] args) throws Exception { //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251", 5672, "/", "guest", "guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declare the exchanger as direct. channel.exchangeDeclare(EXCHANGE_NAME, "direct"); //4. Create message String message = "hello rabbitmq"; //5. Release information channel.basicPublish(EXCHANGE_NAME, "update", null, message.getBytes()); System.out.println("Sent by producer" + message + "'"); //6. Close the channel channel.close(); //7. Close the connection connection.close(); } }
②. Consumers Consumer 1:
package com.spiritmark.routing; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer1 { private final static String QUEUE_NAME = "direct_queue_1"; private final static String EXCHANGE_NAME = "direct_exchange"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Bind the queue to the switch, and specify the route key as update. channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"update"); channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"delete"); channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"add"); //At the same time, the server will send only one message to the consumer channel.basicQos(1); //5. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6. Monitor the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" Consumer 1:" + message + "'"); //Consumer 1 sleeps for 10 ms after receiving a message Thread.sleep(10); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
Consumer 2:
package com.spiritmark.routing; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer2 { private final static String QUEUE_NAME = "direct_queue_2"; private final static String EXCHANGE_NAME = "direct_exchange"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Bind the queue to the switch, and specify the route key as select. channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"select"); //At the same time, the server will send only one message to the consumer channel.basicQos(1); //5. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6. Monitor the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" Consumer 1:" + message + "'"); //Consumer 2 sleeps for 10 ms after receiving a message Thread.sleep(1000); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
③ test results Let's first look at the code. The producer publishes the message. The specified route key is update. When consumer 1 binds queues and switches, the key is update/delete/add; when consumer 2 binds queues and switches, the key is select.
So we can guess that only consumer 1 can receive and consume the messages sent by producers, while consumer 2 cannot.
④ application scenario
Taking advantage of the characteristics that consumers can selectively receive messages, for example, the background management system of our mall system needs to update the interface display of the foreground system to modify, delete and add goods, while the query operation does not need to, so it is better to separate the two queues to receive messages.
5. Theme mode
①. Producers
package com.spiritmark.topic; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Producer { private final static String EXCHANGE_NAME = "topic_exchange"; public static void main(String[] args) throws Exception { //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251", 5672, "/", "guest", "guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declare the exchanger as direct. channel.exchangeDeclare(EXCHANGE_NAME, "topic"); //4. Create message String message = "hello rabbitmq111"; //5. Release information channel.basicPublish(EXCHANGE_NAME, "update.Name", null, message.getBytes()); System.out.println("Sent by producer" + message + "'"); //6. Close the channel channel.close(); //7. Close the connection connection.close(); } }
②. Consumers
Consumer 1:
package com.spiritmark.topic; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer1 { private final static String QUEUE_NAME = "topic_queue_1"; private final static String EXCHANGE_NAME = "topic_exchange"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Bind the queue to the switch, and specify the route key as update.# channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"update.#"); //At the same time, the server will send only one message to the consumer channel.basicQos(1); //5. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6. Monitor the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" Consumer 1:" + message + "'"); //Consumer 1 sleeps for 10 ms after receiving a message Thread.sleep(10); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
Consumption 2:
package com.spiritmark.topic; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.QueueingConsumer; import com.ys.utils.ConnectionUtil; /** * Create by YSOcean */ public class Consumer2 { private final static String QUEUE_NAME = "topic_queue_2"; private final static String EXCHANGE_NAME = "topic_exchange"; public static void main(String[] args) throws Exception{ //1. Get the connection Connection connection = ConnectionUtil.getConnection("192.168.146.251",5672,"/","guest","guest"); //2. Declaration channel Channel channel = connection.createChannel(); //3. Declaration queue channel.queueDeclare(QUEUE_NAME, false, false, false, null); //4. Bind the queue to the switch, and specify the route key as select.# channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"select.#"); //At the same time, the server will send only one message to the consumer channel.basicQos(1); //5. Define the consumers in the queue QueueingConsumer queueingConsumer = new QueueingConsumer(channel); //6. Monitor the queue and return to completion status manually channel.basicConsume(QUEUE_NAME,false,queueingConsumer); //6. Get information while (true){ QueueingConsumer.Delivery delivery = queueingConsumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" Consumer 1:" + message + "'"); //Consumer 2 sleeps for 10 ms after receiving a message Thread.sleep(1000); //Return to confirmation status channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false); } } }
③ analysis results
The route key of the producer sending message binding is update.Name; the route key of the consumer 1 listening queue and the switch binding is update. ා; the route key of the consumer 2 listening queue and the switch binding is select. ා.
Obviously, consumer 1 will receive a message, while consumer 2 will not.
6. Four types of exchanger
The first five queue modes are introduced, but there are only three. The first is a simple queue, the second is a working mode, and the remaining three are all bound to the switch. In this section, we will introduce the switch in detail.
There are four types of switches: direct, fanout, topic and headers.
The first three correspond to the routing mode, publish / subscribe mode and wildcard mode respectively. The headers switch allows to match the header of AMQP messages instead of the routing key. In addition, the header switch and the direct switch are exactly the same, but the performance is much worse, so the switch is not used basically, and will not be described in detail here.
①,direct
If the routing keys match exactly, the message will be put into the corresponding queue.
②,fanout
When a message is sent to a fanout switch, it places the message on all queues attached to the switch.
③,topic
Set the fuzzy binding method. The "*" operator regards "." as a separator to match a single character; the "ා" operator does not have the concept of blocking. It regards any "." as the matching part of the keyword, which can match multiple characters.
7, summary
As for the five queues of RabbitMQ, actually, the most commonly used is the last theme mode, which makes the operation more comfortable through fuzzy matching. Let's summarize the work mode of queues (the last three queues) with switch participation as follows: