ActiveMQ中的NetworkConnector(網絡連接器)詳解

       注:本文以ActiveMQ5.10版本爲基礎。

       我們知道,ActiveMQ中的TransportConnector(傳輸連接器)主要用於配置ActiveMQ服務端和客戶端之間的通信方式,NetworkConnector(網絡連接器)則主要用來配置ActiveMQ服務端與服務端之間的通信。在某些場景,網絡拓撲中我們可能會需要大量的生產者和消費者,也就是說我們會有大量的ActiveMQ客戶端,這樣,我們就需要在網絡環境中有多個MQ服務器,服務器之間是可以透傳消息的,這是,我們就需要用到NetworkConnector,我們先從簡單的分析起,假設我們需要部署兩臺MQ服務器,如下圖:

 

 使用NetworkConnector的簡單場景

 如上圖所示,服務器S1和S2通過NewworkConnector相連,則生產者P1發送消息,消費者C3和C4都可以接收到,而生產者P3發送的消息,消費者C1和C2同樣也可以接收到,要使用NewworkConnector的功能,需要在服務器S1的activemq.xml中的broker節點下添加如下配置(注:10.79.11.172:61617爲S2的地址):

<networkConnectors>     
          <networkConnector uri="
static:(tcp://10.79.11.172:61617)"/>   
</networkConnectors>
如果只是這樣,S1可以將消息發送到S2,即S2對S1來說彷彿就是S1的消費者,但此時通信只是單向的,發送到S2上的的消息是不能發送到S1上的如果要想S1也收到從S2發來的消息,需要在S2的activemq.xml中的broker節點下也添加如下配置(注:10.79.11.171:61617爲S1的地址):
<networkConnectors>     
          <networkConnector uri="
static:(tcp://10.79.11.171:61617)"/>   
</networkConnectors>
這樣,S1和S2就可以雙向通信了。這時,我們可以訪問S1和S2的控制檯頁面(S1默認是http://10.79.11.171:8161)中的“Network”來看橋接的結果。如果有多個,可以用逗號隔開,如下:
<networkConnectors>     
          <networkConnector uri="
static:(tcp://10.79.11.171:61617,tcp://10.79.11.173:61617,tcp://10.79.11.174:61617)"/>   
</networkConnectors>
       靜態連接器有一些常用的屬性,如下:
【initialReconnectDelay】默認值1000,每次重連的間隔時間,單位爲毫秒,當然得useExponentialBackOff=false纔有效。
maxReconnectDelay】:默認值30000,最大重連間隔,單位爲毫秒。
useExponentialBackOff】:默認值爲true,是否不斷增加重連時間間隔。
backOffMultiplier】:默認值爲2,使用useExponentialBackOff特性的次數。
例如:uri="static:(tcp://host1:61616,tcp://host2:61616)?maxReconnectDelay=5000&useExponentialBackOff=false"
       有人會想,如果只有兩三臺MQ服務器,我們可以像上面那樣簡單配置,如果MQ服務器非常多,我們就不太可能在每個MQ服務器的xml文件中去一個個配置其它服務器地址了,所以,我們希望MQ服務器能在自己的網絡中發現其他的MQ服務器並自動建立“橋接”,幸運的是,ActiveMQ提供了多播發現(Multicast Discovery)的功能,我們可以在每臺MQ服務器的activemq.xml中的broker節點下添加如下配置:
<networkConnectors>      
       <networkConnector uri="
multicast://default"/>   
</networkConnectors>
這樣,這些在網絡中的MQ服務器,在啓動和運行中,將不斷的發現其他新的MQ服務器了,並和他們創建連接,注意,如果新的MQ服務器中沒有配置networkConnectors,那麼這種連接就是單向的,而不是雙向。
       當然,如果NetworkConnector的功能就只有如此,那本文也就沒有繼續下去的必要了,接下來,讓我們看看NetworkConnector常用的幾個屬性配置。個人認爲,結合源碼看屬性,才能理解的更深刻和貼切,因爲需要通過好幾段話來解釋一個功能,還不如直接給讀者幾行源碼(非程序猿除外)來的深刻。
name:默認值是bridge,這無需過多說明,可以給每個MQ服務器起個屬於自己的名字,看MQ日誌也方便。
dynamicOnly:默認爲false,官方文檔是這樣說的,默認的時候,也就是該值爲false的時候,網絡中的持久化訂閱者是在啓動的時候被激活的,如果改值爲true,則對應的持久化訂閱者被激活時,才激活一個網絡的持久化訂閱者,筆者看了下源碼,調試過,但不瞭解該值配置true或false帶來的實際上的效果是什麼,有興趣的讀者可以去看一下DurableConduitBridge#setupStaticDestinations中的源碼,筆者弄明白後會後續補充的。

decreaseNetworkConsumerPriority:默認值爲false,如果該值爲false,網絡上的消費者和本地的消費者有相同的優先級,就是說一個消息發送到本地的消費者和其他的網絡消費者有相同的概率。如果該值爲true,則其他網絡消費者的優先級從-5開始算起,根據網絡跳數(network hops)來算優先級,當然是越“遠”優先級越低。

 

networkTTL:默認值爲1,該值表示消息或訂閱可以通過的消息提供者(brokers)的數量。拿上圖來說,假設P1向S1發了條消息,另外有個ActiveMQ服務器S3(上圖未畫出)與S2相互橋接,但不直接與S1橋接,因爲該值爲1,即使S3上有該隊列的消費者或主題的訂閱者,但對於S1來說S3這些網絡消費者和訂閱者是不可見的,所以P1發的這條消息就不能被S3上的消費者給消費,如果想要讓S3上的消費者也有機會消費,可以讓S3和S1橋接,或者將S1的networkTTL參數配置爲2.

 

messageTTL:默認爲1,從5.9版本開始有效,表示消息能通過的消息提供者數量,該值可以覆蓋掉networkTTL中對消息通過數量的限制。

 

consumerTTL:默認爲1,從5.9版本開始有效,表示訂閱能通過的消息提供者數量,該值可以覆蓋掉networkTTL中對訂閱通過數量的限制。

 

conduitSubscriptions:默認爲true。該值表示多個消費者訂閱一個相同的目的地是否在網絡上被對待爲一個消費者。以上圖爲例,如果採用默認的分配策略,P1連續發120條消息,結果應該是C1和C2都收到40條,而C3和C4共收到40條(C3和C4平分這40條),爲什麼不是C1、C2、C3和C4都收到大概30條呢?因爲該值爲true,C3和C4對於S1來說只是一個消費者,而不是兩個。注意,如果你的多個網絡提供者中的消費者使用了消息選擇器(selector),你又設置了conduitSubscriptions爲true,則有可能會導致消息不會被髮送到正確的網絡消費者從而消息不被消費,因爲網絡消費者中的消息選擇器對生產者的提供者來說是透明的,所以此種情況下,請將conduitSubscriptions設置爲false。

 

excludedDestinations:默認爲空,用來配置不會在網絡中轉發的目的地(Destination)。

 

dynamicallyIncludedDestinations:默認爲空,用來配置可以在網絡中轉發的目的地,和上面的excludedDestinations的功能相反。例如:

<networkConnector uri="static:(tcp://host)">
  <dynamicallyIncludedDestinations>
    <queue physicalName="queue1"/>
    <topic physicalName="topic1"/>
  </dynamicallyIncludedDestinations>
</networkConnector>

 

staticallyIncludedDestinations:默認爲空,用來配置可以在網絡中轉發的目的地,但它和dynamicallyIncludedDestinations不同的是dynamicallyIncludedDestinations只在對方有該目的地的消費者時纔將消息轉發給對方,staticallyIncludedDestinations則不管對方有沒有該目的地都將消息轉發給對方。

舉例配置如下:

  <networkConnectors>     
   <networkConnector uri="static:(tcp://0.0.0.0:61616,tcp://0.0.0.0:61618)" >
    <staticallyIncludedDestinations>
     <queue physicalName="TopicTestQueue1"/>
    </staticallyIncludedDestinations>
   </networkConnector>
  </networkConnectors>

 

duplex:默認值爲false,默認情況下,在兩個提供者之間的連接上的消息流動方向是單向(單工連接),如果該值設置爲true,則一個連接上可以雙向流動消息(雙工連接)。可以想象,單工連接比雙工連接吞吐量要高,但增加了連接數量方面的開銷。如果在使用雙工連接時爲了增加吞吐量,可以建立多個雙工連接,但每個連接必須起不同的名字,例如:

 <networkConnectors>
        <networkConnector name="SYSTEM1" duplex="true" uri="static:(tcp://10.79.6.56:61616)">
                <dynamicallyIncludedDestinations>
                        <topic physicalName="outgoing.System1" />
                </dynamicallyIncludedDestinations>
        </networkConnector>
        <networkConnector name="SYSTEM2" duplex="true" uri="static:(tcp://10.79.6.56:61616)">
                <dynamicallyIncludedDestinations>
                        <topic physicalName="outgoing.System2"/>
                </dynamicallyIncludedDestinations>
        </networkConnector>
</networkConnectors>

 

prefetchSize:默認是1000,指網絡連接中的消費者的預讀數量,該值必須大於0,因爲網絡消費者不能採用poll來獲取消息(輪詢消息)。

 

suppressDuplicateQueueSubscriptions:(從5.3版本開始有效)默認爲false,如果該參數爲true,會防止提供者之間相互橋接時的隊列重複訂閱的問題,其實該參數爲true和false只是ActiveMQ代碼中的微妙的性能變化,對實際的集羣結果並不會帶來什麼影響。

 

bridgeTempDestinations:默認值爲true,該值用來指定在MQ服務器在網絡中創建臨時目的地(temp destinations)時是否需要廣播公告消息(broadcast advisory messages )。如果設置爲false,表示禁用此功能,則當生產者和消費者不是連接到同一個MQ服務器時,可以減少網絡開銷。

 

alwaysSyncSend:(從5.6版本開始有效)默認爲false,表示是否總是異步發送。默認時,非持久化消息被髮送到遠程的MQ服務器時將採用請求/應答方式而不是oneway方式。此參數對待持久化和非持久化消息相同。

 

staticBridge:(從5.6版本開始有效)默認爲false,如果設置爲true,MQ服務器將不會動態應答新的消費者,也意味着該提供者將對其他遠程提供者的主題不感興趣。當設置爲true是,我們可以使用staticallyIncludedDestinations來創建配置需要訂閱的主題,例如:

<networkConnector uri="static:(tcp://host)" staticBridge="true">
        <staticallyIncludedDestinations>
            <queue physicalName="always.include.queue"/>
        </staticallyIncludedDestinations>
</networkConnector>

 

       消息如果一開始就是持久化的化的或者是被持久訂閱的,則在網絡經紀人中傳播時也會保持這種特性,然而,如果消息一開始就不是持久化的或者不是持久訂閱的,則在網絡的MQ服務器中傳播時也一定不會有這些特性。

       總的消息順序在網絡經紀人中是不保證的,當然,即使不是網絡經紀人,在單個經紀人環境下,有多個消費者時,消息被消費的順序也是不保證的。

       如果你希望提供者不受任何遠程提供者上消費者的影響,或者希望不管遠程提供者上是否有消費者都將所有消息轉發到遠程提供者,那麼你可以考慮使用靜態網絡(static networks)。 

       就如前面你說看到的,如果你想增加吞吐量,或者想採用不同的通信方式(如tcp或者nio),又或者你想採用更靈活的配置,兩個提供者之間可以由多個NetworkConnector相連, 例如,如果使用分佈式隊列(distributed queues),你可能希望在通過網絡對隊列接收者能採用等效加權(equivalent weighting),但只針對活躍的接收者,你可以如下配置:

<networkConnectors>
      <networkConnector uri="static:(tcp://localhost:61617)" name="queues_only" conduitSubscriptions="false"   decreaseNetworkConsumerPriority="false">
        <excludedDestinations>
            <topic physicalName=">"/>
        </excludedDestinations>
      </networkConnector>
</networkConnectors>

這裏你需要注意,你只能在excludedDestinations和dynamicallyIncludedDestinations上使用通配符。 還有,當你使用持久主題訂閱者時,請不要去修改NetworkConnector和提供者的(默認)名字,因爲網絡中的ActiveMQ是通過提供者名字和NetworkConnector名字加上持久訂閱者名字來標誌一個持久訂閱者的。
         一般情況下,在採用網絡提供者時,爲了防止消息在提供者之間重複流動,一個消息是不允許再一次發送到同一個網絡提供者的,但這樣就有一個問題,如果某些消息發送到一個網絡提供者時,該網絡提供者剛好因爲某種原因重啓,導致消息消費失敗,這些消息需要重新發送到該網絡提供者,這樣就矛盾了。有一種解決方案就是強制讓客戶端採用rebalanceClusterClients方式進行重連(http://manzhizhen.iteye.com/blog/2105572 )。再一個,就是讓消息回到原來的地方重新發送,因爲那個網絡提供者已經沒有消費者了。有一種目的地策略(destination policy),它通過配置一個replayWhenNoConsumers=true的conditionalNetworkBridgeFilterFactory來提供了這種行爲,conditionalNetworkBridgeFilterFactory提供了一個可配置的基於提供者時間(broker-in time)的重發延遲(replayDelay ),配置如下:
 <destinationPolicy>
  <policyMap>
    <policyEntries>
      <policyEntry queue="TEST.>" enableAudit="false">
        <networkBridgeFilterFactory>
   <conditionalNetworkBridgeFilterFactory replayWhenNoConsumers="true"/>
        </networkBridgeFilterFactory>
      </policyEntry>
    </policyEntries>
  </policyMap>
</destinationPolicy>
主要,在ActiveMQ5.9之前的版本使用replayWhenNoConsumers="true"需要加enableAudit="false",具體原因請看文章後面提供的官網鏈接,這裏不細說。conditionalNetworkBridgeFilterFactory可以對目的地進行比例限制,可以有效的避免低優先級的網絡消費者餓死本地的快消費者。
本文對網絡連接器的屬性介紹的不是很詳細,官網的文章似乎也有些前後矛盾表述不清的地方,還是等以後有時間分析分析源代碼再來補充吧!

感興趣的童鞋可以去看看官方文檔:http://activemq.apache.org/networks-of-brokers.html

  • 大小: 37.5 KB
發佈了48 篇原創文章 · 獲贊 49 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章