NMS.ActiveMQ 虛擬目的地
虛擬目的地 允許我們建立邏輯目的地,客戶端可以使用這些目的地來生產和消費訊息,但這些目的地會對應到一個或多個實體目的地。這讓我們可以提供更具彈性的鬆散耦合訊息傳遞組態。
虛擬主題
發布訂閱背後的想法非常棒。讓生產者與消費者解耦,讓他們甚至不知道有多少消費者對他們發布的訊息感興趣。JMS 規範定義了對持久主題的支援,但正如我們將描述的,它們存在限制……
JMS 持久主題的限制
一個 JMS 持久訂閱者的 MessageConsumer 是以唯一的 JMS clientID 和持久訂閱者名稱建立的。為了符合 JMS 規範,在任何時間點,一個 JMS clientID 只能有一個 JMS 連線是活動的,並且一個 clientID 和訂閱者名稱只能有一個消費者是活動的。也就是說,只有一個執行緒可以主動從給定的邏輯主題訂閱中消費。這表示我們無法實現
- 訊息的負載平衡。
- 如果執行該消費者執行緒的單一進程死掉,則訂閱者快速故障轉移。
現在,JMS 中的 佇列 語義提供了在多個消費者之間以可靠方式平衡工作負載的能力 - 允許使用許多執行緒、進程和機器來處理訊息。然後我們有了複雜的黏性負載平衡技術,例如 訊息群組,可以在保持順序的同時平衡負載和並行化工作。
為每個邏輯主題訂閱者設置實體佇列的另一個額外好處是,我們可以透過 JMX 監控佇列深度,以監控系統效能,並能夠瀏覽這些實體佇列。
虛擬主題來救援
虛擬主題背後的想法是,生產者以通常的 JMS 方式發送到主題。消費者可以繼續使用 JMS 規範中的主題語義。然而,如果主題是虛擬的,消費者可以從邏輯主題訂閱的實體佇列中消費,允許許多消費者在許多機器和執行緒上執行,以平衡負載。
例如,假設我們有一個名為 VirtualTopic.Orders
的主題。(其中前綴 VirtualTopic. 表示它是一個虛擬主題)。我們邏輯上希望將訂單發送到系統 A 和 B。現在,使用常規的持久主題,我們將為 clientID_A 和「A」以及 clientID_B 和「B」建立 JMS 消費者。
使用虛擬主題,我們可以立即消費到佇列 Consumer.A.VirtualTopic.Orders
,以成為系統 A 的消費者,或消費到 Consumer.B.VirtualTopic.Orders
,以成為系統 B 的消費者。
現在,我們可以為每個系統擁有一個消費者池,然後它們會爭奪系統 A 或 B 的訊息,以便系統 A 的所有訊息都被精確處理一次,系統 B 也是如此。
自訂預設值
預設值如上所述。也就是說,可用的唯一虛擬主題必須位於 VirtualTopic.>
命名空間內,且消費者佇列名為 Consumer.*.VirtualTopic.>
。
您可以設定這個來使用您想要的任何命名慣例。以下 範例 顯示如何使所有主題成為虛擬主題。下面的範例使用名稱 >
來表示「符合所有主題」。您可以使用此萬用字元在不同的層次結構中應用不同的虛擬主題原則。
<destinationInterceptors>
<virtualDestinationInterceptor>
<virtualDestinations>
<virtualTopic name=">" prefix="VirtualTopicConsumers.*." selectorAware="false"/>
</virtualDestinations>
</virtualDestinationInterceptor>
</destinationInterceptors>
請注意,使主題虛擬化會在發送訊息到主題時增加少量 CPU 負擔,但它相當小。
選項 | 預設值 | 說明 |
---|---|---|
selectorAware | false | 只有符合現有訂閱者的訊息才會實際被派送。當獨佔消費者使用選擇器時,使用此選項可防止累積未匹配的訊息 |
local | false | 當為 true 時,不要散播透過網路接收的訊息 |
concurrentSend | false | 當為 true 時,使用執行器進行散播,以便並行發生發送。這允許日誌批次寫入,這將減少磁碟 I/O (5.12) |
transactedSend | false | 當為 true 時,為散播發送使用交易,以便進行單一磁碟同步。如果沒有用戶端交易,則會建立本地代理交易 (5.13) |
複合目的地
複合目的地允許在個別目的地上一對多的關係;主要的使用案例是複合佇列。例如,當訊息發送到佇列 A 時,您可能還希望將其轉發到佇列 B 和 C 以及主題 D。然後,複合目的地是從虛擬目的地到其他實體目的地的集合的映射。在這種情況下,映射是在代理端進行的,而用戶端並不知道目的地之間的映射。這與用戶端 複合目的地 不同,後者用戶端使用 URL 標記法來指定必須將訊息發送到的實際實體目的地。
以下 範例 顯示如何在 XML 組態中設定 <compositeQueue/>
元素,以便當訊息發送到 MY.QUEUE
時,它實際上會被轉發到實體佇列 FOO
和主題 BAR
。
<destinationInterceptors>
<virtualDestinationInterceptor>
<virtualDestinations>
<compositeQueue name="MY.QUEUE">
<forwardTo>
<queue physicalName="FOO" />
<topic physicalName="BAR" />
</forwardTo>
</compositeQueue>
</virtualDestinations>
</virtualDestinationInterceptor>
</destinationInterceptors>
預設情況下,訂閱者無法直接從複合佇列或主題消費訊息 - 它只是一個邏輯結構。考慮到上述設定,訂閱者只能從 FOO
和 BAR
消費訊息;但不能從 MY.QUEUE
消費。
可以變更此行為以實現諸如透過將相同訊息發送到通知主題 (竊聽) 來監看佇列之類的使用案例,方法是將可選設定的 forwardOnly
屬性設定為 false。
<compositeQueue name="IncomingOrders" forwardOnly="false">
<forwardTo>
<topic physicalName="Notifications" />
</forwardTo>
</compositeQueue>
發送到 IncomingOrders
的訊息都將被複製並轉發到 Notifications
,然後再放置在實體 IncomingOrders
佇列上,供訂閱者消費。
當 forwardOnly
屬性未定義或設定為 true
時,compositeQueue
和 compositeTopic
之間沒有邏輯差異 - 它們可以互換使用。只有在透過使用 forwardOnly
使複合目的地成為實體時,選擇 compositeTopic
/compositeQueue
才會影響行為。
使用篩選的目的地
從 Apache ActiveMQ 4.2 開始,您現在可以使用選擇器來定義虛擬目的地。
您可能希望建立一個虛擬目的地,該目的地將訊息轉發到多個目的地,但首先應用選擇器來決定訊息是否真的必須傳送到特定目的地。
以下範例顯示,如果選擇器符合,則發送到虛擬目的地 MY.QUEUE
的訊息將會轉發到 FOO
和 BAR
<destinationInterceptors>
<virtualDestinationInterceptor>
<virtualDestinations>
<compositeQueue name="MY.QUEUE">
<forwardTo>
<filteredDestination selector="odd = 'yes'" queue="FOO"/>
<filteredDestination selector="i = 5" topic="BAR"/>
</forwardTo>
</compositeQueue>
</virtualDestinations>
</virtualDestinationInterceptor>
</destinationInterceptors>
避免經紀人網路中的重複訊息
您必須確保當您同時使用基於佇列和非基於佇列的訂閱者到虛擬主題時 (也就是說,如果您有正常的主題訂閱者到虛擬主題),發送到 Consumer.*.VirtualTopic.>
目標的訊息不會被轉發。如果您在經紀人網路中使用虛擬主題,則如果您使用預設網路組態,則可能會收到重複的訊息。這是因為網路節點不僅會轉發發送到虛擬主題的訊息,還會轉發關聯的實體佇列。若要修正此問題,您應該停用轉發關聯實體佇列上的訊息。
以下是如何執行此操作的範例
<networkConnectors>
<networkConnector uri="static://(tcp://127.0.0.1:61617)">
<excludedDestinations>
<queue physicalName="Consumer.*.VirtualTopic.>"/>
</excludedDestinations>
</networkConnector>
</networkConnectors>