| .. Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| |
| Indirect Waypoints and Auto-Links |
| ================================= |
| |
| This feature was introduced in Qpid Dispatch 0.6. It is a significant |
| improvement on an earlier somewhat experimental feature called |
| Waypoints. |
| |
| Auto-link is a feature of Qpid Dispatch Router that enables a router |
| to actively attach a link to a node on an external AMQP container. |
| The obvious application for this feature is to route messages through |
| a queue on a broker, but other applications are possible as well. |
| |
| An auto-link manages the lifecycle of one AMQP link. If messages are |
| to be routed to and from a queue on a broker, then two auto-links are |
| needed: one for sending messages to the queue and another for |
| receiving messages from the queue. The container to which an |
| auto-link attempts to attach may be identified in one of two ways: |
| |
| - The name of the connector/listener that resulted in the connection |
| of the container, or |
| - The AMQP container-id of the remote container. |
| |
| Queue Waypoint Example |
| ---------------------- |
| |
| Here is an example configuration for routing messages deliveries |
| through a pair of queues on a broker: |
| |
| :: |
| |
| connector { |
| name: broker |
| role: route-container |
| addr: <hostname> |
| port: <port> |
| sasl-mechanisms: ANONYMOUS |
| } |
| |
| address { |
| prefix: queue |
| waypoint: yes |
| } |
| |
| autoLink { |
| addr: queue.first |
| dir: in |
| connection: broker |
| } |
| |
| autoLink { |
| addr: queue.first |
| dir: out |
| connection: broker |
| } |
| |
| autoLink { |
| addr: queue.second |
| dir: in |
| connection: broker |
| } |
| |
| autoLink { |
| addr: queue.second |
| dir: out |
| connection: broker |
| } |
| |
| The *address* entity identifies a namespace (queue.*) that will be |
| used for routing messages through queues via autolinks. The four |
| *autoLink* entities identify the head and tail of two queues on the |
| broker that will be connected via auto-links. |
| |
| If there is no broker connected, the auto-links shall remain |
| *inactive*. This can be observed by using the *qdstat* tool: |
| |
| :: |
| |
| $ qdstat --autolinks |
| AutoLinks |
| addr dir phase link status lastErr |
| =================================================== |
| queue.first in 1 inactive |
| queue.first out 0 inactive |
| queue.second in 1 inactive |
| queue.second out 0 inactive |
| |
| If a broker comes online with a queue called *queue.first*, the |
| auto-links will attempt to activate: |
| |
| :: |
| |
| $ qdstat --autolinks |
| AutoLinks |
| addr dir phase link status lastErr |
| ====================================================================== |
| queue.first in 1 6 active |
| queue.first out 0 7 active |
| queue.second in 1 failed Node not found: queue.second |
| queue.second out 0 failed Node not found: queue.second |
| |
| Note that two of the auto-links are in *failed* state because the |
| queue does not exist on the broker. |
| |
| If we now use the Qpid Proton example application *simple_send* to |
| send three messages to queue.first via the router: |
| |
| :: |
| |
| $ python simple_send.py -a 127.0.0.1/queue.first -m3 |
| all messages confirmed |
| |
| and then look at the address statistics on the router: |
| |
| :: |
| |
| $ qdstat -a |
| Router Addresses |
| class addr phs distrib in-proc local remote cntnr in out thru to-proc from-proc |
| ======================================================================================================== |
| mobile queue.first 1 balanced 0 0 0 0 0 0 0 0 0 |
| mobile queue.first 0 balanced 0 1 0 0 3 3 0 0 0 |
| |
| we see that *queue.first* appears twice in the list of addresses. The |
| *phs*, or phase column shows that there are two phases for the |
| address. Phase '0' is for routing message deliveries from producers |
| to the tail of the queue (the *out* auto-link associated with the |
| queue). Phase '1' is for routing deliveries from the head of the |
| queue to subscribed consumers. |
| |
| Note that three deliveries have been counted in the "in" and "out" |
| columns for phase '0'. The "in" column represents the three messages |
| that arrived from simple_send and the "out" column represents the |
| three deliveries to the queue on the broker. |
| |
| If we now use *simple_recv* to receive three messages from this |
| address: |
| |
| :: |
| |
| $ python simple_recv_noignore.py -a 127.0.0.1:5672/queue.first -m3 |
| {u'sequence': int32(1)} |
| {u'sequence': int32(2)} |
| {u'sequence': int32(3)} |
| |
| We receive the three queued messages. Looking at the addresses again, |
| we see that phase '1' was used to deliver those messages from the |
| queue to the consumer. |
| |
| :: |
| |
| $ qdstat -a |
| Router Addresses |
| class addr phs distrib in-proc local remote cntnr in out thru to-proc from-proc |
| ======================================================================================================== |
| mobile queue.first 1 balanced 0 0 0 0 3 3 0 0 0 |
| mobile queue.first 0 balanced 0 1 0 0 3 3 0 0 0 |
| |
| Note that even in a multi-router network, and with multiple producers |
| and consumers for *queue.first*, all deliveries will be routed through |
| the queue on the connected broker. |
| |
| Sharded Queue Example |
| --------------------- |
| |
| Here is an extension of the above example to illustrate how Qpid |
| Dispatch Router can be used to create a distributed queue in which |
| multiple brokers share the message-queueing load. |
| |
| :: |
| |
| connector { |
| name: broker1 |
| role: route-container |
| addr: <hostname> |
| port: <port> |
| sasl-mechanisms: ANONYMOUS |
| } |
| |
| connector { |
| name: broker2 |
| role: route-container |
| addr: <hostname> |
| port: <port> |
| sasl-mechanisms: ANONYMOUS |
| } |
| |
| address { |
| prefix: queue |
| waypoint: yes |
| } |
| |
| autoLink { |
| addr: queue.first |
| dir: in |
| connection: broker1 |
| } |
| |
| autoLink { |
| addr: queue.first |
| dir: out |
| connection: broker1 |
| } |
| |
| autoLink { |
| addr: queue.first |
| dir: in |
| connection: broker2 |
| } |
| |
| autoLink { |
| addr: queue.first |
| dir: out |
| connection: broker2 |
| } |
| |
| In the above configuration, there are two instances of *queue.first* |
| on brokers 1 and 2. Message traffic from producers to address |
| *queue.first* shall be balanced between the two instance and messages |
| from the queues shall be balanced across the collection of subscribers |
| to the same address. |
| |
| Dynamically Adding Shards |
| ------------------------- |
| |
| Since configurable entities in the router can also be accessed via the |
| management protocol, we can remotely add a shard to the above example |
| using *qdmanage*: |
| |
| :: |
| |
| qdmanage create --type org.apache.qpid.dispatch.connector addr=<host> port=<port> name=broker3 |
| qdmanage create --type org.apache.qpid.dispatch.router.config.autoLink addr=queue.first dir=in connection=broker3 |
| qdmanage create --type org.apache.qpid.dispatch.router.config.autoLink addr=queue.first dir=out connection=broker3 |
| |