The most complete RabbitMq in history

Posted by deived on Wed, 09 Feb 2022 04:26:45 +0100

RabbitMq data

1.win installation

Step 1: Download and install erlang
  • RabbitMQ server code is written in parallel language Erlang. The premise of installing RabbitMQ is to install Erlang. The download address is: http://www.erlang.org/downloads
  • Configure environment variables this computer – > right click "properties" – > advanced system settings – > environment variables – > "new" system environment variables; The value is the el installation path
  • Double click the system variable path to% Erlang_ Add home% \ bin to path
  • Finally, press the windows key + R key, enter cmd, and then enter erl. Seeing the version number indicates that erlang has been successfully installed
Step 2: Download and install RabbitMQ
  • And install RabbitMQ. Download address: http://www.rabbitmq.com/download.html
  • After RabbitMQ is installed, install RabbitMQ plugins. Open the command line cd and enter the sbin directory of RabbitMQ.
  • Enter the sbin directory and enter rabbitmq plugins enable rabbitmq_ Management for installation
  • If the execution fails, perform the following operations. First, enter rabbitmq service stop on the command line, then rabbitmq service remove, then rabbitmq service install, then rabbitmq service start, and finally re-enter rabbitmq plugins enable rabbitmq_ management.
  • Enter rabbitmqctl status to verify whether the installation is successful
  • Browser input http://localhost:15672 You can see the homepage of RabbitMQ. The default account and password are guest

2. Background management interface

overview

overview → Totals: blocking of all queues
Ready: total number of messages to be consumed
Unacked: the total number of messages to be answered
Total: total ready + unacknowledged
Publish: rate of product pub messages.
Publisher confirm: the rate at which broker confirms pub messages.
Delivery (manual ACK): the rate at which customer s manually acknowledge.
Deliver (auto ACK): the rate at which customer s automatically acknowledge.
Consumer ack: the rate at which customer s are acknowledging.
Redelivered: the rate at which messages of the 'redelivered' flag set are being delivered.
Get (manual ack): respond to basic The transmission rate of messages requiring acknowledgement for get.
Get (auto ack): respond to basic The rate at which messages that do not require acknowledgement are sent without getting.
Return: return basic Return the rate of messages sent to the producer.
Disk read: queue the rate at which messages are read from disk.
Disk write: queue the rate at which messages are written from disk.

Number of overall roles
Connections: the total number of tcp connections of the client.
Channels: total number of channels.
Exchange: total number of switches.
Queues: the total number of queues.
Consumers: the total number of consumers.

Overview→Nodes
Properties of broker
Name: broker name
File descriptors: file descriptors and restrictions opened by the broker.
Socket descriptors: the number and limit of network sockets managed by the broker. When the limit is exhausted, RabbitMQ will stop accepting new network connections.
Erlang processes: the number of processes started by erlang.
Memory: the memory occupied by the current broker.
Disk space: the hard disk occupied by the current broker.
Uptime: the duration of the current broker running continuously.
Info: cluster information.
Reset stats: restart a single node or the entire cluster.

Overview->Export definitions
The definition consists of users, virtual hosts, permissions, parameters, exchanges, queues and bindings. They do not include the contents of the queue or the cluster name. Exclusive queues will not be exported.
Overview->Import definitions
The imported definition will be merged with the current definition. If an error occurs during the import process, any changes you make are not rolled back.

Connections connection properties

Virtual host: the virtual host to which it belongs.
Name: name.
User name: the user name used.
State: current state, running: running; Idle: idle.
SSL/TLS: whether to use ssl for connection.
Protocol: the protocol used.
Channels: total number of channel s created.
From client: packets sent per second.
To client: packets received per second.

Channels currently connects all created channels

Channel properties
channel: name.
Node: node name.
Virtual host: the virtual host to which it belongs.
User name: the user name used.
Mode: channel guarantee mode. It can be one of the following or not: C: confirm. T: Transactional.
State: current state, running: running; Idle: idle.
Unconfirmed: the total number of messages to be confirmed.
Prefetch: set the number of prefetches.
Unacker: the total number of messages to be acked.
publish: rate of producer pub messages.
Confirm: the rate of product confirm messages.
deliver/get: the rate at which consumer s get messages.
ACK: rate of consumer ack messages.

Exchanges exchange properties

Virtual host: the virtual host to which it belongs.
Name: name.
Type: exchange type,
Features: features. It can be one of the following, or not: D: persistence. T: Internal, the presence change function indicates that this exchange cannot be used by client s to push messages, but only for binding between exchange and exchange. Otherwise, messages can be pushed or bound.
Message rate in: the rate at which messages enter.
Message rate out: the rate at which messages go out.

Properties of Queues

Virtual host: the virtual host to which it belongs.
Name: name.
Features: features. It can be one of the following, or not: D: persistence.
State: current state, running: running; Idle: idle.
Ready: the total number of messages to be consumed.
Unacked: the total number of messages to be answered.
Total: total ready + unacknowledged.
incoming: the rate at which messages enter.
deliver/get: the rate at which messages are retrieved.
ack: rate of message replies.

3. Basic concepts

Introduction to rabbitMq
   ```

1.MQ (Message Queue) is a communication method between application systems. It communicates by reading and writing messages in and out of the queue (RPC communicates with each other through direct calls). The message can be returned immediately after sending, and the message system ensures the reliable transmission of the message. The message publisher only publishes the message to MQ, regardless of who gets it. The message user only gets the message from MQ, regardless of who publishes it. In this way, publishers and users do not need to know each other's existence.
2.AMQP, namely Advanced Message Queuing Protocol, is an open standard of application layer protocol and is designed for message oriented middleware. Message middleware is mainly used for decoupling between components. The sender of the message does not need to know the existence of the message consumer, and vice versa.
The main features of AMQP are message oriented, queue oriented, routing (including point-to-point and publish / subscribe), reliability and security.
3.RabbitMQ is an open source AMQP implementation. The server side is written in Erlang language and supports a variety of clients, such as Python, Ruby NET, Java, JMS, C, PHP, ActionScript, XMPP, STOMP, etc. AJAX is supported. It is used to store and forward messages in distributed systems, and performs well in ease of use, scalability, high availability and so on. Common scenarios include: business decoupling, final consistency, broadcasting, peak shifting flow control, etc
```

Basic concepts of RabbitMQ
Message: Message, including message header (i.e. attached configuration information) and message body (i.e. the entity content of the message)
Publisher: Producer, the body that publishes messages to the switch
Exchange: The switch is used to receive the messages sent by the producer and route these messages to the queue in the server
Binding: Binding for Exchange and Queue Building a relationship is what we know as a paired matchmaker
Queue: Message queue, which is used to save messages until they are sent to consumers. It is the container of messages and the destination of messages. A message can be put into one or more queues. The message is always in the queue, waiting for the consumer to connect to the queue and take it away.
Connection: connect
Channel: Access, MQ Dealing with the outside world is through Channel To publish a message, subscribe to a queue, or receive a message, these actions are through Channel Completion; Simply put, the message passes Channel Cram into or out of a queue
Consumer: Consumer, get the body of the message from the message queue
Virtual Host: A virtual host that represents a batch of switches, message queues, and related objects. Virtual hosts are independent server domains that share the same authentication and encryption environment. each vhost Is essentially a mini Edition RabbitMQ The server has its own queue, switch, binding and permission mechanism. vhost yes AMQP The basis of the concept must be specified at the time of connection, RabbitMQ default vhost yes /
Broker: Message queuing server entity
Routing Key:  Routing keywords, exchange Message delivery based on this keyword
Message routing in AMQP
AMQP Routing process and of messages in Java Familiar to developers JMS There are some differences, AMQP Added in Exchange and Binding Your role. The producer publishes the news to Exchange On, the message finally reaches the queue and is received by the consumer, and Binding Decide which queue the switch's messages should be sent to.
Exchange type

When distributing messages, Exchange has different distribution strategies according to different types. At present, there are four types: direct, fanout, topic and headers. The headers match the headers of AMQP messages instead of the routing keys. In addition, the headers switch and the direct switch are exactly the same, but their performance is much worse. At present, they are almost useless. Therefore, we can directly look at the other three types:

Default Exchange
This is special Direct Exchange,yes rabbitmq An internal default switch. Of the switch name Is an empty string, all queue All default binding Connect to the switch. All binding To the on the switch queue,routing-key All and queue of name equally
direct exact match (unicast) switch
Routing keys in messages( routing key)If and Binding Medium binding key Consistent, the switch sends the message to the corresponding queue. The routing key exactly matches the queue name. If a queue is bound to the switch, the routing key is required to be“ test",Forward only routing key Mark as“ test"The message will not be forwarded“ test.test",It will not be forwarded“ test.test1"wait. It is an exact match, unicast mode.
fanout sector switch
Each sent to fanout The messages of the type switch will be distributed to all bound queues. fanout The switch does not process routing keys, but simply binds the queue to the switch. Each message sent to the switch will be forwarded to all queues bound to the switch. Much like subnet broadcasting, hosts in each subnet get a copy of the message. fanout Type forwarding messages is the fastest.
topic wildcard switch
wildcardexplainExamples
*Match one or more contentbigdata. * Can be matched to bigdata Spark or bigdata hadoop. Hive et al
#A content matchbigdata.# Can only match bigdata Spark or bigdata hadoop
topic The switch allocates the routing key attribute of the message through pattern matching to match the routing key with a pattern. At this time, the queue needs to be bound to a pattern. It cuts the strings of routing and binding keys into words separated by dots. It also recognizes two wildcards: symbols“#"And symbols“*". #Match 0 or more words, * match no more than one word
Switches of type Headers header attribute parameter
headers It is also matched according to rules, Compared to direct and topic Fixed use routing_key , headers Is the type of a custom matching rule.When the queue is bound to the switch, A set of key value pair rules will be set, The message also includes a set of key value pairs( headers attribute), When one of these key value pairs, Or all match, The message is delivered to the corresponding queue
ACK confirmation mechanism
each Consumer It may take some time to process the received data. If in this process, Consumer If there is an error, the exception exits, and the data has not been processed, then unfortunately, this data is lost. Because we use no-ack The way to confirm, that is, every time Consumer After receiving the data, regardless of whether the processing is completed or not, RabbitMQ Server I'll take this right away Message Mark as complete, then from queue Deleted in.
If one Consumer The exception exits, and the data it processes can be used by another user Consumer Processing, so that the data will not be lost in this case (note that in this case).
To ensure that data is not lost, RabbitMQ Support message confirmation mechanism, i.e acknowledgments. 
To ensure that the data can be processed correctly, not just by Consumer Roger that, then we can't use it no-ack. It should be sent after processing the data ack. 
Sent after processing data ack,Just tell RabbitMQ The data has been received and processed, RabbitMQ You can safely delete it.
If Consumer Quit but didn't send ack,that RabbitMQ Will put this Message Send to next Consumer. 
This ensures that Consumer In case of abnormal exit, the data will not be lost.
Dead letter queue
Like other queues, the dead letter queue is an ordinary queue. stay RabbitMQ There is no specific "dead letter queue" type in, but it is implemented through configuration.
When creating a service switch and queue, you can configure parameters to indicate that the other queue is the dead letter queue of the current queue RabbitMQ In, the dead letter queue (strictly speaking, it should be the dead letter switch) is called DLX Exchange. When the message "dies", it will be automatically routed to DLX Exchange of queue in.
What kind of messages will enter the dead letter queue?
1.Informative TTL be overdue(Time To Live)-The survival time has expired
2.Consumer to broker answer Nack,And the message cannot be returned to the queue.(basic.reject or basic.nack) And with requeue=false Do not rejoin parameters or reach retry Maximum number of rejoinments
3.Queue The queue length has reached the maximum. The queue is full, queue of"x-max-length"Parameters)
Application scenario:
If the important business queue fails, it needs to re process the message with another business logic; If the normal business logic deliberately fails the illegal value in the message, there is no need for dead letter
Detailed explanation of configuration parameters
#Properties file: org springframework. boot. autoconfigure. amqp. RabbitProperties
#Config:
# base
spring.rabbitmq.host: service Host
spring.rabbitmq.port: Service port
spring.rabbitmq.username: Login user name
spring.rabbitmq.password: Login password
spring.rabbitmq.virtual-host: connection to rabbitMQ of vhost
spring.rabbitmq.addresses: appoint client Connected to server Addresses of, multiple separated by commas(Preferential access addresses,Then take it host)
spring.rabbitmq.requested-heartbeat: Specifies the heartbeat timeout, in seconds, 0 is unspecified; Default 60 s
spring.rabbitmq.publisher-confirms: Enable publish confirmation
spring.rabbitmq.publisher-returns: Enable publish return
spring.rabbitmq.connection-timeout: Connection timeout, in milliseconds. 0 means infinity. No timeout
spring.rabbitmq.parsed-addresses:
# ssl
spring.rabbitmq.ssl.enabled: Support ssl
spring.rabbitmq.ssl.key-store: Designated holding SSL certificate of key store Path of
spring.rabbitmq.ssl.key-store-password: Specify access key store Password for
spring.rabbitmq.ssl.trust-store: Designated holding SSL certificates of Trust store
spring.rabbitmq.ssl.trust-store-password: Specify access trust store Password for
spring.rabbitmq.ssl.algorithm: ssl The algorithm used, for example, TLSv1.1
# cache
spring.rabbitmq.cache.channel.size: Held in cache channel quantity
spring.rabbitmq.cache.channel.checkout-timeout: When the number of caches is set, one is obtained from the cache channel Timeout of, in milliseconds; If 0, a new is always created channel
spring.rabbitmq.cache.connection.size: The number of cached connections is only CONNECTION Effective when in mode
spring.rabbitmq.cache.connection.mode: Connection factory cache mode: CHANNEL and CONNECTION
# listener
spring.rabbitmq.listener.simple.auto-startup: Whether to automatically start the container on startup
spring.rabbitmq.listener.simple.acknowledge-mode: Indicates the message confirmation method. There are three configuration methods, namely none,manual and auto;default auto
spring.rabbitmq.listener.simple.concurrency: Minimum number of consumers
spring.rabbitmq.listener.simple.max-concurrency: Largest number of consumers
spring.rabbitmq.listener.simple.prefetch: Specify how many messages a request can process. If there are transactions, it must be greater than or equal to transaction quantity.
spring.rabbitmq.listener.simple.transaction-size: Specify the number of messages for a transaction, preferably less than or equal to prefetch Number of.
spring.rabbitmq.listener.simple.default-requeue-rejected: Decide whether the rejected message will rejoin the team; Default is true(And parameters acknowledge-mode (related)
spring.rabbitmq.listener.simple.idle-event-interval: How long does it take to publish an idle container, in milliseconds
spring.rabbitmq.listener.simple.retry.enabled: Retry listening available
spring.rabbitmq.listener.simple.retry.max-attempts: max retries 
spring.rabbitmq.listener.simple.retry.initial-interval:The interval between the first and second attempts to publish or deliver a message
spring.rabbitmq.listener.simple.retry.multiplier: Multiplier applied to the last retry interval
spring.rabbitmq.listener.simple.retry.max-interval: Maximum retry interval
spring.rabbitmq.listener.simple.retry.stateless: Retry is stateful or Stateless
# template
spring.rabbitmq.template.mandatory: Enable mandatory information; default false
spring.rabbitmq.template.receive-timeout: receive() Timeout for operation
spring.rabbitmq.template.reply-timeout: sendAndReceive() Timeout for operation
spring.rabbitmq.template.retry.enabled: Is send retry available
spring.rabbitmq.template.retry.max-attempts: max retries 
spring.rabbitmq.template.retry.initial-interval: The interval between the first and second attempts to publish or deliver a message
spring.rabbitmq.template.retry.multiplier: Multiplier applied to the last retry interval
spring.rabbitmq.template.retry.max-interval: Maximum retry interval

4.springboot integration RabbitMQ

  • Configuring pom package is mainly to add spring boot starter AMQP support
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
  • Configure the installation address, port and account information of rabbitmq
spring:
  application:
    name: upms-service
  main:
    allow-bean-definition-overriding: true #Is it allowed to override the registration when the same name is encountered
  rabbitmq:
    username: guest
    password: guest
    port: 5672
    host: localhost
direct Exchange mode
  • springBoot integration mq defaults to direct mode
//Configure test queue
@Configuration
public class RabbitConfig {
    @Bean
    public Queue helloQueue() {
        return new Queue("test");
    }
}

// Consumer monitoring test queue
@Component
public class TestReceiver {
@RabbitListener(queues = "test")
public void receiveMessageTest(String test) throws InterruptedException {
    System.out.println("======process information======");
    Thread.sleep(1000L);
    System.out.println("test Receiver  : " + test+"===="+System.currentTimeMillis());
    System.out.println("======End of processing information======");
 }
}
//Producer sends message
@RestController
public class MQController {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @GetMapping("/send")
    public void send() {
        String context = "hello " +                               			System.currentTimeMillis()+": "+Thread.currentThread().getName();	
        System.out.println("Sender : " + context);
        rabbitTemplate.convertAndSend("test", context);
    }
}
fanout Exchange mode
/**
 * @Description * Description:
 *  1. fanout Routing, also known as broadcast routing, broadcasts the received message to the message pair column. When using the fanout switch, it will broadcast messages to all queues bound to the switch, which is conducive to different responses to a single message.
 *  2. fanout The route does not need to specify a route key. Even if it is specified, it will be ignored. As long as the queue is bound to the switch, the messages sent to the switch will be distributed to the message receiver.
 *
 */
//Configuring fanout queues and switches
@Slf4j
@Configuration
public class TestExchangeConfiguration {
    /**
     * Switch name
     */
    public static final String FANOUT_EXCHANGE_NAME = "fanout.exchange.name";

    /**
     * Test queue name 1
     */
    public static final String TEST_QUEUE1_NAME = "test.queue1.name";

    /**
     * Test queue name 1
     */
    public static final String TEST_QUEUE2_NAME = "test.queue2.name";
    /**
     * Create a switch in broadcast form
     *
     * @return Switch instance
     */
    @Bean
    public FanoutExchange fanoutExchange() {
        log.info("[[[Switch instance created successfully]]");
        return new FanoutExchange(FANOUT_EXCHANGE_NAME);
    }
    /**
     * Test queue I
     *
     * @return Queue instance
     */
    @Bean
    public Queue queue1() {
        log.info("[[[Test queue instance creation succeeded]]");
        return new Queue(TEST_QUEUE1_NAME);
    }

    /**
     * Test queue II
     *
     * @return Queue instance
     */
    @Bean
    public Queue queue2() {
        log.info("[[[Test queue 2 instance created successfully]]");
        return new Queue(TEST_QUEUE2_NAME);
    }
    /**
     * Bind queue to switch
     *
     * @return Binding object
     */
    @Bean
    public Binding bingQueue1ToExchange() {
        log.info("[[[Bind queue to switch successfully]]");
        return BindingBuilder.bind(queue1()).to(fanoutExchange());
    }
    /**
     * Bind queue 2 to switch
     *
     * @return Binding object
     */
    @Bean
    public Binding bingQueue2ToExchange() {
        log.info("[[[Bind queue 2 to switch successfully]]");
        return BindingBuilder.bind(queue2()).to(fanoutExchange());
    }
}

// Consumer listening queue
@Component
@Slf4j
public class TestReceiver {
    @RabbitHandler
    @RabbitListener(queues = "test.queue1.name")
    public void receiveMessage(String message) {
        log.info("The message receiver receives the message from [queue 1], and the message content: {}", message);
    }
    @RabbitHandler
    @RabbitListener(queues = "test.queue2.name")
    public void receiveMessage1(String message) {
        log.info("The message receiver receives the message from [queue 2], and the message content: {}", message);
    }
}
//Send message to switch and broadcast to all queues
@RestController
@Slf4j
public class MQController {
    @Autowired
    RabbitTemplate rabbitTemplate;
    /**
     * send message
     *
     * @param message Message content
     * Note: routingKey can be specified or not. Here we give an empty string ""
     */
    @GetMapping("/send")
    public void sendMessage(@RequestParam String message) {
        log.info("[[message sender] sends a message to fanout Switch, message content is: {}", message);
       rabbitTemplate.convertAndSend("fanout.exchange.name", "", message);
    }

}

Exchange topic mode
//Configuring fanout queues and switches
@Slf4j
@Configuration
public class TestTopicConfiguration {
    /**
     * Switch name
     */
    public static final String FANOUT_EXCHANGE_NAME = "Topic.exchange.name";
    /**
     * Test queue name 1
     */
    public static final String TEST_QUEUE1_NAME = "Topic.queue1.name";
    /**
     * Test queue name 1
     */
    public static final String TEST_QUEUE2_NAME = "Topic.queue2.name";

    /**
     * Create a switch in broadcast form
     * @return Switch instance
     */
    @Bean
    public TopicExchange topicExchange() {
        log.info("[[[Topic Switch instance created successfully]]");
        return new TopicExchange(FANOUT_EXCHANGE_NAME);
    }
    /**
     * Test queue I     
     * @return Queue instance
     */
    @Bean
    public Queue queue1() {
        log.info("[[[Topic Test queue instance creation succeeded]]");
        return new Queue(TEST_QUEUE1_NAME);
    
    /**
     * Test queue II
     *
     * @return Queue instance
     */
    @Bean
    public Queue queue2() {
        log.info("[[[Topic Test queue 2 instance created successfully]]");
        return new Queue(TEST_QUEUE2_NAME);
    }
    /**
     * Bind queue to switch
     * Configure the routingKey of the message queue
     * Topic.* Match the first one The following words represent a word
     * For example, topic ASD will be accepted by the message queue topic asd. DSF will not be accepted by the message queue
     * @return Binding object
     */
    @Bean
    public Binding bingQueue1ToExchange() {
        log.info("[[[Bind queue to switch successfully]]");
        return BindingBuilder.bind(queue1()).to(topicExchange()).with("Topic.*");
    }
    /**
     * Bind queue 2 to switch
     * Configure the routingKey of the message queue
     * Topic.# Match all The following words represent any word
     * For example, topic ASD will be accepted by the message queue topic asd. The DSF will also be accepted by the message queue
     * @return Binding object
     */
    @Bean
    public Binding bingQueue2ToExchange() {
        log.info("[[[Bind queue 2 to switch successfully]]");
        return BindingBuilder.bind(queue2()).to(topicExchange()).with("Topic.#");
    }
}
    /**
 * @describe
 */
// Consumer listening queue
@Component
@Slf4j
public class TestReceiver {
    @RabbitHandler
    @RabbitListener(queues = "Topic.queue1.name")
    public void receiveMessage2(String message) {
        log.info("Topic The message receiver receives the message from [queue 1], and the message content: {}", message);
    }
    @RabbitHandler
    @RabbitListener(queues = "Topic.queue2.name")
    public void receiveMessage3(String message) {
        log.info("Topic The message receiver receives the message from [queue 2], and the message content: {}", message);
    }
}
/*
 * @describe
 */
//Send message to switch
@RestController
@Slf4j
public class MQController {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @GetMapping("send")
    public void sendTwo(String message){
        log.info("[Topic [message sender] sends a message to Topic Switch, message content is: {}", message);
        rabbitTemplate.convertAndSend("Topic.exchange.name","Topic.name",message);
        rabbitTemplate.convertAndSend("Topic.exchange.name","Topic.a",message);

    }

}
Headers Exchange mode
/**
 * @Description * Description:
 */
@Slf4j
@Configuration
public class TestHeadersConfiguration {
    /**
     * Switch name
     */
    public static final String HEADERS_EXCHANGE_NAME = "Headers.exchange.name";

    /**
     * Test queue name 1
     */
    public static final String TEST_QUEUE1_NAME = "Headers.queue1.name";

    /**
     * Test queue name 1
     */
    public static final String TEST_QUEUE2_NAME = "Headers.queue2.name";
    /**
     * Create a switch in broadcast form
     *
     * @return Switch instance
     */
    @Bean
    public HeadersExchange headersExchange() {
        log.info("[Headers Switch instance creation succeeded]");
        return new HeadersExchange(HEADERS_EXCHANGE_NAME);
    }
    /**
     * Test queue I
     * @return Queue instance
     */
    @Bean
    public Queue queue5() {
        log.info("[Headers [test queue instance created successfully]");
        return new Queue(TEST_QUEUE1_NAME);
    }
    /**
     * Test queue II
     * @return Queue instance
     */
    @Bean
    public Queue queue6() {
        log.info("[Headers Test queue 2 instance created successfully]");
        return new Queue(TEST_QUEUE2_NAME);
    }

    @Bean
    public Binding bingQueue5ToExchange() {
        log.info("[Headers Bind queue to switch successfully]");
        HashMap<String, Object> header = new HashMap<>();
        header.put("queue", "queue1");
        header.put("bindType", "whereAll");
        return BindingBuilder.bind(queue5()).to(headersExchange()).whereAll(header).match();
    }

    @Bean
    public Binding bingQueue6ToExchange() {
        log.info("[Headers Bind queue 2 to switch successfully]");
        HashMap<String, Object> header = new HashMap<>();
        header.put("queue", "queue2");
        header.put("bindType", "whereAny");
        return BindingBuilder.bind(queue6()).to(headersExchange()).whereAny(header).match();
    }
    /**
 * @describe
 */
@Component
@Slf4j
public class TestReceiver {
    @RabbitListener(queues = "Headers.queue1.name")
    public void receiveMessage4(Message message) {
        try {
            log.info("Headers The message receiver receives the message from [queue 1], and the message content: {}",new String(message.getBody(),message.getMessageProperties().getContentType()));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
    @RabbitListener(queues = "Headers.queue2.name")
    public void receiveMessage5(Message message) {
        try {
            log.info("Headers The message receiver receives the message from [queue 2], and the message content: {}",new String(message.getBody(),message.getMessageProperties().getContentType()));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}
    /**
 * @describe
 */
@RestController
@Slf4j
public class MQController {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @GetMapping("send3")
    public void send3(String message){
        log.info("[Headers [message sender] sends a message to Headers Switch, message content is: {}", message);
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setDeliveryMode(MessageDeliveryMode.NON_PERSISTENT);
        messageProperties.setContentType("UTF-8");
        messageProperties.setHeader("queue", "queue2");
        messageProperties.setHeader("bindType", "whereAny");
        Message message1 = new Message(message.getBytes(), messageProperties);
        rabbitTemplate.convertAndSend("Headers.exchange.name", null, message1);
    }
}
serialize
    /**
    * If the Serializable interface of java is used, the package names of producers and consumers must be the same*
    *
     */
     @Bean
    public  MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
Message persistence

In the process of message transmission, there may be various abnormal failures or even downtime. In order to ensure the reliability of message transmission, persistence is required, that is, the data is written on the disk. Message queue persistence consists of three parts

1.Message persistence

Message persistence when sending. (message contains body, which is the specific content of the message we need to send. It is generally sent in json string and parsed by the consumer; MessageProperties are some additional properties of message, which can be extended)

    public void send(String message){
        MessageProperties messageProperties = new MessageProperties();
        //Message persistence messagedeliverymode PERSISTENT
        messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        messageProperties.setContentType("UTF-8");
        Message message1 = new Message(message.getBytes(), messageProperties);
        //send out
        rabbitTemplate.convertAndSend("exchange.name", null, message1);
    }

2. Queue persistence
@Bean 
public Queue helloQueue() { 
	return new Queue("hello",true); 
} 
    /**
     *name:Queue name
     *durable:Whether to persist. The default is true
     *exclusive: Exclusive queue, default false. If a queue is declared as an exclusive queue, the queue is only visible to the connection that declares it for the first time, and will be 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 channel s 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
     *  autoDelete: Automatically delete. The default is false. If the queue does not have any subscribed consumers, the queue will be automatically deleted. This kind of queue is suitable for temporary queues.
     */
 public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete) {
        this(name, durable, exclusive, autoDelete, (Map)null);
    }
3. Switch persistence
@Bean 
public DirectExchange helloExchange(){ 
	return new DirectExchange("helloexchange",true,false); 
} 
/** name Switch name 
  * durable Persist default true
  * autoDelete When the switch has no binding queue, it will automatically delete the default false of the switch
  */
 public DirectExchange(String name, boolean durable, boolean autoDelete) {
        super(name, durable, autoDelete);
    }
ack mode
answer mode
NONE
 It can be called automatic callback. Even if there is no response or exception, it will notify the queue of successful consumption and lose data.
AUTO
 Automatically detect exceptions or timeout events, and return if they occur noack,The message automatically returns to the end of the queue. However, this method may cause problems in the message body itself, and other queues returning to the end of the queue cannot be consumed, resulting in queue congestion.
MANUAL
 Manual callback. In the program, we can capture the message exception memory. If there is a message body format error, we can reply manually ack,Then call the sending interface again to push the message to the end of the queue.
yml configuration
spring:
  rabbitmq:
    username: guest
    password: guest
    port: 5672
    host: localhost
    publisher-confirms: true #  Send the message to the switch confirmation mechanism. Confirm the callback
    publisher-returns: true  #  The message is sent to the switch to confirm whether the feedback is returned
    listener:       # Enable ACK
      direct:    #NONE (default): automatic; AUTO: confirm according to the situation; MANUAL: MANUAL confirmation
        acknowledge-mode: manual
      simple:
        acknowledge-mode: manual
Callback method parameters
 public class MsgSendConfirmCallBack implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnCallback {
     /**
     * This method is called when a message is sent to the exchange
     * 1.If the message is not sent to exchange, ack=false
     * 2.ack=true if the message arrives at exchange
     * @param correlationData Callback id
     * @param ack
     * @param cause
     */ 
     @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        System.out.println("MsgSendConfirmCallBack, Callback id:" + correlationData);
        if (ack) {
            System.out.println("Message sent to exchange success");    
        } else {
            System.err.println("Message sent to exchange fail");
        }
    }
 /**
     * This method is called when the message fails from the switch to the queue. (if successful, it will not be called)
     * It should be noted that after this method is called, the confirm method in MsgSendConfirmCallBack will also be called, and ack = true
     * @param message
     * @param replyCode
     * @param replyText
     * @param exchange
     * @param routingKey
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        System.out.println("Message from switch to queue failed]  message: "+message);
    }
 }

/**
 * @Description send message
 */
@Service
@Slf4j
public class sendMq{
    @Autowired
    private RabbitTemplate rabbitTemplate;
    public void send() {
        String context = Thread.currentThread().getName()+"Hello, now " + new Date() +"";
        // ID ID, so [message unique ID] in RabbitConfirmCallBack is not empty
        CorrelationData date = new CorrelationData(UUID.randomUUID().toString());
       // When the producer sends a message to exchange and there is no bound queue, the message will be returned
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            log.info("Message body: {}", message);
            log.info("Reply code: {}", replyCode);
            log.info("Reply content: {}", replyText);
            log.info("exchanger: {}", exchange);
            log.info("Routing key: {}", routingKey);
            log.info(Thread.currentThread().getName()+"Sent message returned" + exchange + routingKey);
        });
           // Producer sends message confirm detection
        this.rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            log.info("Message unique identifier: {}", correlationData);
            log.info("Confirm status: {}", ack);
            if (!ack) {
                log.info("Cause: {}", cause);
            } else {
                System.out.println(Thread.currentThread().getName());
                log.info("Message sent successfully ");
            }
        });
        this.rabbitTemplate.convertAndSend("Direct.exchange.name", "Direct.queue1.name",context,date);
    }
    }
 
Message confirmation
          //Message Receiver 
    @RabbitListener(queues = "Direct.queue1.name")
    @RabbitHandler
    public void receiveMessageTest1(String msg, CorrelationData correlationData, Channel channel, Message message) throws Exception {
        log.info("Message recipient received from[ Direct.exchange.name]Message content: [{}],[{}],[{}],[{}]", message,correlationData,channel,message);
        //The identifier of the message. false only confirms the receipt of the current message. true confirms the messages obtained by all consumer s
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); 
        //ack returns false, returns to the queue and sends it back to the message receiver
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        //Discard this message
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
        //Reject message deliveryTag: index request of the message: whether to re-enter the queue for the rejected. true re-enter the queue
        channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
          }
Spring retry
rabbitMQ introduction
rabbitMQ There's a way channel.basicNack()The message can be returned to the queue, so that retry can be realized. However, this does not specify the number of retries. If the current message is retried all the time, the subsequent messages will accumulate, resulting in the inability to consume the subsequent messages. This is a fatal disadvantage. Therefore, it is necessary to set the number of retries to solve this problem. Several solutions are provided below.
1.use redis perhaps mongo Wait for a third party to store the current number of retries.
2.stay header Add the number of retries in and use channel.basicPublish() Method adds 1 to the number of retries after sending the message again.
3.use spring-rabbit Built in retry function
Manual confirmation mode description
1.The internal monitoring method must be used channel Confirm the message, including consumption success or consumption failure
2.If you do not manually confirm or throw an exception, the message will not be automatically re pushed (including other consumers), because for rabbitmq Generally, the confirmation of whether the message consumption is successful has not been received, and Channel There is a cache on the consumer side and the connection is not disconnected
3.If rabbitmq After disconnection, it will automatically push again (whether it is a network problem or downtime)
4.If the consumer application restarts, the message will be automatically pushed again
5.If the consumer goes down while processing the message, the message will be automatically pushed to other consumers
6.If the method that listens for the message throws an exception, the message will follow listener.retry If an exception is thrown after the number of retransmissions, the message will not be retransmitted (nor will it be retransmitted to other consumers), but will be pushed again after the application is restarted. because retry It is handled internally by the consumer, including exceptions. For rabbitmq Is unknown (dead letter queue can be used)
7.spring.rabbitmq.listener.retry The configured retransmission is processed in the consumer application, not rabbitqq retransmission
8.Can configure MessageRecoverer Handle the exception message, which will be processed in listener.retry The configuration can be adjusted only after the number of attempts is completed and an exception is thrown MessageRecoverer Handle the exception message, which will be processed in listener.retry It is called only after the number of attempts is completed and an exception is thrown. By default, there are two implementations:
//RepublishMessageRecoverer: to resend messages to the specified queue, it needs to be manually configured, such as:
@Bean
public MessageRecoverer messageRecoverer(RabbitTemplate rabbitTemplate){
    return new RepublishMessageRecoverer(rabbitTemplate, "exchangemsxferror", "routingkeymsxferror");
}
//RejectAndDontRequeueRecoverer: if MessageRecoverer is not manually configured, it will be used by default. The implementation is only to throw exception printing. The source code is as follows:
public class RejectAndDontRequeueRecoverer implements MessageRecoverer {
    protected Log logger = LogFactory.getLog(RejectAndDontRequeueRecoverer.class);
    @Override
    public void recover(Message message, Throwable cause) {
    	if (this.logger.isWarnEnabled()) {
            this.logger.warn("Retries exhausted for message " + message, cause);
    	}
    	throw new ListenerExecutionFailedException("Retry Policy Exhausted", new AmqpRejectAndDontRequeueException(cause), message);
    }
}
retry yml configuration
  rabbitmq:
    username: guest
    password: guest
    port: 5672
    host: localhost
    publisher-confirms: true #  Send the message to the switch confirmation mechanism. Confirm the callback
    publisher-returns: true  #  The message is sent to the switch to confirm whether the feedback is returned
    listener:       # Enable ACK
      direct:
        acknowledge-mode: manual
      simple:
        acknowledge-mode: manual
        retry:
          enabled: true         #  Allow retry of message consumption failure
          max-attempts: 6       # Messages can be consumed up to 6 times
          initial-interval: 1000ms # The interval between multiple consumption of messages is 1 second
          max-interval: 1200000ms #Maximum retry interval (in milliseconds)
          multiplier: 2 #The multiplier applied to the last retry interval, that is, the retry time is the last retry time * 2
          stateless: true
          default-requeue-rejected: false  #  If set to false, the message will be discarded or republished to the dead letter queue
Implementation of dead letter queue
yml configuration
spring:
  rabbitmq:
    username: guest
    password: guest
    port: 5672
    host: localhost
    publisher-confirms: true #  Send the message to the switch confirmation mechanism. Confirm the callback
    publisher-returns: true  #  The message is sent to the switch to confirm whether the feedback is returned
    listener:       # Enable ACK
      direct:
        acknowledge-mode: manual
      simple:
        acknowledge-mode: manual
        retry:
          enabled: true         # Do you support retry
          max-attempts: 6
          initial-interval: 5000ms
          multiplier: 2
          stateless: true
          default-requeue-rejected: false
Dead letter switch and queue configuration
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @describe
 */
@Configuration
@Slf4j
public class TestDLXConfiguration {
    /**
     * Delay queue
     * Messages sent to the queue will expire after a period of time and enter delay_process_queue
     * All message s in the queue have a uniform expiration time
     */
    public static String DELAY_QUEUE   = "delay.queue";

    /**
     * Service switch
     */
    public static String DELAY_EXCHANGE = "delay.queue.exchange";

    /**
     * Actual consumption queue
     * message The queue entered after failure is the actual consumption queue
     */
    public static final String PROCESS_QUEUE = "process.queue";

    /**
     * Treated exchanger
     */
    public static String PROCESS_EXCHANGE = "process.queue.exchange";

    /**
     * Timeout
     */
    public static Long QUEUE_EXPIRATION = 4000L;

    /**
     * Dead letter exchange (switch configuration)
     * @return
     */
    @Bean
    DirectExchange processExchange() {
         log.info("[DLX Switch instance creation succeeded]");
        return new DirectExchange(PROCESS_EXCHANGE);
    }
    /**
     * Set processing queue (dead letter queue)
     * @return
     */
    @Bean
    public Queue processQueue() {
          log.info("[DLX [test queue instance created successfully]");
        return QueueBuilder
                .durable(PROCESS_QUEUE)
                .build();
    }

    /**
     * Bind DLX to actual consumption queue (bind dead letter queue to dead letter switch)
     * @return
     */
    @Bean
    Binding processBinding() {
        return BindingBuilder
                .bind(processQueue())
                .to(processExchange())
                .with(PROCESS_QUEUE);
    }
    /**
     * Configure service queue
     * @return
     */
    @Bean
    public Queue delayQueue() {
       //Map<String,Object> arguments = new HashMap<>(2);
       //arguments.put("x-dead-letter-exchange",DIRCET_EXCHANGE_NAME);
       // arguments.put("x-dead-letter-routing-key",TEST_QUEUE1_NAME);
       // arguments.put("x-message-ttl", 4000L);
       // return new Queue(orderQueue,true,false,false,arguments);
        //Constructor mode
        return QueueBuilder.durable(DELAY_QUEUE)
                // DLX, exchange sent by dead letter, set the dead letter queue switch to the processing switch
                .withArgument("x-dead-letter-exchange", PROCESS_EXCHANGE)
                // The routing key carried by dead letter is used to configure the routing key of the processing queue
                .withArgument("x-dead-letter-routing-key", PROCESS_QUEUE)
                // Set the expiration time. When this event is configured, it is a delayed dead letter queue
                .withArgument("x-message-ttl", QUEUE_EXPIRATION)
                .build();
        
    }





    /**
     * Configure service switch
     * @return
     */
    @Bean
    DirectExchange delayExchange() {
        return new DirectExchange(DELAY_EXCHANGE);
    }


    /**
     * Bind delayQueue2 to the delay switch, and routingKey is the queue name
     * @return
     */
    @Bean
    Binding delayBinding() {
        return BindingBuilder
                .bind(delayQueue())
                .to(delayExchange())
                .with(DELAY_QUEUE);
    }

}
    //send out
   rabbitTemplate.convertAndSend(
                DelayConfig.DELAY_EXCHANGE,
                // routingKey
                DelayConfig.DELAY_QUEUE,
                msg);
Two configurations of delayed dead letter queue
  • Mode 1
rabbitTemplate.convertAndSend("Direct.exchange.name", "Direct.queue1.name",
                msg, message -> {                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                      //The delay time unit is set here in milliseconds
                    message.getMessageProperties().setExpiration("10000");
                    return message;
                });
  • Mode 2
   /**
     * Declare business queue
     * @return Queue
     * When declaring the business queue, a Map is created and two values are put, which are the declarations of the dead letter queue.
     * x-dead-letter-exchange: Name of dead letter switch
     * x-dead-letter-routing-key: The routing key of dead letter switch. Because the types of the two switches in the demo are direct, the routing key must be the same.
     */
    @Bean
    public Queue orderQueue() {
        Map<String,Object> arguments = new HashMap<>(2);
        // Bind the queue to the dead letter switch
        arguments.put("x-dead-letter-exchange",DIRCET_EXCHANGE_NAME);
        arguments.put("x-dead-letter-routing-key",TEST_QUEUE1_NAME);
        // Set expiration time
        arguments.put("x-message-ttl", 4000L);
        return new Queue(orderQueue,true,false,false,arguments);
    }
Dcoker cluster
Download images
docker pull rabbitmq:management
Running multiple rabbitmq containers
## Use "-- link" connection between multiple containers. This attribute cannot be less;
## The Erlang Cookie value must be the same, that is, rabbitmq_ ERLANG_ Value of cookie parameter

docker run -d --hostname rabbit1 --name myrabbit1 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:management

docker run -d --hostname rabbit2 --name myrabbit2 -p 15673:15672  -p 5673:5672 --link myrabbit1:rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:management

docker run -d --hostname rabbit3 --name myrabbit3 -p 15674:15672  -p 5674:5672 --link myrabbit1:rabbit1 --link myrabbit2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:management
Mount operation
docker run -d --hostname rabbit1 --name myrabbit1  -v /usr/herdsric/rabbitmq/rabbitmq1/etc/rabbitmq:/etc/rabbitmq  -v /usr/herdsric/rabbitmq/rabbitmq1/lib/rabbitmq:/var/lib/rabbitmq -v /usr/herdsric/rabbitmq/rabbitmq1/log/rabbitmq:/var/log/rabbitmq -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:management

docker run -d --hostname rabbit2 --name myrabbit2   -v /usr/herdsric/rabbitmq/rabbitmq2/etc/rabbitmq:/etc/rabbitmq  -v /usr/herdsric/rabbitmq/rabbitmq2/lib/rabbitmq:/var/lib/rabbitmq -v /usr/herdsric/rabbitmq/rabbitmq2/log/rabbitmq:/var/log/rabbitmq  -p 15673:15672  -p 5673:5672 --link myrabbit1:rabbit1 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:management

docker run -d --hostname rabbit3 --name myrabbit3   -v /usr/herdsric/rabbitmq/rabbitmq3/etc/rabbitmq:/etc/rabbitmq  -v /usr/herdsric/rabbitmq/rabbitmq3/lib/rabbitmq:/var/lib/rabbitmq -v /usr/herdsric/rabbitmq/rabbitmq3/log/rabbitmq:/var/log/rabbitmq -p 15674:15672  -p 5674:5672 --link myrabbit1:rabbit1 --link myrabbit2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:management

Copy container contents to host
Copy files from physical machine to container: docker cp Physical machine directory container name:Container directory
 Copy files from container to physical machine: docker cp Container name:Container directory physical machine directory
docker cp -a 'container id':/var/log/rabbitmq /usr/herdsric/rabbitmq/rabbitmq3/log/
docker cp -a 'container id'://etc/rabbitmq /usr/herdsric/rabbitmq/rabbitmq3/etc/
docker cp -a 'container id':/var/lib/rabbitmq /usr/herdsric/rabbitmq/rabbitmq3/lib/
Join the RabbitMQ node to the cluster
  • Set node 1:
docker exec -it myrabbit1 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
exit
  • Set node 2:
# The parameter "-- ram" indicates that it is set as a memory node. Ignoring the secondary parameter, it defaults to a disk node
docker exec -it myrabbit2 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbit1
rabbitmqctl start_app
exit
  • Set node 3:
docker exec -it myrabbit3 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbit1
rabbitmqctl start_app
exit
  • You have accessed the account using http: / / physical machine ip:15672. The default account password is guest/guest

Started 3 nodes, 1 disk node and 2 memory nodes To stop the container, stop the disk node first and then the memory node That is, you need to start it first

– link dependency. Turn off the opposite

sr/herdsric/rabbitmq/rabbitmq3/log/rabbitmq:/var/log/rabbitmq -p 15674:15672 -p 5674:5672 --link myrabbit1:rabbit1 --link myrabbit2:rabbit2 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:management

###### Copy container contents to host

Copy files from physical machine to container: docker cp physical machine directory container name: container directory
Copy files from container to physical machine: docker cp container name: container directory physical machine directory
docker cp -a 'container id': / var/log/rabbitmq /usr/herdsric/rabbitmq/rabbitmq3/log/
docker cp -a 'container id' 😕/ etc/rabbitmq /usr/herdsric/rabbitmq/rabbitmq3/etc/
docker cp -a 'container id': / var/lib/rabbitmq /usr/herdsric/rabbitmq/rabbitmq3/lib/

###### Join the RabbitMQ node to the cluster

-  Set node 1:

```shell
docker exec -it myrabbit1 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
exit
  • Set node 2:
# The parameter "-- ram" indicates that it is set as a memory node. Ignoring the secondary parameter, it defaults to a disk node
docker exec -it myrabbit2 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbit1
rabbitmqctl start_app
exit
  • Set node 3:
docker exec -it myrabbit3 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbit1
rabbitmqctl start_app
exit
  • You have accessed the account using http: / / physical machine ip:15672. The default account password is guest/guest

Started 3 nodes, 1 disk node and 2 memory nodes To stop the container, stop the disk node first and then the memory node That is, you need to start it first

– link dependency. Turn off the opposite

Topics: Java RabbitMQ queue switch