ActiveMQ 5 Cluster 之 Networks of Brokers

原文:http://activemq.apache.org/networks-of-brokers
要提升消息系统巨大的弹性能力,典型的做法是在一个网络内把很多brokers连到一起,这样你想要多少就可以让多少clients逻辑上连在一起 - 并且根据客户端数量和网络拓扑你需要运行多少broker就可以运行多少broker。

如果你使用 client/server or hub/spoke style topology (客户端/服务器 or 总线/星形 拓扑),那么你连接的 broker 将成为一个故障单点。这也是我们需要 network of brokers的原因,这样我们可以承受任何特定broker,machine,subnet的故障而不受影响。

ActiveMQ 从 1.1 起支持 networks of brokers ,允许我们支持分布于network of brokers的distributed queues and topics (分布式队列和主题)。

这允许 client 连接 network 内的任意一台 broker - 并在在故障的情况下 fail over 到另外一台 - 从clients的角度提供broker HA 集群。

注意 默认网络连接是唯一的方式 - broker 和 与之相连的brokers 建立网络连接发送消息。从 version 5.x 起,网络连接可以被开启为duplex(双工网络术语)模式,用于 hub and spoke architectures(总线/星形拓扑), hub 位于防火墙后。

Configuring a network of brokers

最简单配置 network of brokers 的方式是通过 Xml Configuration。有两种主要方法创建:

  • networkConnector 元素内列出固定清单

  • 使用 Discovery 功能来侦测发现 brokers (广播 or rendezvous)

Example with a fixed list of URIs

如下是使用固定URIs清单的范例:





    
    
      
    

    
      
    

   
      
    
  



ActiveMQ 也支持除tcp外的其他transports来用于network connector,比如http。

Example using multicast discovery

使用广播 multicast discovery 的范例:





    
    
      
    

    
      
    

  
      
    
  



Starting network connectors

默认,network connectors按顺序初始化,作为 broker 启动序列的一环。 当有些网络慢了,它们也会阻止其他网络的及时启动。Version 5.5 supports 支持 broker 属性networkConnectorStartAsync=”true”,可以在broker启动过程中让broker使用executor以并行和异步的方式启动 network connectors。

Static discovery

static: discovery 将broker URLs列在固定清单中。每个broker都创建如下的network connector:


  


如下是设置static network connector的一些有用配置项:

property default description
initialReconnectDelay 1000 第一次重连前的等待时间(ms) ,如果useExponentialBackOff设为false
maxReconnectDelay 30000 两次重连之间的最大间隔时间(ms)
useExponentialBackOff true 重连时间间隔是否以指数形式增长
backOffMultiplier 2 使用 exponential back off 所配置的指数值

范例:

uri="static:(tcp://host1:61616,tcp://host2:61616)?maxReconnectDelay=5000&useExponentialBackOff=false"

MasterSlave Discovery

network of brokers的一个通用配置项是,在master和slave brokers之间建立网桥连接。典型的配置包括failover: transport,但是还有一些其他特殊配置。因此,ActiveMQ v5.6+ 设计了简单的发现方法配置 masterslave: transport :


  


URIs 清单的顺序: MASTER,SLAVE1,SLAVE2…SLAVE?

static: 使用的配置选项也适用于 masterslave:

NetworkConnector Properties

property default description
name bridge name of the network - for more than one network connector between the same two brokers - use different names
dynamicOnly false if true, only activate a networked durable subscription when a corresponding durable subscription reactivates, by default they are activated on startup.
decreaseNetworkConsumerPriority false if true, starting at priority -5, decrease the priority for dispatching to a network Queue consumer the further away it is (in network hops) from the producer. When false all network consumers use same default priority(0) as local consumers
networkTTL 1 the number of brokers in the network that messages and subscriptions can pass through (sets both message&consumer -TTL)
messageTTL 1 (version 5.9) the number of brokers in the network that messages can pass through
consumerTTL 1 (version 5.9) the number of brokers in the network that subscriptions can pass through (keep to 1 in a mesh)
conduitSubscriptions true multiple consumers subscribing to the same destination are treated as one consumer by the network
excludedDestinations empty destinations matching this list won’t be forwarded across the network (this only applies to dynamicallyIncludedDestinations)
dynamicallyIncludedDestinations empty destinations that match this list will be forwarded across the network n.b. an empty list means all destinations not in the exluded list will be forwarded
useVirtualDestSubs false if true, the network connection will listen to advisory messages for virtual destination consumers
staticallyIncludedDestinations empty destinations that match will always be passed across the network - even if no consumers have ever registered an interest
duplex false if true, a network connection will be used to both produce AND Consume messages. This is useful for hub and spoke scenarios when the hub is behind a firewall etc.
prefetchSize 1000 Sets the prefetch size on the network connector’s consumer. It must be > 0 because network consumers do not poll for messages
suppressDuplicateQueueSubscriptions false (from 5.3) if true, duplicate subscriptions in the network that arise from network intermediaries will be suppressed. For example, given brokers A,B and C, networked via multicast discovery. A consumer on A will give rise to a networked consumer on B and C. In addition, C will network to B (based on the network consumer from A) and B will network to C. When true, the network bridges between C and B (being duplicates of their existing network subscriptions to A) will be suppressed. Reducing the routing choices in this way provides determinism when producers or consumers migrate across the network as the potential for dead routes (stuck messages) are eliminated. networkTTL needs to match or exceed the broker count to require this intervention.
bridgeTempDestinations true Whether to broadcast advisory messages for created temp destinations in the network of brokers or not. Temp destinations are typically created for request-reply messages. Broadcasting the information about temp destinations is turned on by default so that consumers of a request-reply message can be connected to another broker in the network and still send back the reply on the temporary destination specified in the JMSReplyTo header. In an application scenario where most/all messages use request-reply pattern, this will generate additional traffic on the broker network as every message typically sets a unique JMSReplyTo address (which causes a new temp destination to be created and broadcasted via an advisory message in the network of brokers). When disabling this feature such network traffic can be reduced but then producer and consumers of a request-reply message need to be connected to the same broker. Remote consumers (i.e. connected via another broker in your network) won’t be able to send the reply message but instead raise a “temp destination does not exist” exception.
alwaysSyncSend false (version 5.6) When true, non persistent messages are sent to the remote broker using request/reply in place of a oneway. This setting treats both persistent and non-persistent messages the same.
staticBridge false (version 5.6) If set to true, broker will not dynamically respond to new consumers. It will only use staticallyIncludedDestinations to create demand subscriptions
userName null The username to authenticate against the remote broker
password null The password for the username to authenticate against the remote broker

Reliability

Networks of brokers 实现了可靠的存储和消息转发。如果源是可持久化的,队列中持久化的消息 或 持久化的主题订阅,那么network 任然会保留持久化。
但是,如果源是非持久化的,networks就不能添加持久化属性。非持久化的主题订阅和缓存目的地(both queues and topics) 定义都是非持久化。 当非持久化的源实现network后,故障发生时,没有落地的消息会丢失。

参考:
ActiveMQ中的 消息持久化和非持久化,以及持久订阅和非持久订阅
Message Durability 和 Message Persistence的区别
Durable Subscribers and NonDurable Subscribers
ActiveMQ支持两种传输模式:持久传输和非持久传输(persistent and non-persistent delivery),默认情况下使用的是持久传输。

Ordering

消息的排序并不保存在networks of brokers内。Total ordering 仅在单消费者时有效 ,但是networkBridge总是会邀请第二个消费者。另外,network bridge consumers 通过producer.send(..)转发消息,所以他们总是将forwarding broker队列的最上面的消息发送到目的broker队列的最下面。如果是单个消费者在networked brokers之间漂移,并且所有的小心总是跟随这个消费者,total order或许可以被保留下来,但是也非常难保证大量消息堆积时有效。

参考:
arrival (no) order, total order, causal order
total order = every process receives all messages in the same order (including its own) every process receives all messages in the same order (including its own).

When to use and not use Conduit subscriptions

自译:翻译为 管道订阅? 把好多订阅绑一起像个管子,当作单个订阅对待?

ActiveMQ 依赖于活动消费者(订阅)在network之间传递消息的信息。Broker会像处理本地连接客户端的订阅那样来处理remote(networked) broker的订阅,并且将相关的消息副本路由到每个订阅。 对于主题订阅和超过一个远程订阅,remote broker 会把每个消息副本都作为合法处理,所以当它把消息路由到它自己的本地连接,多重记录就出现了。因此,默认conduit 行为将所有的匹配订阅信息都聚合在一起来避免网络内的多重记录。该默认行为,将remote broker上的N个订阅都识别为网络内的单个订阅。

如果你只使用队列,duplicate subscriptions是一个值得开发的有用特性。因为负载均衡的逻辑是平滑的分布消息负载,如果设置flag conduitSubscriptions=false,那么network内的消费者会平等的共享消息负载。范例:假设有两个brokers, A and B,通过 forwarding bridge互联。 连到broker A, 有一个消费者,订阅了Q.TEST。连到broker B, 有两个消费者,也订阅了Q.TEST。所有的消费者优先级相同。然后在broker A上启动一个生产者,写入30条消息到Q.TEST。默认, (conduitSubscriptions=true), 15条消息会被发送到broker A的消费者,另外15条消息会被发送到broker B上的两个消费者。这样消息就没有在所有的消费者上平均负载,默认,broker A 视 broker B 上的两个订阅为一个。如果你设置 conduitSubscriptions to false, 那么这三个消费者都会收到10条消息。

Duplex network connectors

默认的,一个 network bridge 在单个连接上根据需要向一个方向转发消息。当设置duplex=true, 该bridge上同样的连接还能用于相反方向,这样就成了一个双向的bridge。network bridge的配置会传播到其他brokers,所以duplex bridge is an exact replica or the original.

假设两个brokers, broker A and broker B,配置A to B的双工桥(duplex bridge),等同于一个A to B的默认桥(default bridge) 和一个B to A的默认桥。

注意,如果你想在两个brokers之间配置不止一个 duplex network bridge,来提升带宽或分区主题和队列,你必须为每个提供唯一的名字:


        
                
                        
                
        
        
                
                        
                
        
  

Conduit subscriptions and consumer selectors

Conduit subscriptions 忽视本地broker上的 consumer selectors ,并发送所有的消息给远程broker。Selectors在消息发送给消费者前,会在 remote brokers 上解析消息。在多broker的network中,这个特性会在消费使用selector的队列的时候带来问题。
设想一下,当你在生产者broker上发送消息给两个接收brokers,这两个broker各自有一个配置了不同selector的消费者。既然在生产者broker那端没有配置任何selector的信息,那么会导致所有的消息仅发送到一台broker上,这样一些配置特定属性的消息就没有办法被消费。
如果你需要支持这个用法,请关闭 conduitSubscription 功能。

Configuration Pitfalls (配置陷阱)

如果 advisorySupport broker property 设置为 disabled,networks不会像我们设想的那样去工作(它们不会动态的答复新消费者)。如果advisorySupport设置为disabled,network只能全静态配置。下面进行了更多描述。

Networks of brokers and advisories

Network of brokers 严重依赖于advisory messages(公告消息),因为它们工作在底层来处理远端的新增消费者的相关信息。默认的,当network connector启动,它会在下面的主题ActiveMQ.Advisory.Consumer.>下定义一个消费者 (暂且忽略缓存目的对象)。这样,当消费者连接(或断开)remote broker, local broker将会收到消息,并将之待为一个消费者处理。

对于少量目的对象、消费者的小型networks和环境,这是很好的。但是当一切开始增长,默认的模型 (listen to everything, share everything) 不能很好的扩展。那就是为什么你有很多种方式可以过滤目的对象(brokers 共享)的原因。

Dynamic networks

动态配置的networks。意思是,我们只需要当remote broker有消费者的时候,发送消息到remote broker。 如果我们要限制在特定的目的对象上,我们需要设置dynamicallyIncludedDestinations,比如:


  
    
    
  


在ActiveMQ 5.6之前,broker 使用同样的 advisory filter ,并且获取remote broker上所有的消费者信息。匹配过滤过程在消息发送过程中完成。在大型的networks中,这不是最优解决方案,因为它在brokers产生了大量的流量和负载。自动版本 5.6,broker会自从创建合适的 advisory filter ,仅采集动态包含在内的目的对象(dynamically included destinations)。比如:
ActiveMQ.Advisory.Consumer.Queue.include.test.foo,ActiveMQ.Advisory.Consumer.Topic.include.test.bar”.
这可以显著的提升在复杂和高负载环境的反应(behavior )。

在老版本, 我们可以用稍复杂的配置来实现同样的东西。我们感兴趣的消费者上的advisory filter 是由tdestinationFilter connector 属性定义的。默认值是“>”,以 "ActiveMQ.Advisory.Consumer." 作为前缀。所以要达到同样的痛惜,我们需要如下:


  
    
    
  


注意,第一个 destination 没有前缀,因为它已经隐含了。 设置和维护略有一点复杂,但是我们可以的。如果你使用了5.6或以上版本的broker,只用 dynamicallyIncludedDestinations包含了希望的目的对象,也是可以的。

这也解释了为什么关闭brokers的advisory support ,dynamic networks就不工作了。在这种情况下,brokers不能动态的响应新加入的消费者。

Pure static networks

如果你希望完全避免收到remote broker的消费者的影响,或者你希望将brokers作为简单代理并转发消息到远端而不管是否有消费者,静态的networks你可以考虑下:


        
            
        


自版本5.6起,我们可以使用staticBridge 参数 。它的意思是,local broker不订阅remote broker上的任何advisory topics ,或者说它不关心远端是否有消费者。
另外,你需要在 staticallyIncludedDestinations内添加一个目的对象清单。(这在目的对象新增消费者时也有效,所以消息也会被转发到远端。This will have the same effect as having an additional consumer on the destinations so messages will be forwarded to the remote broker as well.)
在ActiveMQ早期的版本中没有 staticBridge 参数,你可以配置 destinationFilter来监听一个没用的 advisory topic,比如


        
            
        


如果配置成这样,broker将会在 ActiveMQ.Advisory.Consumer.NO_DESTINATION监听新消费者, 这样永远没有消息,所以可以隔离远端消费者的消息。

Dynamic networks and Virtual Destinations (New for 5.13.0)

正如上面描述的,一个network of brokers可以配置为仅发送消息给一个remote broker,当被包含的目的对象有消费者的时候。 那么, 当使用 Virtual Destinations 的时候,dynamic如何处理呢。

Virtual Destination consumers and Composite Destinations

这里有两个brokers 组成network 的范例。 Local Broker设置了network connector参数 dynamicallyIncludedDestination,Remote Broker 设置了CompositeTopic:

Local Broker


    
        
    


Remote Broker


    
        
    


在这个范例中,我们假设Remote Broker 的队列include.bar.forward有单个消费者。 如果一条消息被直接发送给Remote Broker 的 topic include.bar,它会被转发给队列 include.bar.forward,然后消费者会接收到该消息。但是,如果消息被发送到 Local Broker 上同样的topic,这条消息将不会转发给Remote Broker。

消息不会被转发的原因是,queue include.bar.forward上的消费者没有被Local Broker识别为dynamicallyIncludedDestinations清单中的一部分。消息不会被转发给Remote Broker,除非在源topic上也有一个消费者 (本例 include.bar)。这可以通过配置 Local Broker 监听 Virtual Destination Subscriptions固定下来。

首先,我们需要配置当消费者订阅一个匹配Virtual Destination的destination的时候,Remote Broker 发送advisory messages 。这样,会通过Destination Filter来做一个内部匹配来决定one destination 是否转发到 another destination。在 Remote Broker 设置 property useVirtualDestSubstrue 来开启:

Remote Broker





    
     .....
  



然后,Local Broker 上的 network connector设置 useVirtualDestSubstrue,来监听 new advisory messages:

Local Broker


  
    
  


现在,如果一个消费者在Remote Broker订阅队列 include.bar.forward ,Local Broker将会转发发送到topic include.bar.的消息。

Virtual Destination Consumers on Destination Creation

现在,我们考虑同样的composite topic但是队列没有消费者的情况。
Remote Broker


    
        
    


在Remote Broker配置了一个Composite Topic,并且配置Local Broker组网。

即使我们开启了 useVirtualDestSubs,消息仍然没有转发给Remote Broker ,除非一个消费者订阅了转发的这个队列。如果没有消费者,当消息被发送到Local Broker的topic(include.bar)的时候会被丢失 。在这种情况下,期望实现基于virtual destination存在的转发:

  • one or more queues; or
  • topics that have durable subscriptions.

这些情况都是考虑了Local Broker消息发送的情况,即使在那些destinations没有存活的消费者。

Remote Broker





    
     .....
  



在该配置下,当队列include.bar.forward被创建,一个Virtual Destination consumer advisory将被发送给Local Broker,这样它就知道基于Composite Topic的存在转发消息了。

Composite Destination consumers and Virtual Topics

以上的范例介绍了怎么配置 Composite Destination,但是Virtual Topic也是可以的。 下面的范例,在Remote Broker 上的一个消费者,位于Virtual Topic的队列,产生需求;然后 Local Broker通过network发送消息。

Local Broker


  
    
  


Remote Broker





    
     .....
  



Example Configuration using NetworkConnector properties

这是Broker的范例中的部分:


      
        
            
            
        
        
            
            
        
        
            
            
        
      
    

注意,在这里excludedDestinations 属性不影响 staticallyIncludedDestinations

在两个brokers之间可以有不止一个network connector。每个network connector都会占用一个底层的传输通道(connection),所以你可以从这个角度来提升吞吐带宽,或实现更灵活的配置。

比如,如果使用分布式队列,你希望receivers有着同样的权重,当且仅当receivers处于active状态的时候。
范例:


      
        
            
        
      
    

注意excludedDestinationsdynamicallyIncludedDestinations 属性内,你只能配置使用 wildcards 。
注意 不要 改变Broker内配置的bridge名字,如果你使用了持久主题订阅。 内部 ActiveMQ 使用 network name 和 broker name 来构建一个唯一的、可持续的持久订阅。

Stuck Messages (version 5.6)

默认,禁止将消息回传给发过来的broker。这可以确保在配置 duplex or by directional network connectors的时候,消息不会成环(loop)。有的时候,也有回传的需求。假设一个场景,在一对broker间存在一个双向桥。生产者和消费者使用failover transport随机的选择一个broker。如果一个broker因为维护而重启了,消息会堆积在那个broker上, 将不能被消费者使用直到消费者重连broker成功。解决该问题的一个方案是,强制客户端使用 rebalanceClusterClients重连;另外一个是,允许消息在那个broker上没有消费者的时候回传给源。
有一条destination policy允许这种操作,通过在 conditionalNetworkBridgeFilterFactory 内配置replayWhenNoConsumers=trueconditionalNetworkBridgeFilterFactory 基于broker-in time提供可选的 replayDelay 配置项。

    
      
        
          
            
              
            
          
        
      
    

注意: 在<5.9版本使用replayWhenNoConsumers=true ,非常有必要设置enableAudit=false来disable the cursors duplicate detection,因为the cursor could mark the replayed messages as duplicates (取决于在network bridge 上 playing and replaying这些消息的时间窗)。这个问题阐述在blog post.

Throttling a network consumer

(实在看不懂)

The conditionalNetworkBridgeFilterFactory factory allows a rate limit to be specified for a destination, such that network consumer can be throttled. Prefetch for a network consumer is largely negated by the fact that a network consumer relays a message typically acks very quickly so even with a low prefetch and decreased priority a network consumer can starve a modestly quick local consumer. Throttling provides a remedy for this.

你可能感兴趣的:(ActiveMQ 5 Cluster 之 Networks of Brokers)