Working mode of RabbitMQ series

Working mode of RabbitMQ

Work queues work queue mode

Mode description

As shown in the figure, a queue corresponds to multiple consumers. C1 and C2 belong to a competitive relationship. The same message is either consumed by C1 or C2

Summary: Work queues multiple consumers consume messages in the same queue

Application scenario: when tasks are too heavy or there are many tasks, using work queue can improve task processing speed

producer

public class MessageProducer {

    public static void sendMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Create queue
        /**
         * Parameter Description:
         * 1.queue: Queue name
         * 2.durable: Is it persistent? After mq restarts, the data still exists
         * 3.exclusive: 
         *            - Exclusive. Only one listener can this queue
         *            - Delete queue when connection is closed
         * 4.autoDelete: Delete automatically. If there is no Consumer, delete automatically
         * 5.arguments: parameter

         */
        // If there is no queue named "first_queue", it will be created, otherwise it will not be created
        channel.queueDeclare("work_queue",true,false,false,null);
        // 6. Send message
        /**
         * Parameters:
         * 1.exchange:Switch name. In simple mode, the switch defaults to ''
         * 2.routing key:Routing mingc
         * 3.props:configuration information
         * 4.body:Message data sent
         */
        for (int i = 1; i < 21; i++) {
            String message = "work queues The first" + i + "Message";
            channel.basicPublish("","work_queue",null,message.getBytes());
        }

        // 7. Release resources
        channel.close();
        connection.close();
    }
}

To test the effect, send 20 messages in a loop

consumer

public class MessageConsumer {
    public static void getMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Create queue
        /**
         * Parameter Description:
         * 1.queue: Queue name
         * 2.durable: Is it persistent? After mq restarts, the data still exists
         * 3.exclusive: 
         *            - Exclusive. Only one listener can this queue
         *            - Delete queue when connection is closed
         * 4.autoDelete: Delete automatically. If there is no Consumer, delete automatically
         * 5.arguments: parameter

         */
        // If there is no queue named "first_queue", it will be created, otherwise it will not be created
        channel.queueDeclare("work_queue",true,false,false,null);
        // 6. Receive message
        /**
         * handleDelivery()Parameters:
         * 1.consumerTag:identification
         * 2.envelope:Get some information, switch, routing key
         * 3.properties:configuration information
         * 4.bady:data
         */
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("Client 1 consumption:" + new String(body));
            }
        };
        channel.basicConsume("work_queue",true,consumer);
        // 7. Release resources? No consumer is required, which is equivalent to a listener listening to the queue at all times
        // Here we just don't let the program end and wait for the callback function to execute
        while (true){}
    }
}

Copy the same code and modify the printout. As client 2, you will see work when you start_ Queue has two consumers

After the consumer starts, run the production client to send a message

The consumer client 1 console prints as follows:

Client 1 consumes: the second message of work queues
Client 1 consumes: the fourth message of work queues
Client 1 consumption: work queues message 6
Client 1 consumption: work queues message 8
...

The consumer client 2 console prints as follows:

Client 2 consumes: the first message of work queues
Client 2 consumes: the third message of work queues
Client 2 consumption: the fifth message of work queues
Client 2 consumption: work queues message 7
Client 2 consumption: work queues message 9

...

It can be seen that the 20 messages produced are shared by the two consumers

Pub/Sub subscription mode

Mode description

Exchange is added to this mode, and the whole sending process is changed compared with the previous one. Messages produced by producers are no longer sent to the queue, but to the switch

Exchange: a switch (X), on the one hand, receives messages sent by producers, and on the other hand, knows how to process messages, such as delivering to a special queue, delivering to all queues, or discarding messages. How to operate depends on the type of exchange. There are three common types:

  • Fanout: broadcast and deliver the message to all bound switch queues
  • Direct: direct: send the message to the queue that matches the specified routing key
  • Topic: wildcard, which gives the message to the queue conforming to the routing pattern

Exchange is only responsible for forwarding messages and does not have the ability to store messages. Therefore, if there is no queue bound to exchange or no queue that meets the routing rules, messages will be lost

producer

public class MessageProducer_PubSub {

    public static void sendMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Common switches
        /**
         * Parameter Description:
         * 1.exchange: Switch Type 
         * 2.type: Switch Type 
         *     DIRECT("direct"),directional
         *     FANOUT("fanout"),Send to all bound queues
         *     TOPIC("topic"),Wildcard mode
         *     HEADERS("headers");Parameter matching
         * 3.durable: Persistent
         * 4.autoDelete: Delete automatically
         * 5.internal: Internal use, generally false
         * 6.arguments: parameter
         */
        String exchangeName = "test_fanout";
        channel.exchangeDeclare(exchangeName,BuiltinExchangeType.FANOUT,true,false,false,null);
        // 6. Create queue
        String queue1 = "test_fanout_queue1";
        String queue2 = "test_fanout_queue2";
        channel.queueDeclare(queue1,true,false,false,null);
        channel.queueDeclare(queue2,true,false,false,null);
        // 7. Bind queue and switch
        /**
         * Parameter Description:
         * 1.queue:Queue name
         * 2.exchange: Switch name
         * 3.routingKey:Routing keys, binding rules
         * If the switch type is fanout, routingKey is set to ""
         */
        channel.queueBind(queue1,exchangeName,"");
        channel.queueBind(queue2,exchangeName,"");
        // 8. Send message to switch
        String message = "pubsub Mode message";
        channel.basicPublish(exchangeName,"", null,message.getBytes());
        // 9. Release resources
        channel.close();
        connection.close();
    }
}

After running the code, look at the rabbit console

The switch has added a custom switch name

Click the switch name to view the details, and you can see the binding relationship as shown in the figure below

The queue adds two queues bound to the switch, and there is a message to be consumed in each queue

consumer

public class MessageConsumer_PubSub1 {

    public static void getMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Receive message
        /**
         * handleDelivery()Parameters:
         * 1.consumerTag:identification
         * 2.envelope:Get some information, switch, routing key
         * 3.properties:configuration information
         * 4.bady:data
         */
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("Client 1 consumption:" + new String(body));
            }
        };
        channel.basicConsume("test_fanout_queue1",true,consumer);
        // 6. Release resources? No consumer is required, which is equivalent to a listener listening to the queue at all times
        // Here we just don't let the program end and wait for the callback function to execute
        while (true){}
    }
}

Copy the same code and modify the listening queue to test_fanout_queue2, modify the print information as client 2, and start consumer client 1 and consumer client 2 respectively

The console output is as follows:

Client 1 consumption: messages in pubsub mode

Client 2 consumption: messages in pubsub mode

It can be seen that the same message is sent to the switch, distributed by the switch to two queues, and the two clients consume in the corresponding queues respectively

Routing mode

Mode description:

The figure shows different log levels, which are distributed to different queues by the switch

  • The queue is bound to the switch. It cannot be bound arbitrarily. Instead, specify a RoutingKey
  • When a message is sent to exchange, the RoutingKey of the message must be specified
  • Exchange does not send messages to each bound queue, but judges according to the routingkey of the message. Messages will be received only when the routingkey of the queue is consistent with the routingkey of the message
  • Switch type is Direct, binding

producer

public class MessageProducer_Routing {

    public static void sendMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Common switches
        /**
         * Parameter Description:
         * 1.exchange: Switch Type 
         * 2.type: Switch Type 
         *     DIRECT("direct"),directional
         *     FANOUT("fanout"),Send to all bound queues
         *     TOPIC("topic"),Wildcard mode
         *     HEADERS("headers");Parameter matching
         * 3.durable: Persistent
         * 4.autoDelete: Delete automatically
         * 5.internal: Internal use, generally false
         * 6.arguments: parameter
         */
        String exchangeName = "test_direct";
        channel.exchangeDeclare(exchangeName,BuiltinExchangeType.DIRECT,true,false,false,null);
        // 6. Create queue
        String queue1 = "test_direct_queue1";
        String queue2 = "test_direct_queue2";
        channel.queueDeclare(queue1,true,false,false,null);
        channel.queueDeclare(queue2,true,false,false,null);
        // 7. Bind queue and switch
        /**
         * Parameter Description:
         * 1.queue:Queue name
         * 2.exchange: Switch name
         * 3.routingKey:Routing keys, binding rules
         * If the switch type is fanout, routingKey is set to ""
         */
        // error queue binding
        channel.queueBind(queue1,exchangeName,"error");
        // info error warn queue binding
        channel.queueBind(queue2,exchangeName,"info");
        channel.queueBind(queue2,exchangeName,"error");
       channel.queueBind(queue2,exchangeName,"warning");
        // 8. Send message to switch
        String messageInfo = "Log information: info";
        String messageError = "Log information: error";
        String messageWarn = "Log information: warning";
        // Send messages of different RoutingKey types and observe how exchange handles them
        channel.basicPublish(exchangeName,"info", null,messageInfo.getBytes());
        channel.basicPublish(exchangeName,"error", null,messageError.getBytes());
        channel.basicPublish(exchangeName,"warning", null,messageWarn.getBytes());
        // 9. Release resources
        channel.close();
        connection.close();
    }
}

Run the producer code and observe the rabbit console

The new name of the Exchange switch is test_direct switch

Click the name to enter to view the binding relationship with the queue

In the queues column, you can see that messages are distributed to different queues according to different routing keys

Queue 1 receives only 1 message with RoutingKey error

Queue 2 receives messages with RoutingKey info, error and warning for three days

Because both queues are bound with the message with RoutingKey as error, the error message will appear in both queues

consumer

public class MessageConsumer_Routing1 {

    public static void getMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Receive message
        /**
         * handleDelivery()Parameters:
         * 1.consumerTag:identification
         * 2.envelope:Get some information, switch, routing key
         * 3.properties:configuration information
         * 4.bady:data
         */
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("Client 1 consumption:" + new String(body));
            }
        };
        channel.basicConsume("test_direct_queue1",true,consumer);
        // 6. Release resources? No consumer is required, which is equivalent to a listener listening to the queue at all times
        // Here we just don't let the program end and wait for the callback function to execute
        while (true){}
    }
}

Copy the same code, modify the listening queue name, and modify the print information as client 2

Start the consumer console and print as follows:

Client 1 consumption log information: error

Client 2 consumption log information: info
Client 2 consumption log information: error
Client 2 consumption log information: warning

Summary: the messages sent by the producer are processed by exchange, matched according to the RoutingKey, distributed to different queues, and consumed by the consumers corresponding to the queue

Topic wildcard mode

Mode description:

  • The switch type is Topic and wildcard mode
  • For example, the RoutingKey is Usa.news, which can match the queue of USA. #, or the queue of #. News
  • Process: the producer sends messages to the switch, which distributes them to different queues according to the matching rules set by the queue RoutingKey

producer:

public class MessageProducer_Topic {

    public static void sendMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Common switches
        /**
         * Parameter Description:
         * 1.exchange: Switch Type 
         * 2.type: Switch Type 
         *     DIRECT("direct"),directional
         *     FANOUT("fanout"),Send to all bound queues
         *     TOPIC("topic"),Wildcard mode
         *     HEADERS("headers");Parameter matching
         * 3.durable: Persistent
         * 4.autoDelete: Delete automatically
         * 5.internal: Internal use, generally false
         * 6.arguments: parameter
         */
        String exchangeName = "test_topic";
        channel.exchangeDeclare(exchangeName,BuiltinExchangeType.TOPIC,true,false,false,null);
        // 6. Create queue
        String queue1 = "test_topic_queue1";
        String queue2 = "test_topic_queue2";
        channel.queueDeclare(queue1,true,false,false,null);
        channel.queueDeclare(queue2,true,false,false,null);
        // 7. Bind queue and switch
        /**
         * Parameter Description:
         * 1.queue:Queue name
         * 2.exchange: Switch name
         * 3.routingKey:Routing keys, binding rules
         * If the switch type is fanout, routingKey is set to ""
         */
        // Order related information and info information are stored in queue 1
        channel.queueBind(queue1,exchangeName,"*.info.*");
        channel.queueBind(queue1,exchangeName,"order.#");
        // Order error information and payment information are stored in queue 2
        channel.queueBind(queue2,exchangeName,"order.error.*");
        channel.queueBind(queue2,exchangeName,"pay.#");
        // 8. Send message to switch
        String message = "Topic Mode message";
        // Send messages of different RoutingKey types and observe how exchange handles them
        channel.basicPublish(exchangeName,"test.info.test", null,message.getBytes());
        channel.basicPublish(exchangeName,"order.error.select", null,message.getBytes());
        channel.basicPublish(exchangeName,"order.error.select.success", null,message.getBytes());
        channel.basicPublish(exchangeName,"pay.test", null,message.getBytes());
        // 9. Release resources
        channel.close();
        connection.close();
    }
}

Start the producer and observe the rabbit console

The new name of Exchange is test_topic switch

Click the name to view the wildcards of the queue and related bindings

Queue condition

Queue 1 is bound with wildcards *. Info. *, order. #. The matching RoutingKey has test.info.test, order.error.select, order.error.select.success, so it has three messages

Queue 2 is bound with wildcards order.error. *, pay. #, and the matching routingkeys include order.error.select and pay.test, so there are only two

Why can't order.error. * match order.error.select.success

Because * represents one word, # represents multiple words, and the word definition is bounded by. So it cannot be matched

consumer

public class MessageConsumer_Topic1 {

    public static void getMessage() throws IOException, TimeoutException {
        // 1. Create a connection factory
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 2. Set parameters
        // ip, the default is local localhost
        connectionFactory.setHost("127.0.0.1");
        // Port, default 5672
        connectionFactory.setPort(5672);
        // Virtual machine, default/
        connectionFactory.setVirtualHost("my_vhost");
        // Account number, default: guest
        connectionFactory.setUsername("admin");
        // Password, default: guest
        connectionFactory.setPassword("admin");
        // 3. Create a Connection
        Connection connection = connectionFactory.newConnection();
        // 4. Create a Channel
        Channel channel = connection.createChannel();
        // 5. Receive message
        /**
         * handleDelivery()Parameters:
         * 1.consumerTag:identification
         * 2.envelope:Get some information, switch, routing key
         * 3.properties:configuration information
         * 4.bady:data
         */
        Consumer consumer = new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                System.out.println("Client 1 consumption:" + new String(body));
            }
        };
        channel.basicConsume("test_topic_queue1",true,consumer);
        // 6. Release resources? No consumer is required, which is equivalent to a listener listening to the queue at all times
        // Here we just don't let the program end and wait for the callback function to execute
        while (true){}
    }
}

Copy the code, modify the queue name, and modify the print content as client 2

Run two consumer clients and print them on the console respectively

Client 1:

Client 1 consumption: Topic mode message
Client 1 consumption: Topic mode message
Client 1 consumption: Topic mode message

Client 2:

Client 1 consumption: Topic mode message
Client 1 consumption: Topic mode message

Summary: topic mode is very similar to Routing mode, but Routing mode belongs to value binding and topic belongs to wildcard binding, which has a wider application range

Tags: Java RabbitMQ

Posted on Mon, 20 Sep 2021 10:17:18 -0400 by Mad Mick