1, rabbitMq concept
rabbitMq is a message oriented middleware that receives and uses messages for third parties. Just like express delivery, merchants are producers, express stations are MQ, and users are consumers.
2, Why rabbitMq
- decoupling
For example, system A of the company needs to push data to other different systems. In this way, the coupling between subsystems becomes higher. System A needs to consider A series of messy factors, such as whether other systems hang up and need to push, wait and wait again. At this time, if rabbitMq is used, system A only needs to consider pushing the data to rabbitMq. If other systems need to consume, they can go to system A to obtain it by themselves, which can effectively decouple system A from other systems. - Peak clipping
For example, the company's business has a peak period. For example, the amount of data written in the morning is w/s, while the bearing capacity of the database is only k/s, the system may crash and get stuck. However, if the message is written to rabbitmq, rabbitmq controls the message reading speed to be less than the system capacity, so that it will not hang up even in peak periods. - asynchronous
For example, system A has requirements. If A certain piece of data is accepted, it needs to be written to system A and other systems, and the time is cumulative. However, if the data is sent to other rabbitmq and written by each system, the writing time will be greatly reduced.
3, Disadvantages of using rabbitMq
- System availability
The addition of rabbitmq leads to the increase of system components and the difficulty of deployment and operation and maintenance. And if rabbitmq hangs up, it will also affect the use of the system.
2. Data consistency
Because rabbitmq is added, the number of issues to be considered will also increase. For example, the message is lost, the message is consumed repeatedly, whether the message is successfully sent but successfully consumed by the consumer, and so on
4, Selection of MQ
name | advantage | shortcoming | Applicable scenario |
---|---|---|---|
activeMQ | The throughput of a single machine is 10000, the timeliness is ms, the availability is high, and the probability of data loss is low. | The official community is now for ActiveMQ 5 The version maintenance of X is less and less, and high-throughput scenarios are less used. | With the emergence of other MQS, the usage of ActiveMQ in the early stage gradually decreases, and it has not been verified by the large-scale throughput scenario, and the community is not very active, so it is not recommended. |
Kafka | Single machine throughput is one million level, timeliness is ms level, availability is very high, and message reliability can be configured with 0 loss. And it is distributed. One data has multiple copies, and a few machines will not lose data when they go down. | When a single machine has more than 64 queues / partitions, the CPU will be significantly higher. The more queues, the higher the response time of sending messages. Consumption failed. Retry is not supported. | It is mainly used for log collection and transmission, which is generally used by large companies |
RocketMQ | The single machine has a throughput of 100000 levels, high availability, supports distributed, message reliability can achieve 0 loss, good scalability, and supports the accumulation of one billion levels of messages. | Not many clients are supported. At present, only java and c + + are supported. | It is mainly used in the financial field and is widely used by Alibaba in order, transaction, reset, message push and other scenarios. |
RabbitMQ | Written in erlang language, it has good performance, 10000 class single machine throughput and timeliness μ s-level, high availability, basically no loss of message reliability, and supports a large number of other languages, with high community activity and high update frequency. | The commercial version needs to be charged, and the learning cost is high. | Convenient interface management and complete functions. If the amount of data is small, it can be recommended for small and medium-sized companies. |
5, Installing rabbitmq
ps: because the required packages are downloaded slowly, they can be downloaded directly from here (those with better network can be ignored): https://download.csdn.net/download/weixin_40496191/80386784
- Because rabbitmq requires erlang support, you need to determine the corresponding relationship between erlang and rabbitmq before downloading the package: https://www.rabbitmq.com/which-erlang.html
- Install ErLang
1) Download: wget https://github.com/rabbitmq/erlang-rpm/releases/tag/v21.3.1/erlang-21.3.1-1.el7.x86_64.rpm
2) Installation: RPM -ivh erlang-21.3.1-1 el7. x86_ 64.rpm
ps1: if the installation is wrong: rabbitmq-server-3.8.8-1 el7. noarch. rpm: not an rpm package (or no manifest). This is because github network access is slow and may not be fully downloaded. Therefore, if wget has a problem, you can choose to log in to the website directly, download the package, and then transfer it to linux!
ps2: the downloaded version el7 is based on linux and can be viewed through uname -a: - Installing RabbitMQ
1) Download dependency: yum install -y socat
2) Download package: wget https://github.com/rabbitmq/rabbitmq-server/releases/tag/v3.8.8/rabbitmq-server-3.8.8-1.el7.noarch.rpm
3) Installation: RPM - IVH rabbitmq-server-3.8.8-1 el7. noarch. rpm
ps: if the installation reports an error and the download is incomplete, the solution is as follows! - Start RabbitMQ: systemctl start RabbitMQ server
- Set RabbitMQ startup self startup: systemctl enable RabbitMQ server
ps1: related commands - close RabbitMQ: rabbitmqctl stop
ps2: related commands - restart RabbitMQ: systemctl restart RabbitMQ server
ps3: related commands - plug-in list: rabbitmq plugins list
ps4: related command - start plug-in: rabbitmq plugins enable XXX (XXX is the plug-in name)
ps5: related commands - Disable plug-ins: rabbitmq plugins disable XXX - Check the status after startup: rabbitmqctl status, systemctl status rabbitmq server
- Create a new user
1) New user: rabbitmqctl add_user admin admin
2) Grant administrator permission: rabbitmqctl set_user_tags admin administrator
3) Set the virtual machine permissions that admin can use: rabbitmqctl add_vhost admin–>rabbitmqctl set_ permissions -p admin admin ".*" ".*" ".*" - Viewing user: rabbitmqctl list_users
- Restart RabbitMQ: systemctl restart RabbitMQ server
- View page: http://192.168.248.10:15672
Enter the account password: admin/admin
Entering this interface indicates that the installation is successful (because some code operations have been done here, the interface is not original, and the newly installed one is somewhat different from mine)
6, RabbitMQ working principle diagram
- producer is the system that sends messages.
- connection: the TCP channel that connects to the RabbitMQ server
- exchange and queue: messages are sent to the switch first, and then forwarded to the queue by the switch according to the rules. A switch can correspond to multiple queues. If the switch is not specified when working, the default switch will be used.
- consumer: the system that consumes the queued messages last.
7, Code implementation - simple work
Workflow
Since our subsequent tests will connect to the rabbitmq server, a public connection class is created here.
- Create public connection class
package com.rabbitmqUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * Create channel * @create 2022-02-08 16:26 * @desc **/ public class RabbitmqUtils { //Queue name public static final String RABBITMQ_QUEUE = "RABBITMQ_QUEUE"; //Switch name public static final String RABBITMQ_EXCHANGE = "RABBITMQ_EXCHANGE"; public static Channel getChannel() throws IOException, TimeoutException { //Create a connection factory ConnectionFactory factory = new ConnectionFactory(); //Factory ip factory.setHost("192.168.248.10"); //user name factory.setUsername("admin"); //password factory.setPassword("admin"); //create link Connection connection = factory.newConnection(); //Acquisition channel Channel channel = connection.createChannel(); return channel; } }
- Create producer
package com.rabbitmq1; import com.rabbitmq.client.Channel; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { //Send a message public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Generate a queue, do not create a switch, go to the default switch //1. Name //2. Whether the queue message is persistent (No: stored in memory, yes: stored in disk. No by default) //3. Whether the queue is only for one consumer. No by default //4. Whether to delete automatically after the last consumer disconnects. //5. Other parameters channel.queueDeclare(RabbitmqUtils.RABBITMQ_QUEUE, true, false, false, null); //Send a message String message = "this is QUEUE_P1"; //Keep sending messages for (int i = 0; i < 10; i++) { Thread.sleep(1000); //1. Switch. The simple version is not considered, and the empty string is directly used, that is, the default switch //2. Route key. Write the queue name directly //3. Parameter, ignore //4. Message body channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, null, (message+i).getBytes()); } System.out.println("Message sent successfully"); } }
- Create consumer
package com.rabbitmq1; import com.rabbitmq.client.*; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 15:34 * @desc **/ public class Consume { //Send a message public static void main(String[] args) throws IOException, TimeoutException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Callback method when the consumer fails to consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption //3. Callback when consumers successfully consume //4. Callback method for consumers to cancel consumption channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, true, deliverCallback, cancelCallback); } }
Start the producer class and check the rabbitmq visual interface. You can find that 10 entries have been written
Start the consumer. The effect is as follows. You can see that the queue message has been consumed. Then it is successful!
ps: if an error is reported, error com rabbitmq. client. impl. Forgivingexceptionhandler - an unexpected connection driver error occurred, admin authorization is required
8, Code implementation - multiple consumers
Working principle diagram
producer
package com.rabbitmq2; import com.rabbitmq.client.Channel; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { //Send a message public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //0 is polling, 1 is unfair distribution, and greater than 1 is the preset value. The default value is 0. After prefetching, unfair distribution is carried out. channel.basicQos(0); //Generating queues, //1. Name //2. Whether the queue message is persistent (No: stored in memory, yes: stored in disk. No by default) //3. Whether the queue is only for one consumer. No by default //4. Whether to delete automatically after the last consumer disconnects. //5. Other parameters channel.queueDeclare(RabbitmqUtils.RABBITMQ_QUEUE, true, false, false, null); //Keep sending messages for (int i = 0; i < 10; i++) { String message="this is Product"+i; //1. Switch. The simple version is not considered, and the empty string can be directly used (default / nameless switch) //2. Route key. Write the queue name directly //3. Parameter, ignore //4. Message body channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, null, message.getBytes()); } System.out.println("Message sent successfully"); } }
Consumer 1
package com.rabbitmq2; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * This is a worker thread * * @author Naive heat * @create 2022-02-08 16:36 * @desc **/ public class Consume01 { //receive messages public static void main(String[] args) throws IOException, TimeoutException { System.out.println("This is worker thread 1...."); Channel channel = RabbitmqUtils.getChannel(); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, true, deliverCallback, cancelCallback); } }
Consumer 2
package com.rabbitmq2; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * This is a worker thread * * @author Naive heat * @create 2022-02-08 16:36 * @desc **/ public class Consume02 { //receive messages public static void main(String[] args) throws IOException, TimeoutException { System.out.println("This is worker thread 2...."); Channel channel = RabbitmqUtils.getChannel(); //Callback method when the consumer fails to consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption //3. Callback when consumers successfully consume //4. Callback method for consumers to cancel consumption channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, true, deliverCallback, cancelCallback); } }
Start consumer 1 and then consumer 2 Then start the producer and you can see that the message is polled and sent to two consumers.
8, Code implementation - automatic / manual response
- concept
1) Automatic response: when the message is sent from the queue to the consumer, the default consumption is successful.
Advantages: high efficiency.
On the one hand, if the message is successfully processed, the consumer will lose the default message. On the other hand, if the message is successfully processed, the consumer will lose the data. On the other hand, if the consumer's system performance is crossed and cannot process messages in time, it will cause message backlog, memory depletion and crash.
2) Manual response: when a message is sent from the queue to the consumer, the consumer needs to manually confirm the message before the queue considers the consumption successful.
Advantages: data transmission is relatively safe and operable.
Disadvantages: low efficiency - Operability in manual response environment
1) According to the efficiency of different consumers' response messages, the queue can dynamically allocate messages to consumers
2) For some special queue information, you can choose to reject it and put it back in the queue - code implementation
producer
package com.rabbitmq3; import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { //Send a message public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Generating queues, //1. Name //2. Whether the queue message is persistent (No: stored in memory, yes: stored in disk. No by default) //3. Whether the queue is only for one consumer. No by default //4. Whether to delete automatically after the last consumer disconnects. //5. Other parameters channel.queueDeclare(RabbitmqUtils.RABBITMQ_QUEUE, true, false, false, null); //Keep sending messages for (int i = 0; i < 10; i++) { //Send a message String message = "this is Product"+i; //1. Switch. The simple version is not considered, and the empty string can be directly used (default / nameless switch) //2. Route key. Write the queue name directly //3. Parameter, (message persistence is effective only when the queue is enabled) //4. Message body channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); } System.out.println("Message sent successfully"); } }
Consumer 1 (accept, accept 1 every second, take 5 initially)
package com.rabbitmq3; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * This is a worker thread * * @author Naive heat * @create 2022-02-08 16:36 * @desc **/ public class Consume01 { //receive messages public static void main(String[] args) throws IOException, TimeoutException { System.out.println("This is worker thread 1...."); Channel channel = RabbitmqUtils.getChannel(); //0 is polling, the default //1 is unfair distribution, that is, which consumer is efficient and which side is distributed more //If it is greater than 1, it is a pre value, that is, the number of messages that consumers will consume. After prefetching, unfair distribution is carried out. channel.basicQos(5); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { //sleep try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); //Manual response //1. Message confirmation flag, 2 Batch response channel.basicAck(message.getEnvelope().getDeliveryTag(), false); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, false, deliverCallback, cancelCallback); } }
Consumer 2 (reject, reject one every 10s, take 2 initially)
package com.rabbitmq3; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * This is a worker thread * * @author Naive heat * @create 2022-02-08 16:36 * @desc **/ public class Consume02 { //receive messages public static void main(String[] args) throws IOException, TimeoutException { System.out.println("This is worker thread 2...."); Channel channel = RabbitmqUtils.getChannel(); //0 is polling, 1 is unfair distribution, and greater than 1 is the preset value. The default value is 0. After prefetching, unfair distribution is carried out. channel.basicQos(2); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { //sleep try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); //1. Message negative acknowledgement flag, 2 Is the message re queued channel.basicReject(message.getEnvelope().getDeliveryTag(), true); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(RabbitmqUtils.RABBITMQ_QUEUE, false, deliverCallback, cancelCallback); } }
You can check the rabbitmq interface
result:
9, Code implementation - three ways of message publishing confirmation
Message release confirmation means that after the producer sends the message to the Broker, if the Broker receives the message, it will give a reply to our producer. The producer receives the response to determine whether the message is sent to the Broker normally. There are three ways to confirm news release.
- Single confirmation is to confirm every time a message is sent. The advantage is that it is accurate, but the disadvantage is that it takes up a lot of resources and is slow. The test time of 1000 pieces of data is 1311ms
/** * Single confirmation */ public static void publishDg() throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Open release confirmation channel.confirmSelect(); //start time long begin = System.currentTimeMillis(); //send message for (int i = 0; i < 1000; i++) { channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, ("message" + i).getBytes()); //Release confirmation boolean flag = channel.waitForConfirms(); if (flag) { System.out.println("Sent successfully"); } } //End time long end = System.currentTimeMillis(); System.out.println("Time spent on individual confirmation=" + (end - begin)); }
- Batch confirmation refers to another confirmation for each batch of messages sent. The advantage is that it is faster than a single confirmation, but it cannot accurately locate the sending failure message. The test time of 1000 pieces of data is 170ms
public static void publishPl() throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Open release confirmation channel.confirmSelect(); //start time long begin = System.currentTimeMillis(); //Batch confirmation size int batchSize = 100; //Batch sending messages and confirmation for (int i = 0; i < 1000; i++) { channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, ("message" + i).getBytes()); if (i % batchSize == 0) { channel.waitForConfirms(); } } //End time long end = System.currentTimeMillis(); System.out.println("Time spent on individual confirmation=" + (end - begin)); }
- Asynchronous confirmation is to create a Map that supports high concurrency before sending, key stores message tag, values stores message, and call the listener to listen for message sending. If the callback function sends the message successfully, it will record the result according to the callback function after sending the message successfully. Send failed, call back the failed function, and display the message through Map in the failed function. Asynchronous acknowledgment has the best overall performance of all acknowledgments. The test time of 1000 pieces of data is 43ms
public static void publishYb() throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Open release confirmation channel.confirmSelect(); //start time long begin = System.currentTimeMillis(); //A thread safe and orderly hash table, suitable for high concurrency //1. Associate serial number with message //2. Easily delete entries in batch as long as the serial number is given //3. Support high concurrency ConcurrentSkipListMap<Long, String> concurrentSkipListMap = new ConcurrentSkipListMap<>(); //--------------------Listener-------------------------- //Message confirmation success callback function //1. Mark of message, 2 Batch operation ConfirmCallback ackCallback = (deliveryTag, multiple) -> { //Message acceptance processing if (multiple) { //batch ConcurrentNavigableMap<Long, String> confirmd = concurrentSkipListMap.headMap(deliveryTag); confirmd.clear(); } else { //Non batch concurrentSkipListMap.remove(deliveryTag); } System.out.println("Confirmed message:" + deliveryTag); }; //Message confirmation failure callback function //1. Mark of message, 2 Batch operation ConfirmCallback nackCallback = (deliveryTag, multiple) -> { //The message was not accepted for processing String message = concurrentSkipListMap.get(deliveryTag); System.out.println("Unacknowledged message:" + deliveryTag + ":" + message); }; //Message listener, listening for failure and success messages channel.addConfirmListener(ackCallback, nackCallback); //Batch sending messages and confirmation for (int i = 0; i < 1000; i++) { String message = ("message" + i); channel.basicPublish("", RabbitmqUtils.RABBITMQ_QUEUE, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); //Record messages sent concurrentSkipListMap.put(channel.getNextPublishSeqNo(), message); } //End time long end = System.currentTimeMillis(); System.out.println("Time spent on individual confirmation=" + (end - begin)); System.out.println(concurrentSkipListMap.size()); }
10, Code implementation - switch
As mentioned earlier, in fact, the producer sends messages directly to the switch, and then the switch assigns them to the queue according to relevant rules. According to the allocation rules, the common base switches are: direct switch, topic switch, topic switch, Headers switch, etc.
ps: because I use the same switch here. If the same switch is used and the configuration is modified, the original switch needs to be deleted, otherwise an error will be reported.
- Switch mode I fanout
This mode is the same as broadcasting, that is, all messages sent to the switch will be sent to all queues of the switch. The code is as follows:
producer
package com.rabbitmq5; import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "fanout"); for (int i = 0; i < 10; i++) { String message = "Messages sent" + i; //1. Switch. The simple version is not considered, and the empty string can be directly used (default / nameless switch) //2. Route key. Write the queue name directly //3. Parameter, (message persistence) //4. Message body channel.basicPublish(RabbitmqUtils.RABBITMQ_EXCHANGE, "", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); } } }
Consumer 1
package com.rabbitmq5; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume01 { //receive messages public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "fanout"); //Declare a temporary queue String queueName = channel.queueDeclare().getQueue(); //Binding switches and queues channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, ""); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(queueName, true, deliverCallback, cancelCallback); } }
Consumer 2:
package com.rabbitmq5; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume02 { //Send a message public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "fanout"); //Declare a temporary queue String queueName = channel.queueDeclare().getQueue(); //Binding switches and queues channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, ""); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(queueName, true, deliverCallback, cancelCallback); } }
result
2. Switch mode direct
Compared with fanout, this method increases certain restrictions, that is, messages can only be sent to the queue of the fixed rountKey of the switch. The code is as follows:
producer:
package com.rabbitmq6; import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch // channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "direct"); for (int i = 0; i < 10; i++) { String message = "Messages sent" + i; //1. Switch. The simple version is not considered, and the empty string can be directly used (default / nameless switch) //2. Route key. Write the queue name directly //3. Parameter, (message persistence) //4. Message body channel.basicPublish(RabbitmqUtils.RABBITMQ_EXCHANGE, "error", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); } } }
Consumer 1:
package com.rabbitmq6; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume01 { //receive messages public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "direct"); //Declare a temporary queue String queueName = channel.queueDeclare().getQueue(); //Binding switches and queues channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "info"); channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "warning"); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(queueName, true, deliverCallback, cancelCallback); System.out.println("queue info/warning wait for..."); } }
Consumer 2
package com.rabbitmq6; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume01 { //receive messages public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "direct"); //Declare a temporary queue String queueName = channel.queueDeclare().getQueue(); //Binding switches and queues channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "info"); channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "warning"); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(queueName, true, deliverCallback, cancelCallback); System.out.println("queue error wait for..."); } }
3. topic of switch mode
The direct mode mentioned above is actually the absolute matching of rountkey. topic is the fuzzy matching of roundkey.
*(asterisk) represents a word
#(pound sign) can replace zero or more words
The code is as follows:
producer
package com.rabbitmq7; import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "topic"); for (int i = 0; i < 10; i++) { String message = "Messages sent" + i; //1. Switch. The simple version is not considered, and the empty string can be directly used (default / nameless switch) //2. Route key. Write the queue name directly //3. Parameter, (message persistence) //4. Message body channel.basicPublish(RabbitmqUtils.RABBITMQ_EXCHANGE, "queue.queue.queue11", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); } } }
Consumer 1
package com.rabbitmq7; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume01 { //receive messages public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "topic"); //Declare a temporary queue String queueName = channel.queueDeclare().getQueue(); //Binding switches and queues channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "*.queue.*"); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(queueName, true, deliverCallback, cancelCallback); System.out.println("consumer|*.queue.*|Waiting...."); } }
Consumer 2
package com.rabbitmq7; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume02 { //receive messages public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch channel.exchangeDeclare(RabbitmqUtils.RABBITMQ_EXCHANGE, "topic"); //Declare a temporary queue String queueName = channel.queueDeclare().getQueue(); //Binding switches and queues channel.queueBind(queueName, RabbitmqUtils.RABBITMQ_EXCHANGE, "queue.*.*"); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption (if yes, it is successful by default, otherwise it is required) //3. Callback when consumers fail to consume successfully //4. Callback method for consumers to cancel consumption channel.basicConsume(queueName, true, deliverCallback, cancelCallback); System.out.println("consumer|queue.*.*|Waiting...."); } }
effect
11, Code implementation - priority queue
The consumption order of the queue is generally first in first out. However, in some order businesses, we need to give vip users the special permission to place an order and ship first. At this time, we need to use the priority queue.
Principle: in the original FIFO logic, the priority is given to the queue. The final order is as follows:
High priority – > low priority – > no note priority
ps: the priority range is 0-255
producer
package com.rabbitmq12; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { //Queue name public static final String ORDER_QUEUE = "ORDER_QUEUE"; //Send a message public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //parameter Map<String, Object> argument = new HashMap<>(); argument.put("x-max-priority", 10);//Set the priority range 0-10, and the official allowable value is 0-255. Setting too much will waste memory //Generating queues, //Do not create a switch, go to the default switch //1. Name //2. Whether the queue message is persistent (No: stored in memory, yes: stored in disk. No by default) //3. Whether the queue is only for one consumer. No by default //4. Whether to delete automatically after the last consumer disconnects. //5. Other parameters channel.queueDeclare(ORDER_QUEUE, true, false, false, argument); //Send a message String message = "this is QUEUE_P"; //Keep sending messages for (int i = 0; i < 10; i++) { //1. Switch. The simple version is not considered, and the empty string can be directly used (default / nameless switch) //2. Route key. Write the queue name directly //3. Parameter, ignore //4. Message body if (i == 5) { AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().priority(5).build(); channel.basicPublish("", ORDER_QUEUE, properties, (message + i).getBytes()); } else { channel.basicPublish("", ORDER_QUEUE, null, (message + i).getBytes()); } } System.out.println("Message sent successfully"); } }
consumer
package com.rabbitmq12; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 15:34 * @desc **/ public class Consume { //Queue name public static final String ORDER_QUEUE = "ORDER_QUEUE"; //Send a message public static void main(String[] args) throws IOException, TimeoutException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Callback method when the consumer fails to consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news //1. Queue name //2. Whether to respond automatically after successful consumption //3. Callback when consumers successfully consume //4. Callback method for consumers to cancel consumption channel.basicConsume(ORDER_QUEUE, true, deliverCallback, cancelCallback); } }
Test, start the producer, and then start the consumer
12, Code implementation - dead letter queue
Dead letter refers to information that cannot be consumed. These messages cannot be consumed because of some reasons such as network timeout, and become dead letter messages. Therefore, in order to ensure that these data are not lost, there is a dead letter queue to process dead letter messages.
Working drawing:
The code is as follows:
Generated by:
package com.rabbitmq8; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Product { //Normal switch public static String NORMAL_EXCHANGE = "NORMAL_EXCHANGE"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare a switch (duplicate declaration is not required) //channel.exchangeDeclare(NORMAL_EXCHANGE, "direct"); //Set the ttl time to 10s, and enter the dead letter queue when it expires AMQP.BasicProperties properties = new AMQP.BasicProperties().builder().expiration("10000").build(); //Send dead letter message for (int i = 0; i < 10; i++) { String message = "Messages sent" + i; //1. Switch. The simple version is not considered, and the empty string can be directly used (default / nameless switch) //2. Route key. Write the queue name directly //3. Parameter, (message persistence) //4. Message body channel.basicPublish(NORMAL_EXCHANGE, "normalQueue", properties, message.getBytes()); } } }
Consumer (normal queue)
package com.rabbitmq8; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume01 { //Normal switch public static String NORMAL_EXCHANGE = "NORMAL_EXCHANGE"; //Dead letter switch public static String DEAD_EXCHANGE = "DEAD_EXCHANGE"; //Normal queue public static String NORMAL_QUEUE = "NORMAL_QUEUE"; //Dead letter queue public static String DEAD_QUEUE = "DEAD_QUEUE"; //receive messages public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Declare normal and dead letter switches channel.exchangeDeclare(NORMAL_EXCHANGE, "direct"); channel.exchangeDeclare(DEAD_EXCHANGE, "direct"); //Declare dead letter queue channel.queueDeclare(DEAD_QUEUE, false, false, false, null); //Set parameters Map<String, Object> arguments = new HashMap<>(); //Set up dead letter switch arguments.put("x-dead-letter-exchange", DEAD_EXCHANGE); //Set dead letter RoutingKey arguments.put("x-dead-letter-routing-key", "deadQueue"); //Set normal queue length arguments.put("x-max-length", 6); //Set the expiration time, 10s (generally not set here, but configured on the producer side, so that the sub expiration time can be changed at will by the producer) //arguments.put("x-message-ttl", "10000"); //Declare normal queue channel.queueDeclare(NORMAL_QUEUE, false, false, false, arguments); //Binding common switches and queues channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, "normalQueue"); //Binding dead letter switch and queue channel.queueBind(DEAD_QUEUE, DEAD_EXCHANGE, "deadQueue"); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("refuse"); //Reject and do not put it back in the queue channel.basicReject(message.getEnvelope().getDeliveryTag(), false); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news channel.basicConsume(NORMAL_QUEUE, false, deliverCallback, cancelCallback); System.out.println("Normal queue preparation consumption message......"); } }
Consumer 2 (dead letter queue)
package com.rabbitmq8; import com.rabbitmq.client.CancelCallback; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DeliverCallback; import com.rabbitmqUtils.RabbitmqUtils; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; /** * @author Naive heat * @create 2022-02-08 14:52 * @desc **/ public class Consume02 { //Dead letter queue public static String DEAD_QUEUE = "DEAD_QUEUE"; //receive messages public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //Acquisition channel Channel channel = RabbitmqUtils.getChannel(); //Callback method when consumers consume successfully DeliverCallback deliverCallback = (consumerTag, message) -> { System.out.println("Callback when consumers successfully spend" + new String(message.getBody())); }; //Callback method for consumers to cancel consumption CancelCallback cancelCallback = consumerTag -> { System.out.println("Callback method for consumers to cancel consumption"); }; //Consumption news channel.basicConsume(DEAD_QUEUE, true, deliverCallback, cancelCallback); System.out.println("Dead letter queue ready to consume messages......"); } }
Test 1: first run the dead letter queue, and then run the producer. Since the produced messages are not consumed, the messages will automatically enter the dead letter queue after timeout
Test 2: run the dead letter queue and normal queue, and then run the producer. Since the production message is rejected, the message will automatically enter the dead letter queue when it times out
13, Code implementation - delay queue
Delay queue: the elements in the delay queue are processed after reaching the specified time. If the order function, if payment is not made within the specified time, the order will be cancelled.
schematic diagram:
Because our subsequent rabbitmq must run in the springboot framework, we need to integrate springboot here.
- Configure in yml configuration file
spring: rabbitmq: host: 192.168.248.10 port: 5672 username: admin password: admin #Switch confirmation interface publisher-confirms: true
- Add configuration class
package com.rabbitmq9; import org.springframework.amqp.core.*; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * @author Naive heat * @create 2022-02-10 10:09 * @desc **/ @Configuration public class Config { //General exchange public static final String X_EXCHANGE = "X"; //Dead letter switch public static final String Y_DEAD_LETTER_EXCHANGE = "Y"; //Common queue name public static final String QUEUE_A = "QA"; public static final String QUEUE_B = "QB"; public static final String QUEUE_C = "QC"; //Dead letter queue name public static final String DEAD_LETTER_QUEUE = "QD"; //Declare xExchange alias @Bean("xExchange") public DirectExchange xExchange() { return new DirectExchange(X_EXCHANGE); } //Declare yExchange alias @Bean("yExchange") public DirectExchange yExchange() { return new DirectExchange(Y_DEAD_LETTER_EXCHANGE); } //Declare the normal queue A ttl as 10s @Bean("queueA") public Queue queuA() { Map<String, Object> argument = new HashMap<>(); //Set up dead letter switch argument.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE); //Set dead letter RoutingKey argument.put("x-dead-letter-routing-key", "YD"); //Set ttl,10s argument.put("x-message-ttl", 10000); //Create queue return QueueBuilder.durable(QUEUE_A).withArguments(argument).build(); } //Declare the normal queue B ttl as 10s @Bean("queueB") public Queue queuB() { Map<String, Object> argument = new HashMap<>(); //Set up dead letter switch argument.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE); //Set dead letter RoutingKey argument.put("x-dead-letter-routing-key", "YD"); //Set ttl,40s argument.put("x-message-ttl", 40000); //Create queue return QueueBuilder.durable(QUEUE_B).withArguments(argument).build(); } //Declare that the common queue C ttl is determined by the producer @Bean("queueC") public Queue queuC() { Map<String, Object> argument = new HashMap<>(); //Set up dead letter switch argument.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE); //Set dead letter RoutingKey argument.put("x-dead-letter-routing-key", "YD"); //Create queue return QueueBuilder.durable(QUEUE_C).withArguments(argument).build(); } //Dead letter queue @Bean("queueD") public Queue queuD() { //Create queue return QueueBuilder.durable(DEAD_LETTER_QUEUE).build(); } //Bind queue A @Bean public Binding queueABindingX(@Qualifier("queueA") Queue queueA, @Qualifier("xExchange") DirectExchange xExchange) { return BindingBuilder.bind(queueA).to(xExchange).with("XA"); } //Bind queue B @Bean public Binding queueBBindingX(@Qualifier("queueB") Queue queueB, @Qualifier("xExchange") DirectExchange xExchange) { return BindingBuilder.bind(queueB).to(xExchange).with("XB"); } //Bind queue C @Bean public Binding queueCBindingX(@Qualifier("queueC") Queue queueC, @Qualifier("xExchange") DirectExchange xExchange) { return BindingBuilder.bind(queueC).to(xExchange).with("XC"); } //Bind queue D @Bean public Binding queueDBindingY(@Qualifier("queueD") Queue queueD, @Qualifier("yExchange") DirectExchange yExchange) { return BindingBuilder.bind(queueD).to(yExchange).with("YD"); } }
- Add production message class
package com.rabbitmq9; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author Naive heat * @create 2022-02-10 15:03 * @desc **/ @Slf4j @RestController @RequestMapping("/ttl") public class SendMessageController { @Autowired private RabbitTemplate rabbitTemplate; @GetMapping("/sendMsg/{message}") public void sendMessage(@PathVariable String message) { log.info("send message"); rabbitTemplate.convertAndSend("X", "XA", "Message from 10 s of ttl: " + message); rabbitTemplate.convertAndSend("X", "XB", "Message from 40 s of ttl: " + message); } @GetMapping("/sendExpireMsg/{message}/{ttlTime}") public void sendExpireMsg(@PathVariable String message, @PathVariable String ttlTime) { log.info("Send timing message"); rabbitTemplate.convertAndSend("X", "XC", "Message from timed message:" + message, msg -> { //When sending messages, the delay is extended msg.getMessageProperties().setExpiration(ttlTime); return msg; }); } }
- Add consumer class
package com.rabbitmq9; import com.rabbitmq.client.Channel; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; /** * Queue ttl consumers * * @author Naive heat * @create 2022-02-10 16:00 * @desc **/ @Slf4j @Component public class Consume { //receive messages @RabbitListener(queues = Config.DEAD_LETTER_QUEUE) public void receiveD(Message msg, Channel channel) { String message = new String(msg.getBody()); log.info("Delay queue message received:" + message); } }
Test 1: http://localhost:8090/ttl/sendMsg/hahaha
Test 2: http://localhost:8090/ttl/sendExpireMsg/5555/100
Test 3: send two addresses continuously. It can be seen that delayed messages need to be queued, so they can't be sent first. It's a disadvantage. You can use plug-ins to overcome this problem.
http://localhost:8090/ttl/sendExpireMsg/5555/10000
http://localhost:8090/ttl/sendExpireMsg/558885/1000
14, Code implementation - RabbitMQ plug-in implements delay queue
Installation tutorial
- Download: https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/tag/v3.8.0
- Put the plug-in in: / usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins
- Enter the directory: cd /usr/lib/rabbitmq/lib/rabbitmq_server-3.8.8/plugins
- Installation: rabbitmq plugins enable rabbitmq_ delayed_ message_ exchange
- Restart: server restart BBQ
working principle:
The code is as follows
Configuration class
package com.rabbitmq10; import org.springframework.amqp.core.*; import org.springframework.beans.factory.annotation.CustomAutowireConfigurer; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * @author Naive heat * @create 2022-02-10 10:09 * @desc **/ @Configuration public class DelayConfig { //queue public static final String DELAY_QUEUE = "DELAY_QUEUE"; //Switch public static final String DELAY_EXCHANGE = "DELAY_EXCHANGE"; //routingKey public static final String DELAY_ROUNTING_KEY = "DELAY_ROUNTING_KEY"; //Declaration switch @Bean public CustomExchange delayEchange() { Map<String, Object> arguments = new HashMap<>(); arguments.put("x-delayed-type", "direct"); //1. Switch name //2. Switch type //3. Is persistence needed //4. Whether to delete automatically //5. Other parameters return new CustomExchange(DELAY_EXCHANGE, "x-delayed-message", true, false, arguments); } //Declaration queue @Bean public Queue delayQueue() { //Create queue return new Queue(DELAY_QUEUE); } //Bind queue @Bean public Binding delayBindingQueue(@Qualifier("delayQueue") Queue delayQueue, @Qualifier("delayEchange") CustomExchange delayEchange) { return BindingBuilder.bind(delayQueue).to(delayEchange).with("DELAY_ROUNTING_KEY").noargs(); } }
consumer
package com.rabbitmq10; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; /** * Queue ttl consumers * * @author Naive heat * @create 2022-02-10 16:00 * @desc **/ @Slf4j @Component public class DelayConsume { //receive messages @RabbitListener(queues = DelayConfig.DELAY_QUEUE) public void receiveDelay(Message msg) { String message = new String(msg.getBody()); log.info("Received plug-in delay queue message:" + message); } }
Send message class
package com.rabbitmq10; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author Naive heat * @create 2022-02-10 15:03 * @desc **/ @Slf4j @RestController @RequestMapping("/delayed") public class SendDelayMessageController { @Autowired private RabbitTemplate rabbitTemplate; @GetMapping("/sendExpireMsg/{message}/{ttlTime}") public void sendExpireMsg(@PathVariable String message, @PathVariable Integer ttlTime) { log.info("Send timing message"); rabbitTemplate.convertAndSend(DelayConfig.DELAY_EXCHANGE, DelayConfig.DELAY_ROUNTING_KEY, "Message from timed message:" + message, msg -> { //When sending a message, the delay time is long msg.getMessageProperties().setDelay(ttlTime); return msg; }); } }
Test: execute the following two addresses in turn. It can be found that those with short delay time will execute first without queuing
http://localhost:8090/delayed/sendExpireMsg/10000/10000
http://localhost:8090/delayed/sendExpireMsg/500/500
15, Code implementation - release confirmation advanced
schematic diagram
configuration file
spring: rabbitmq: host: 192.168.248.10 port: 5672 username: admin password: admin #Switch confirmation interface publisher-confirms: true #New version: spring rabbitmq. publisher-confirm-type=correlated #Route fallback messages to producers publisher-returns: true
Send message class
package com.rabbitmq11; import com.rabbitmq10.DelayConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.connection.CorrelationData; import org.springframework.amqp.rabbit.core.CorrelationDataPostProcessor; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author Naive heat * @create 2022-02-10 15:03 * @desc **/ @Slf4j @RestController @RequestMapping("/confirm") public class SendConfirmMessageController { @Autowired private RabbitTemplate rabbitTemplate; @GetMapping("/sendMsgToBadExchange/{message}") public void sendMsgToBadExchange(@PathVariable String message) { //Class, which can be accepted when the queue receives messages CorrelationData correlationData = new CorrelationData("1"); //send message rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE + "bad", ConfirmConfig.CONFIRM_ROUNTING_KEY, "Message from timed message:" + message, correlationData); log.info("send message"); } @GetMapping("/sendMsgToBadRounting/{message}") public void sendMsgToBadRounting(@PathVariable String message) { //Class, which can be accepted when the queue receives messages CorrelationData correlationData = new CorrelationData("1"); //send message rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE, ConfirmConfig.CONFIRM_ROUNTING_KEY + "bad", "Message from timed message:" + message, correlationData); log.info("send message"); } @GetMapping("/sendMsg/{message}") public void sendMsg(@PathVariable String message) { //Class, which can be accepted when the queue receives messages CorrelationData correlationData = new CorrelationData("1"); //send message rabbitTemplate.convertAndSend(ConfirmConfig.CONFIRM_EXCHANGE, ConfirmConfig.CONFIRM_ROUNTING_KEY , "Message from timed message:" + message, correlationData); log.info("send message"); } }
Configuration class
package com.rabbitmq11; import org.springframework.amqp.core.*; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * Release confirmation * * @author Naive heat * @create 2022-02-10 10:09 * @desc **/ @Configuration public class ConfirmConfig { //queue public static final String CONFIRM_QUEUE = "CONFIRM_QUEUE"; //Switch public static final String CONFIRM_EXCHANGE = "CONFIRM_EXCHANGE"; //routingKey public static final String CONFIRM_ROUNTING_KEY = "CONFIRM_ROUNTING_KEY"; //Backup switch public static final String BACKUP_EXCHANGE = "BACKUP_EXCHANGE"; //Backup queue public static final String BACKUP_QUEUE = "BACKUP_QUEUE"; //Alarm queue public static final String WARNING_QUEUE = "WARNING_QUEUE"; //Declaration switch //Because the previous switch is used here, the original switch needs to be deleted to take effect @Bean public DirectExchange confirmEchange() { return (DirectExchange) ExchangeBuilder.directExchange(CONFIRM_EXCHANGE).durable(true).withArgument("alternate-exchange", BACKUP_EXCHANGE).build(); } //Declare backup switch @Bean public FanoutExchange backupEchange() { return new FanoutExchange(BACKUP_EXCHANGE); } //Declaration queue @Bean public Queue confirmQueue() { //Create queue return new Queue(CONFIRM_QUEUE); } //Declare backup queue @Bean public Queue backupQueue() { //Create queue return new Queue(BACKUP_QUEUE); } //Declare alarm queue @Bean public Queue warningQueue() { //Create queue return new Queue(WARNING_QUEUE); } //Bind queue @Bean public Binding confirmBindingQueue(@Qualifier("confirmQueue") Queue confirmQueue, @Qualifier("confirmEchange") DirectExchange confirmEchange) { return BindingBuilder.bind(confirmQueue).to(confirmEchange).with(CONFIRM_ROUNTING_KEY); } //Bind backup queue @Bean public Binding backupBindingQueue(@Qualifier("backupQueue") Queue backupQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) { return BindingBuilder.bind(backupQueue).to(backupEchange); } //Bind alarm queue @Bean public Binding warningBindingQueue(@Qualifier("warningQueue") Queue warningQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) { return BindingBuilder.bind(warningQueue).to(backupEchange); } }
Alarm configuration class
package com.rabbitmq11; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.connection.CorrelationData; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; /** * Callback interface * * @author Naive heat * @create 2022-02-11 15:25 * @desc **/ @Component @Slf4j public class CallBack implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback { @Autowired private RabbitTemplate rabbitTemplate; //injection @PostConstruct private void init() { //injection rabbitTemplate.setConfirmCallback(this); rabbitTemplate.setReturnCallback(this); } /** * Switch callback method (for whether the switch successfully receives messages) * 1.The messaging switch received a callback * 1.1 correlationData Save the id and related information of the callback message * 1.2 The switch receives the message ack=true * 1.3 call null * 2. The messaging switch failed a callback * 2.1 correlationData Save the id and related information of the callback message * 2.2 The switch receives the message ack=false */ @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { String id = correlationData != null ? correlationData.getId() : ""; if (ack) { System.out.println("The switch accepted successfully"); } else { System.out.println("Switch acceptance failed"); } } /** * When the message cannot reach the destination, it is returned to the producer * * @param message news * @param replayCode Failure code * @param replayText Failure reason * @param exchanges Switch * @param routingKey route */ @Override public void returnedMessage(Message message, int replayCode, String replayText, String exchanges, String routingKey) { System.out.println("Queue acceptance failed"); System.out.println("Message:" + message + ";Message code:" + replayCode + ";reason:" + replayText + ";Switch:" + exchanges + ";route:" + routingKey); } }
Normal consumer
package com.rabbitmq11; import org.springframework.amqp.core.*; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.Map; /** * Release confirmation * * @author Naive heat * @create 2022-02-10 10:09 * @desc **/ @Configuration public class ConfirmConfig { //queue public static final String CONFIRM_QUEUE = "CONFIRM_QUEUE"; //Switch public static final String CONFIRM_EXCHANGE = "CONFIRM_EXCHANGE"; //routingKey public static final String CONFIRM_ROUNTING_KEY = "CONFIRM_ROUNTING_KEY"; //Backup switch public static final String BACKUP_EXCHANGE = "BACKUP_EXCHANGE"; //Backup queue public static final String BACKUP_QUEUE = "BACKUP_QUEUE"; //Alarm queue public static final String WARNING_QUEUE = "WARNING_QUEUE"; //Declaration switch //Because the previous switch is used here, the original switch needs to be deleted to take effect @Bean public DirectExchange confirmEchange() { return (DirectExchange) ExchangeBuilder.directExchange(CONFIRM_EXCHANGE).durable(true).withArgument("alternate-exchange", BACKUP_EXCHANGE).build(); } //Declare backup switch @Bean public FanoutExchange backupEchange() { return new FanoutExchange(BACKUP_EXCHANGE); } //Declaration queue @Bean public Queue confirmQueue() { //Create queue return new Queue(CONFIRM_QUEUE); } //Declare backup queue @Bean public Queue backupQueue() { //Create queue return new Queue(BACKUP_QUEUE); } //Declare alarm queue @Bean public Queue warningQueue() { //Create queue return new Queue(WARNING_QUEUE); } //Bind queue @Bean public Binding confirmBindingQueue(@Qualifier("confirmQueue") Queue confirmQueue, @Qualifier("confirmEchange") DirectExchange confirmEchange) { return BindingBuilder.bind(confirmQueue).to(confirmEchange).with(CONFIRM_ROUNTING_KEY); } //Bind backup queue @Bean public Binding backupBindingQueue(@Qualifier("backupQueue") Queue backupQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) { return BindingBuilder.bind(backupQueue).to(backupEchange); } //Bind alarm queue @Bean public Binding warningBindingQueue(@Qualifier("warningQueue") Queue warningQueue, @Qualifier("backupEchange") FanoutExchange backupEchange) { return BindingBuilder.bind(warningQueue).to(backupEchange); } }
Consumer alert
package com.rabbitmq11; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; /** * Queue ttl consumers * * @author Naive heat * @create 2022-02-10 16:00 * @desc **/ @Slf4j @Component public class WarningConsume { //receive messages @RabbitListener(queues = ConfirmConfig.WARNING_QUEUE) public void receiveDelay(Message msg) { String message = new String(msg.getBody()); log.info("Alarm found non routable message:" + message); } }
Backup consumer
package com.rabbitmq11; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; /** * Queue ttl consumers * * @author Naive heat * @create 2022-02-10 16:00 * @desc **/ @Slf4j @Component public class BackupConsume { //receive messages @RabbitListener(queues = ConfirmConfig.BACKUP_QUEUE) public void receiveDelay(Message msg) { String message = new String(msg.getBody()); log.info("Backup switch message:" + message); } }
Test 1 - normal access: http://localhost:8090/confirm/sendMsg/100
Test 2 - access the wrong route: http://localhost:8090/confirm/sendMsgToBadExchange/100
Test 3 - access the wrong routingkey: http://localhost:8090/confirm/sendMsgToBadRounting/100
16, Introduction to RabbitMq's interface Features attribute
- d: d is the abbreviation of durable, which means that the messages in this queue support persistence.
- ad: ad is an abbreviation for autoDelete. The last consumer representing the current queue is automatically deleted when unsubscribing. Note: at this time, the queue will be deleted regardless of whether there are messages in the queue.
- excl: it is the abbreviation of exclusive. It means this is an exclusive queue. If a queue is declared as an exclusive queue, it is only visible to the connection that first declared it and is automatically deleted when the connection is disconnected. Three points need to be noted here: first, the exclusive queue is visible based on the connection. Different channels of the same connection can access the exclusive queue created by the same connection at the same time. Second, for the first time, if a connection has declared an exclusive queue, other connections are not allowed to establish an exclusive queue with the same name, which is different from ordinary queues. Third, even if the queue is persistent, once the connection is closed or the client exits, the exclusive queue will be deleted automatically. This queue is applicable to the application scenario where only one client sends read messages.
- Args: short for arguments. The arguments parameter is configured on behalf of the queue.
- TTL: it is the abbreviation of x-message-ttl. Set the life cycle of all messages in the queue (uniformly set the life cycle for all messages in the whole queue), or specify the remaining life time for a message separately when publishing a message, in milliseconds.
- Exp: Auto Expire is the abbreviation of x-expires configuration. When the queue is not accessed at the specified time (consume, basicGet, queueDeclare...), it will be deleted. Features=Exp. Note that this is to delete the queue, not the messages in the queue.
- Lim: indicates that the queue is configured with x-max-length. Limit the maximum length of messages in the queue. If it exceeds the specified length, the earliest messages will be deleted.
- Lim B: indicates that the queue is configured with x-max-length-bytes. Limit the maximum space occupied by the queue, which is generally limited by the size of memory and disk.
- DLX: indicates that the queue is configured with x-dead-letter-exchange. When the queue message length is greater than the maximum length or expired, push the messages deleted from the queue to the specified switch instead of discarding them.
- DLK: abbreviation of x-dead-letter-routing-key, which pushes the deleted message to the queue of the specified routing key of the specified switch.
- Pri: abbreviation of x-max-priority, priority queue. It indicates that the queue supports priority. First define the maximum priority value (the maximum value is generally not too large), specify the priority of the message when publishing the message, and the messages with higher priority (higher value) are consumed first.
- Ovfl: abbreviation for x-overflow. How to handle messages in the queue when they overflow. Either discard the message at the head of the queue, or reject all messages sent by subsequent producers. There are two configuration items: drop head, which represents the message discarding the queue head. The default behavior is; Reject publish sets the behavior of the queue after message overflow in the queue: "reject" (all messages).
- Ha all: mirror queue. All indicates that all nodes on the cluster are mirrored, and the HA params parameter is ignored.