RabbitMQ官方文档翻译之Topics(五)

Topics (using the Java client)

In the previous tutorial we improved our logging system. Instead of using a fanout exchange only capable of dummy broadcasting, we used a direct one, and gained a possibility of selectively receiving the logs.

在上一个教程中,我们改进了我们的日志记录系统。 而不是使用只能进行广播的fanout exchange。取而代之的是direct exchange,它使选择性地接收日志成为可能。

Although using the direct exchange improved our system, it still has limitations - it can't do routing based on multiple criteria.

虽然使用direct exchange改进了我们的系统,但它仍然有限制 - 它不能基于多个标准进行路由选择。

In our logging system we might want to subscribe to not only logs based on severity, but also based on the source which emitted the log. You might know this concept from the syslog unix tool, which routes logs based on both severity (info/warn/crit...) and facility (auth/cron/kern...).

在的日志记录系统中,我们想要订阅日志,不仅是根据严重性,而且还可以基于发送日志的源进行订阅。 您可能会从syslog unix工具中了解此概念,该工具根据严重性(info / warn / crit ...)和设备(auth / cron / kern ...)路由日志。

That would give us a lot of flexibility - we may want to listen to just critical errors coming from 'cron' but also all logs from 'kern'.

To implement that in our logging system we need to learn about a more complex topicexchange.

这将给我们带来很大的灵活性 - 我们不仅要监听来自“cron”设备的严重错误Error日志消息,而且要监听来自“kern”设备的所有日志。

要在我们的日志记录系统中实现这个需求,我们需要了解一个更复杂的topic exchange。

Topic exchange

Messages sent to a topic exchange can't have an arbitrary routing_key - it must be a list of words, delimited by dots. The words can be anything, but usually they specify some features connected to the message. A few valid routing key examples: "stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit". There can be as many words in the routing key as you like, up to the limit of 255 bytes.

发送到 topic exchange的消息不能具有随意的routingkey - 它必须是由点分隔的单词列表。 这些单词可以是任意的,但通常它们指定与消息相关联的一些单词。 例如这些有效的routing key:“stock.usd.nyse”,“nyse.vmw”,“quick.orange.rabbit”。routing key中可以有任意多的单词,但最多可达255个字节。

The binding key must also be in the same form. The logic behind the topic exchange is similar to a direct one - a message sent with a particular routing key will be delivered to all the queues that are bound with a matching binding key. However there are two important special cases for binding keys:

binding key也必须是相同的格式。topic exchange背后的逻辑类似于direct exchange , 发送到exchange具有特定routing key的消息将被传递到与匹配的binding key绑定的所有队列。 但是,binding keys有以下两个要求:

  • * (star) 可以代替一个单词            
  • # (hash) 可以代替0个或多个单词

It's easiest to explain this in an example:

看下面这个例子就很容易明白:

In this example, we're going to send messages which all describe animals. The messages will be sent with a routing key that consists of three words (two dots). The first word in the routing key will describe speed, second a colour and third a species: "<speed>.<colour>.<species>".

在这个例子中,我们将发送所有描述动物的消息。 消息将使用由三个字(两个点)组成的routing key发送。 rounting key中的第一个字将描述速度speed,第二个颜色colour和第三个物种species:"<speed>.<colour>.<species>"

We created three bindings: Q1 is bound with binding key "*.orange.*" and Q2 with "*.*.rabbit" and "lazy.#".

我们创建了三个绑定:Q1 binding key“* .orange。*”,  Q2 binding key是“*.*.rabbit”和“lazy.#”

These bindings can be summarised as:

  • Q1 is interested in all the orange animals.
  • Q2 wants to hear everything about rabbits, and everything about lazy animals.

3个绑定关系可以总结为:

  • Q1 对所有橙色动物感兴趣
  • Q2 对所有兔子和行动缓慢的动物感兴趣

A message with a routing key set to "quick.orange.rabbit" will be delivered to both queues. Message "lazy.orange.elephant" also will go to both of them. On the other hand "quick.orange.fox" will only go to the first queue, and "lazy.brown.fox" only to the second. "lazy.pink.rabbit" will be delivered to the second queue only once, even though it matches two bindings. "quick.brown.fox" doesn't match any binding so it will be discarded.

这样

routing key设置为“quick.orange.rabbit”和“lazy.orange.elephant”的消息将传递给两个队列。                                                         routing key设置为“quick.orange.fox”的消息只会传递到第一个队列                                                                                                               routing key设置为“lazy.brown.fox”的消息只能到第二个队列。 

routing key设置为“lazy.pink.rabbit”的消息只能被传递到第二个队列,且只传送一次,即使它匹配两个绑定,但绑定的都是是同一个队列。 routing key设置为“quick.brown.fox”的消息不匹配任何rounting key,因此它将被丢弃。

What happens if we break our contract and send a message with one or four words, like "orange" or "quick.orange.male.rabbit"? Well, these messages won't match any bindings and will be lost.

如果我们设置的routing key找不到能够匹配的binding key, 那么这些消息将不会匹配任何绑定,并将丢失

Topic exchangeTopic exchange is powerful and can behave like other exchanges.When a queue is bound with "#" (hash) binding key - it will receive all the messages, regardless of the routing key - like in fanout exchange.When special characters "*" (star) and "#" (hash) aren't used in bindings, the topic exchange will behave just like a direct one.

Topic exchange的功能十分强大。当队列的binding key设为“#”,无论routing key如何,会收到所有的消息 。

如果采用的是Topic类型的exchange,但是binding key不使用"#"和“*",那么Topic就变得和Direct效果一样了。

Putting it all together

We're going to use a topic exchange in our logging system. We'll start off with a working assumption that the routing keys of logs will have two words: "<facility>.<severity>".

下面是采用Topic exchange改造的日志记录系统

The code is almost the same as in the previous tutorial.

The code for EmitLogTopic.java:

import com.rabbitmq.client.*;

import java.io.IOException;

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();

        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        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();
    }
    //...
}

The code for ReceiveLogsTopic.java:

import com.rabbitmq.client.*;

import java.io.IOException;

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();

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

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

    for (String bindingKey : argv) {
      channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
    }

    System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

    Consumer consumer = new DefaultConsumer(channel) {
      @Override
      public void handleDelivery(String consumerTag, Envelope envelope,
                                 AMQP.BasicProperties properties, byte[] body) throws IOException {
        String message = new String(body, "UTF-8");
        System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'");
      }
    };
    channel.basicConsume(queueName, true, consumer);
  }
}

Compile and run the examples, including the classpath as in Tutorial 1 - on Windows, use %CP%.

To compile:

javac -cp $CP ReceiveLogsTopic.java EmitLogTopic.java

To receive all the logs:

java -cp $CP ReceiveLogsTopic "#"

To receive all logs from the facility "kern":

java -cp $CP ReceiveLogsTopic "kern.*"

Or if you want to hear only about "critical" logs:

java -cp $CP ReceiveLogsTopic "*.critical"

You can create multiple bindings:

java -cp $CP ReceiveLogsTopic "kern.*" "*.critical"

And to emit a log with a routing key "kern.critical" type:

java -cp $CP EmitLogTopic "kern.critical" "A critical kernel error"

Have fun playing with these programs. Note that the code doesn't make any assumption about the routing or binding keys, you may want to play with more than two routing key parameters.

(Full source code for EmitLogTopic.java and ReceiveLogsTopic.java)

Next, find out how to do a round trip message as a remote procedure call in tutorial 6


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值