RabbitMQ erlang "topics"

    原文链接:http://www.rabbitmq.com/tutorials/tutorial-five-python.html

    在前面的例子中我们改进了我们的日志系统。使用 fanout 类型的exchage 只能广播消息。我们使用 direct 来代替,获得了选择性接收消息的可能。

    虽然使用direct类型的exchange改善了我们的系统,但它仍然有缺陷,它不能基于多种条件 进行routing。

    在我们的日志系统中,我们可能想要订阅日志不仅基于严重性程度,而且基于发布日志的源码。你可能知道 syslog unix tool 中的概念, 那个基于 严格的(info/warning/crit...)和灵巧的(auth/cron/kern)。
    这将给我们许多灵活性——我们可能想听仅来自于 'corn'日志中的 严重的错误和kern 里面的所有日志。

    在我们的日志系统为了实现那个,我们需要学习更复杂的 topic exchange.

    Topic exchange

发送给topic exchange的消息不能随便定义一个routing key——routing key 必须是一个由”.”号分隔的单词列表。单词可以是任意的,但是一般情况下它应该代表消息的一些特征。比如下面一些routing key :

“stock.usd.nyse”  “nyse.vmw”  “quick.orange.rabbit”

Routing key 的最大长度限制为255字节。

队列的binding key 也必须是同样的格式。Topic exchange的逻辑跟direct exchange差不多——带有指定routing key的消息将会被发送到有相同binding key 的消息队列中。

Binding key 有两特例:

  • *(star) 代表一个单词

  • #(hash) 代表0个或者多个单词

    如下面的例子

RabbitMQ erlang "topics"_第1张图片

在这个例子中我们将发送描述动物的消息。消息的routing key 由三个单词组成,第一个单词代表动物的速度,第二个单词代表动物的颜色,第三个单词代表动物的种类。”<celerity>.<colour>.<species>”

我们创建三个绑定:Q1使用binding key “*.orange.*”, Q2使用binding key “*.*.rabbit” 和”lazy.#”。 也就是说Q1对颜色为orange的动物感兴趣,而Q2对所有的rabbit和速度为lazy的动物感兴趣。

routing key 为'qucik.orange.rabbit'的消息将会被发送Q1和Q2队列, "lazy.orange.elephant"消息也会发送到Q1和Q2。 “quick.orange.fox”仅仅去Q1,“lazy.brown.fox”仅去Q2.  "lazy.pink.rabbit"将会被发送给Q2一次,虽然它匹配两个bindings. “quick.brown.fox”不匹配任意binding ,所以它被丢弃。

如果我们打破规则,发送一个单词或者四个单词的消息将会发生什么,如: “orange”或"quick.orange.male.rabbit"?好吧,这个消息将不匹配任何一个bindings,将会被丢弃。

另一种情况,“lazy.orange.male.rabbit”, 虽然他也是四个单词,但是它将会匹配Q2 binding 将会被发送到Q2。因为匹配“lazy.#”

RabbitMQ erlang "topics"_第2张图片

    tipic exchange 是强大的,你能表现的像其他的exchanges.

    当一个队列的 binding key 是"#"(hash) ——它将收到所有的消息,无视 routing key :向 fanout exchange.

    当 bindings里没有 使用"*"和"#"特殊字符时, topic echange 和 direct exchange 行为将会一样。

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>".

emit_log_topic.erl

-module(emit_log_topic).
-compile([export_all]).

-include_lib("amqp_client/include/amqp_client.hrl").

main(Argv) ->
    {ok, Connection} =
        amqp_connection:start(#amqp_params_network{host = "localhost"}),
    {ok, Channel} = amqp_connection:open_channel(Connection),

    amqp_channel:call(Channel, #'exchange.declare'{exchange = <<"topic_logs">>,
                                                   type = <<"topic">>}),

    {RoutingKey, Message} = case Argv of
                                [] ->
                                    {<<"anonymous.info">>, <<"Hello World!">>};
                                [R] ->
                                    {list_to_binary(R), <<"Hello World!">>};
                                [R | Msg] ->
                                    {list_to_binary(R), list_to_binary(string:join(Msg, " "))}
                            end,
    amqp_channel:cast(Channel,
                      #'basic.publish'{
                        exchange = <<"topic_logs">>,
                        routing_key = RoutingKey},
                      #amqp_msg{payload = Message}),
    io:format(" [x] Sent ~p:~p~n", [RoutingKey, Message]),
    ok = amqp_channel:close(Channel),
    ok = amqp_connection:close(Connection),
    ok.

receiver_logs_topic.erl

-module(receive_logs_topic).
-compile([export_all]).

-include_lib("amqp_client/include/amqp_client.hrl").

main(Argv) ->
    {ok, Connection} =
        amqp_connection:start(#amqp_params_network{host = "localhost"}),
    {ok, Channel} = amqp_connection:open_channel(Connection),

    amqp_channel:call(Channel, #'exchange.declare'{exchange = <<"topic_logs">>,
                                                   type = <<"topic">>}),

    #'queue.declare_ok'{queue = Queue} =
        amqp_channel:call(Channel, #'queue.declare'{exclusive = true}),

    [amqp_channel:call(Channel, #'queue.bind'{exchange = <<"topic_logs">>,
                                              routing_key = list_to_binary(BindingKey),
                                              queue = Queue})
     || BindingKey <- Argv],

    io:format(" [*] Waiting for logs. To exit press CTRL+C~n"),

    amqp_channel:subscribe(Channel, #'basic.consume'{queue = Queue,
                                                     no_ack = true}, self()),
    receive
        #'basic.consume_ok'{} -> ok
    end,
    loop(Channel).

loop(Channel) ->
    receive
        {#'basic.deliver'{routing_key = RoutingKey}, #amqp_msg{payload = Body}} ->
            io:format(" [x] ~p:~p~n", [RoutingKey, Body]),
            loop(Channel)
    end.

 接收所有的日志

RabbitMQ erlang "topics"_第3张图片

接收所有来自 facility是 "kern"的日志

RabbitMQ erlang "topics"_第4张图片

接收“critical”日志:

创建多个bindings:

RabbitMQ erlang "topics"_第5张图片

发送一个 “kern.critical”类型 routing key 的日志:

RabbitMQ erlang "topics"_第6张图片

  


你可能感兴趣的:(rabbitmq,erlang)