RabbitMQ tutorial Routing

Posted by kevinsequeira on Thu, 30 Dec 2021 08:39:54 +0100

Foreword: in the last article, our program realized the broadcast of messages to all consumers. In this chapter, we will add a feature. We will only subscribe to a subset of messages. For example, we will save the message with ERROR level to disk and info Warning level logs are printed directly

RabitMQ installation

How to install: https://blog.csdn.net/Beijing_L/article/details/119042261

legend


P (producer): the producer belongs to the sender of data, and the sent message is put into the queue

C (consumer): the consumer belongs to the receiver of data, finds the message in the queue, reads the message from the queue for business operations

Queue: RabbitMQ is used to store messages. The queue is characterized by first in first out

Several concepts


Bindings

In the previous chapter, we know the relationship between the switch and the queue. We call it a binding and create a binding. The binding is also easy to understand, for example

channel.queueBind(queueName, EXCHANGE_NAME, "");

A key parameter for binding is called routingkey. In order to avoid confusion, we call it bindingkey, which allows us to create a binding relationship through a routing key. The meaning of bindingkey depends on the second brother parameter exchange, that is, the switch type. The fan out exchange we used last time ignored this parameter

    /**
     * @param Queue name
     * @param Exchanger name
     * @param Use bound routing keys
     * @return a binding-confirm method if the binding was successfully created
     * @throws java.io.IOException if an error is encountered
     */
    Queue.BindOk queueBind(String queue, String exchange, String routingKey) throws IOException;

Direct exchange

When we use the fan out switch, we will find that it is not very flexible. The fan out switch broadcasts messages in an almost mindless way. It is applicable when we want to filter and process messages. For example, the system has many log messages. After broadcasting messages, some consumers process ERROR severity messages, such as writing them to disk, and some consumers process non ERROR messages, such as printing out. At this time, we need to use the direct connection switch. The algorithm of the direct connection switch is very simple: when a message enters the queue and the routing key of the message to be sent is exactly the same as the binding key of the direct connection switch and the queue relationship, the message will be sent to the associated queue

As shown in the figure below, there are two queues Q1 and Q2 linked to the direct switch X. the first queue has a binding key orange, and the second brother queue has two binding keys black and green. When a message is sent to the direct switch with the routing key orange, the message will be pushed to the Q1 queue, When the message is sent to the direct connection switch x with black or green as the routing key, the message will be pushed to the Q2 queue

 

Multiple binding

Of course, it is also legal to use the same bindingkey to bind multiple queues. In the above example, we can use black to bind Q1 and Q2 at the same time. When a message is sent to the direct connection switch X with black as the route, the message will be pushed to Q1 and Q2. This practical method replaces the fan out switch

Implementation diagram

In order to process log messages according to the log ERROR level mentioned above, we use the message level as the routing key, and use the message level as the bindingKey to bind the direct switch and different queues. C1 only processes the log of ERROR level, which is used to save it to the disk file, and C2 receives all logs to print out As shown in the figure below

 

Reference code

producer

Create 3 messages according to Lu Youjian

public class Producer {

    private static final String EXCHANGE_NAME = "exchange_direct_log";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");


        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        //Exchange type = direct direct exchange, routingKeys =bindingkey
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");

        //routingKeys
        List<String> routingKeys = Arrays.asList("INFO", "WARNING", "ERROR");

        for (String rountingkey : routingKeys) {
            String message =rountingkey+ " Send the message level:" ;
            channel.basicPublish(EXCHANGE_NAME, rountingkey, null, message.getBytes("UTF-8"));
            System.out.println(" Send" + rountingkey + "':'" + message);
        }


        channel.close();
        connection.close();
    }
}

among

Direct indicates a direct switch

channel.exchangeDeclare(EXCHANGE_NAME, "direct");

Send message according to routing key

 channel.basicPublish(EXCHANGE_NAME, rountingkey, null, message.getBytes("UTF-8"));

consumer

//Processing: "INFO", "WARNING","ERROR"
public class CustomerReviver1 {
    private static final String EXCHANGE_NAME = "exchange_direct_log";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");


        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        //Declare the switch and get the anonymous queue
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");

        String queueName = channel.queueDeclare().getQueue();
        channel.queueBind(queueName, EXCHANGE_NAME, "");


        //Setting bindingkey
        List<String> bindingkeys = Arrays.asList("INFO", "WARNING","ERROR");
        for (String bindingkey : bindingkeys) {
            channel.queueBind(queueName,EXCHANGE_NAME,bindingkey);
            System.out.println("CustomerReviver1 exchange:"+EXCHANGE_NAME+"," +
                    " queue:"+queueName+", BKey:" + bindingkey);

        }

        System.out.println("CustomerReviver1  Waiting for messages");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" +
                    delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
            System.out.println(" [x] do print");
        };
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });

    }
}


//Another class consumer 2 handles "ERROR"

public class CustomerReviver2 {

    private static final String EXCHANGE_NAME = "exchange_direct_log";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");


        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");

        String queueName = channel.queueDeclare().getQueue();
        channel.queueBind(queueName, EXCHANGE_NAME, "");


        //channel binding bindingkeys
        List<String> bindingkeys = Arrays.asList("ERROR");
        for (String bindingkey : bindingkeys) {
            channel.queueBind(queueName, EXCHANGE_NAME, bindingkey);
            System.out.println("CustomerReviver2 exchange:" + EXCHANGE_NAME + "," +
                    " queue:" + queueName + ", BKey:" + bindingkey);

        }
        System.out.println("CustomerReviver2  Waiting for messages");


        DeliverCallback deliverCallback = (consumerTag, delivery) -> {

            //routingKey=bindingKey
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" +
                    delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
            System.out.println(" [x] do saving");
        };
        channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });

    }
}

results of enforcement

Producer creates 3 messages

 SendINFO':'INFO Send the message level:
 SendWARNING':'WARNING Send the message level:
 SendERROR':'ERROR Send the message level:

consumer

##Consumer customerriver1
CustomerReviver1 exchange:exchange_direct_log, queue:amq.gen-6tprkkdqdrbhk2Elkddyyw, BKey:INFO
CustomerReviver1 exchange:exchange_direct_log, queue:amq.gen-6tprkkdqdrbhk2Elkddyyw, BKey:WARNING
CustomerReviver1 exchange:exchange_direct_log, queue:amq.gen-6tprkkdqdrbhk2Elkddyyw, BKey:ERROR
CustomerReviver1  Waiting for messages
 [x] Received 'INFO':'INFO Send the message level:'
 [x] do print
 [x] Received 'WARNING':'WARNING Send the message level:'
 [x] do print
 [x] Received 'ERROR':'ERROR Send the message level:'
 [x] do print



##The consumer customerrevier2 only processes ERROR level messages
CustomerReviver2 exchange:exchange_direct_log, queue:amq.gen-CzPTr7XnTLLgURIS-gqRKA, BKey:ERROR
CustomerReviver2  Waiting for messages
 [x] Received 'ERROR':'ERROR Send the message level:'
 [x] do saving

Topics: message queue