RabbitMQ learning-the sixth topic type exchange

In the last article, we made a slight improvement to the previous logging system. Instead of using fanout type exchanges to broadcast, direct type exchanges are used to selectively receive log messages.

Although using the direct type of exchange improves the logging system, it still has some limitations (messages cannot be routed based on multiple factors).

In our logging system, we hope to not only subscribe according to the log level, but also subscribe according to the specified routing key. You should understand that, like the system log tool of unix, the log message routing rules are not only based on the log level (info / warn / crit ...), but also on the device (auth / cron / kern ...)

This greatly improves the flexibility, for example, we can only listen to the error level logs pushed by kern.

In order to implement such a function in our logging system, we need to learn more about topic type exchanges.

1. Topic type exchange

When a message is sent to a topic-type exchange, the routing_key cannot be specified arbitrarily (must refer to a series of strings connected by dots. The word can be arbitrary, but it is generally more or less related to the message) The length of the routing key cannot exceed 255 bytes.

Binding key must be the same way. Topic type exchange is like a direct exchange: a message specified by the producer to determine the routing key will be pushed to all consumers whose Binding key can match. However, there are two special cases for this binding:

  • * (Asterisk): can (only) match a word
  • # (Pound sign): can match multiple words (or zero)

Here is an example:

In this example, we will send some messages describing animals. The first word of the Routing key describes speed, the second word describes color, and the third word describes species: "..".

Here we create three Binding: "Binding key is . .Orange " of Q1, and the binding key is " . And" lazy #. "The Q2 .rabbit".

These bindings can be summarized as:

  • Q1 is interested in all orange animals;
  • Q2 hopes to get all the rabbit (rabbit) information, as well as lazy (lazy. #) Animal information.

A message with "quick.orange.rabbit" as the routing key will be pushed to the two queues of Q1 and Q2, and a message with the routing key of "lazy.orange.elephant" will also be pushed to Q1 and Q2. But if the routing key is "quick.orange.fox", the message will only be pushed to Q1; the message with the routing key "lazy.brown.fox" will be pushed to Q2, and the routing key is "lazy.pink. The "rabbit" message will also be pushed to Q2, but the same message will only be pushed to Q2 once.

If the exchange and routing key specified when sending the message do not have the corresponding exchange and binding key bound to it on the consumer side, then this message will be discarded. For example: "orange" and "quick.orange.male.rabbit". But the routing message "lazy.orange.male.rabbit" will be pushed to Q2.

Topic type exchange:

Topic type exchange is very powerful, and other types of exchange can also be realized.

  • When a queue is bound with a binding key of "#", it will receive all messages, which is very similar to the fanout type exchange.
  • When the binding key does not contain "*" and "#", it is very similar to direct exchange.

2. The final realization

We are going to use topic type exchange in the log system. At the beginning we prepared the routing keys using two words: ".". The code is similar to the previous one, EmitLogTopic.java:

public class EmitLogTopic {
    private static final String EXCHANGE_NAME = "topic_logs";

    public static void main(String[] argv)
                  throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        //指定一个topic类型的exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        //这里拿到routing key
        String routingKey = getRouting(argv);
        String message = getMessage(argv);
        channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes());
        System.out.println(" [x] Sent '" + routingKey + "':'" + message + "'");

        connection.close();
    }
    //...
}

Code of ReceiveLogsTopic.java:

public class ReceiveLogsTopic {
    private static final String EXCHANGE_NAME = "topic_logs";
    public static void main(String[] argv)
                  throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("localhost");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();

        //指定一个topic类型的exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");
        String queueName = channel.queueDeclare().getQueue();

        if (argv.length < 1){
            System.err.println("Usage: ReceiveLogsTopic [binding_key]...");
            System.exit(1);
        }

        //绑定binding key
        for(String bindingKey : argv){
            channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
        }

        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(queueName, true, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            String routingKey = delivery.getEnvelope().getRoutingKey();

            System.out.println(" [x] Received '" + routingKey + "':'" + message + "'");
        }
    }
}

3. Summary

On the basis of the above, it only enriches the writing of routing key and binding key.

Published 40 original articles · 25 praises · 100,000+ views

Guess you like

Origin blog.csdn.net/yym373872996/article/details/105651987