1. 概述

Apache ActiveMQ Artemis 叢集允許將多個 Apache ActiveMQ Artemis 伺服器群組在一起,以分擔訊息處理負載。叢集中的每個作用中節點都是一個作用中的 Apache ActiveMQ Artemis 伺服器,管理其自身的訊息並處理其自身的連線。

叢集由每個節點在其核心設定檔 broker.xml 中宣告*叢集連線*到其他節點來形成。當節點與另一個節點形成叢集連線時,內部會在它和另一個節點之間建立一個*核心橋接*(如 核心橋接 中所述)連線,這是透明地在幕後完成的 - 您不必為每個節點宣告一個明確的橋接。這些叢集連線允許訊息在叢集節點之間流動以平衡負載。

節點可以連接在一起形成多種不同的拓樸叢集,我們將在本章稍後討論一些比較常見的拓樸。

我們還將討論客戶端負載平衡,我們可以在叢集節點之間平衡客戶端連線,並且我們將考慮訊息重新分配,其中 Apache ActiveMQ Artemis 將在節點之間重新分配訊息以避免資源耗盡。

叢集化的另一個重要部分是*伺服器探索*,伺服器可以廣播其連線詳細資訊,以便客戶端或其他伺服器可以用最少的設定來連線它們。

一旦設定了叢集節點,通常只需將該設定複製到其他節點即可產生對稱叢集。但是,複製 Apache ActiveMQ Artemis 檔案時必須小心。不要從一個節點複製 Apache ActiveMQ Artemis *資料*(即 bindingsjournalpaginglarge-messages 目錄)到另一個節點。當節點第一次啟動並初始化其日誌檔案時,它還會將一個特殊的識別碼持久化到 journal 目錄。這個 ID 在叢集中的節點之間 *必須* 是唯一的,否則叢集將無法正確形成。

2. 效能考量

務必注意,雖然叢集化的目標是透過水平擴展來提高整體訊息吞吐量,但它並不是「萬靈丹」。在某些情況下,叢集化實際上可能會*降低*訊息吞吐量,因此在選擇叢集配置時必須小心。以下是一些通用指南

  1. 建立明確具體的效能目標。效能測試和調整通常是困難且繁瑣的活動。小的相對增益會誘使您不斷前進,如果沒有目標,您永遠不會知道何時停止。您需要一個目標來了解「有多好才算夠好」。

  2. 從簡單開始。首先使用單一代理程式對您的使用案例進行基準測試。在某些使用案例中,單一代理程式每秒可以處理*數百萬條*訊息。如果您無法使用單一代理程式達到您的效能目標,則只能轉向叢集配置。只有在有*明確好處*時才增加複雜性。

叢集可以降低整體訊息吞吐量的主要方式是,如果每個節點上沒有足夠的生產者和消費者,導致某些節點上訊息累積,而其他節點上的消費者資源耗盡。叢集具有處理此問題的機制(即訊息負載平衡和重新分配,將在稍後介紹),但您真的不希望代理程式介入並在節點之間移動訊息,除非絕對必要,因為 這會增加延遲

因此,當以效能角度思考時,在選擇叢集配置時必須回答的主要問題是:我是否有足夠的客戶端,以便叢集中的每個節點都有足夠的消費者來接收該節點上產生的所有訊息?如果這個問題的答案是「是」,那麼叢集化實際上可能會提高您的整體訊息吞吐量。如果這個問題的答案是「否」,那麼您可能會從較小的叢集或僅使用單一代理程式獲得更好的效能。

另請記住,連線路由器可能會透過將相關的消費者和生產者分組在同一個節點上來提高叢集的效能。

3. 伺服器探索

伺服器探索是一種伺服器可以將其連線詳細資訊傳播到

  • 訊息客戶端的機制。訊息客戶端希望能夠連線到叢集的伺服器,而無需具體了解叢集中哪些伺服器在任何時候處於運作狀態。

  • 其他伺服器。叢集中的伺服器希望能夠彼此建立叢集連線,而無需事先了解叢集中的所有其他伺服器。

這些資訊,我們稱之為叢集拓樸,實際上是透過正常的 Apache ActiveMQ Artemis 連線傳送給客戶端,並透過叢集連線傳送給其他伺服器。在這種情況下,我們需要一種建立初始第一個連線的方法。這可以使用 UDPJGroups 等動態探索技術來完成,或透過提供初始連接器清單來完成。

3.1. 動態探索

伺服器探索使用 UDP 多播或 JGroups 來廣播伺服器連線設定。

3.1.1. 廣播群組

廣播群組是伺服器透過網路廣播連接器的方式。連接器定義客戶端(或其他伺服器)可以連線到伺服器的方式。有關連接器的更多資訊,請參閱 設定傳輸

廣播群組會取得連接器並在網路上廣播。根據您設定的廣播技術,它會使用 UDP 或 JGroups 來廣播連接器資訊。

廣播群組在伺服器設定檔 broker.xml 中定義。每個 Apache ActiveMQ Artemis 伺服器可以有多個廣播群組。所有廣播群組都必須在 broadcast-groups 元素中定義。

讓我們看一下 broker.xml 中的範例廣播群組,它定義了 UDP 廣播群組

<broadcast-groups>
   <broadcast-group name="my-broadcast-group">
    <local-bind-address>172.16.9.3</local-bind-address>
    <local-bind-port>5432</local-bind-port>
    <group-address>231.7.7.7</group-address>
    <group-port>9876</group-port>
    <broadcast-period>2000</broadcast-period>
    <connector-ref>netty-connector</connector-ref>
   </broadcast-group>
</broadcast-groups>

某些廣播群組參數是可選的,您通常會使用預設值,但為了清楚起見,我們在上面的範例中指定了所有參數。讓我們依次討論每個參數

名稱

屬性。伺服器中的每個廣播群組都必須具有唯一的名稱。

local-bind-address

這是資料包通訊端綁定的本地綁定位址。如果您的伺服器有多個網路介面,您可以透過設定此屬性來指定要用於廣播的介面。如果未指定此屬性,則通訊端將綁定到萬用字元位址,這是由核心選擇的 IP 位址。這是 UDP 特有的屬性。

local-bind-port

如果您想指定資料包通訊端綁定的本地連接埠,可以在此處指定。通常您只需使用預設值 -1,表示應使用匿名連接埠。此參數始終與 local-bind-address 一起指定。這是 UDP 特有的屬性。

group-address

這是將廣播資料的多播位址。它是範圍在 224.0.0.0239.255.255.255(含)之間的 D 類 IP 位址。位址 224.0.0.0 已保留,不可使用。此參數為必要參數。這是 UDP 特有的屬性。

group-port

這是用於廣播的 UDP 連接埠號碼。此參數為必要參數。這是 UDP 特有的屬性。

broadcast-period

這是連續廣播之間的時間間隔(以毫秒為單位)。此參數是可選的,預設值為 2000 毫秒。

connector-ref

這指定將廣播的連接器和可選的備份連接器(有關連接器的更多資訊,請參閱 設定傳輸)。

這是另一個範例廣播群組,它定義了 JGroups 廣播群組

<broadcast-groups>
   <broadcast-group name="my-broadcast-group">
      <broadcast-period>2000</broadcast-period>
      <jgroups-file>test-jgroups-file_ping.xml</jgroups-file>
      <jgroups-channel>activemq_broadcast_channel</jgroups-channel>
      <connector-ref>netty-connector</connector-ref>
   </broadcast-group>
</broadcast-groups>

若要能夠使用 JGroups 進行廣播,必須指定兩個屬性,即 jgroups-filejgroups-channel,詳細說明如下

jgroups-file

屬性。這是 JGroups 設定檔的名稱。它將用於初始化 JGroups 通道。請確保檔案位於 Java 資源路徑中,以便 Apache ActiveMQ Artemis 可以載入它。檔案的典型位置是代理程式執行個體的 etc 目錄。

jgroups-channel

屬性。JGroups 通道連線進行廣播的名稱。

上述 JGroups 屬性(jgroups-filejgroups-channel)和 UDP 特定屬性是互斥的。在廣播群組設定中只能指定一組。不要混合使用它們!

以下是 JGroups 檔案的範例

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="urn:org:jgroups"
        xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd">
  <TCP bind_addr="${jgroups.bind_addr:site_local}"
       bind_port="${jgroups.bind_port:7800}"
       external_addr="${jgroups.external_addr}"
       external_port="${jgroups.external_port}"
       thread_pool.min_threads="0"
       thread_pool.max_threads="200"
       thread_pool.keep_alive_time="30000"/>
  <RED/>

  <!-- a location that can be found by both server's running -->
  <FILE_PING location="../file.ping.dir"/>
  <MERGE3  min_interval="10000"
           max_interval="30000"/>
  <FD_SOCK2/>
  <FD_ALL3 timeout="40000" interval="5000" />
  <VERIFY_SUSPECT2 timeout="1500"  />
  <BARRIER />
  <pbcast.NAKACK2 use_mcast_xmit="false" />
  <UNICAST3 />
  <pbcast.STABLE desired_avg_gossip="50000"
                 max_bytes="4M"/>
  <pbcast.GMS print_local_addr="true" join_timeout="2000"/>
  <UFC max_credits="2M"
       min_threshold="0.4"/>
  <MFC max_credits="2M"
       min_threshold="0.4"/>
  <FRAG2 frag_size="60K"  />
  <!--RSVP resend_interval="2000" timeout="10000"/-->
  <pbcast.STATE_TRANSFER/>
</config>

如它所示,檔案內容定義了 jgroups 協定堆疊。如果您希望 Apache ActiveMQ Artemis 使用此堆疊來建立通道,您必須確保廣播群組/探索群組設定中的 jgroups-file 值是此 jgroups 設定檔的名稱。例如,如果上述堆疊設定儲存在名為「jgroups-stacks.xml」的檔案中,則您的 jgroups-file 應該如下所示

<jgroups-file>jgroups-stacks.xml</jgroups-file>

3.1.2. 探索群組

雖然廣播群組定義了如何從伺服器廣播連接器資訊,但探索群組定義了如何從廣播端點(UDP 多播位址或 JGroup 通道)接收連接器資訊。

探索群組會維護一組連接器對清單 - 每個伺服器的每個廣播都有一個。當它從特定伺服器上的廣播端點接收廣播時,它會更新該伺服器在清單中的條目。

如果它在一段時間內沒有收到來自特定伺服器的廣播,它將從其清單中刪除該伺服器的條目。

探索群組在 Apache ActiveMQ Artemis 中有兩個地方使用

  • 叢集連線,以便它們知道如何取得初始連線以下載拓樸

  • 訊息客戶端,以便它們知道如何取得初始連線以下載拓樸

儘管探索群組始終會接受廣播,但其目前可用的主要和備份伺服器清單僅在建立初始連線時使用,之後伺服器探索會透過正常的 Apache ActiveMQ Artemis 連線完成。

每個探索群組都必須設定有與其廣播群組對應的廣播端點(UDP 或 JGroups)。例如,如果使用 UDP 設定廣播,則探索群組也必須使用 UDP,並且必須使用相同的多播位址。

3.1.3. 在伺服器上定義探索群組

對於叢集連線,探索群組在伺服器端設定檔 broker.xml 中定義。所有探索群組都必須在 discovery-groups 元素內定義。Apache ActiveMQ Artemis 伺服器可以定義多個探索群組。讓我們看一個範例

<discovery-groups>
   <discovery-group name="my-discovery-group">
      <local-bind-address>172.16.9.7</local-bind-address>
      <group-address>231.7.7.7</group-address>
      <group-port>9876</group-port>
      <refresh-timeout>10000</refresh-timeout>
   </discovery-group>
</discovery-groups>

我們將考慮探索群組的每個參數

名稱

屬性。每個探索群組在每個伺服器中都必須具有唯一的名稱。

local-bind-address

如果您在同一機器上使用多個網路介面執行,您可能希望指定探索群組僅接聽特定介面。若要執行此操作,您可以使用此參數指定介面位址。此參數為可選參數。這是 UDP 特有的屬性。

group-address

這是要監聽的群組多播 IP 位址。它應該與您希望監聽的廣播群組中的 group-address 相符。這個參數是強制性的。這是一個 UDP 特定的屬性。

group-port

這是多播群組的 UDP 端口。它應該與您希望監聽的廣播群組中的 group-port 相符。這個參數是強制性的。這是一個 UDP 特定的屬性。

refresh-timeout

這是發現群組在收到特定伺服器最後一次廣播後,等待多久才從其列表中移除該伺服器的連線器配對條目的時間。您通常會將此值設定為明顯高於廣播群組上的 broadcast-period 的值,否則伺服器可能會因為時間上的些微差異而間歇性地從列表中消失,即使它們仍在廣播。此參數為選填,預設值為 10000 毫秒(10 秒)。

這裡有另一個定義 JGroups 發現群組的範例

<discovery-groups>
   <discovery-group name="my-broadcast-group">
      <jgroups-file>test-jgroups-file_ping.xml</jgroups-file>
      <jgroups-channel>activemq_broadcast_channel</jgroups-channel>
      <refresh-timeout>10000</refresh-timeout>
   </discovery-group>
</discovery-groups>

要接收來自 JGroups 通道的廣播,必須指定兩個屬性,jgroups-filejgroups-channel,詳細說明如下

jgroups-file

屬性。這是 JGroups 配置檔案的名稱。它將用於初始化 JGroups 通道。請確保該檔案在 Java 資源路徑中,以便 Apache ActiveMQ Artemis 可以載入它。

jgroups-channel

屬性。JGroups 通道連接以接收廣播的名稱。

JGroups 屬性 (jgroups-filejgroups-channel) 和上述 UDP 特定屬性是互斥的。在一個發現群組配置中,只能指定一組。請勿混合使用!

3.1.4. 用戶端上的發現群組

讓我們討論如何設定 Apache ActiveMQ Artemis 用戶端,以使用發現功能來探索它可以連線的伺服器列表。執行此操作的方式會因您使用的是 JMS 還是核心 API 而異。

設定用戶端探索

使用 udp URL 方案,且主機:端口組合與伺服器上相應的 broadcast-group 中的 group-address 和 group-port 相符

udp://231.7.7.7:9876

使用此 URI 建立的連線將在發現群組透過監聽發現群組配置中指定的多播位址所維護的伺服器列表中進行負載平衡。

上述的 refreshTimeout 參數可以直接在 URI 中設定。

還有一個名為 initialWaitTimeout 的 URL 參數。如果對應的 JMS 連線工廠或核心 Session 工廠在建立後立即使用,則可能沒有足夠的時間接收來自叢集中所有節點的廣播。在第一次使用時,連線工廠將確保它自建立以來會等待這麼長的時間,然後再建立第一個連線。此參數的預設值為 10000 毫秒。

3.2. 使用靜態連線器的探索

有時可能無法在您使用的網路上使用 UDP。在這種情況下,可以設定與可能伺服器初始列表的連線。這可能只是您知道將始終可用的單一伺服器,或至少有一個伺服器將可用的伺服器列表。

這並不表示您必須知道所有伺服器將託管在哪裡,您可以設定這些伺服器以使用可靠的伺服器進行連線。一旦它們連線,它們的連線詳細資訊將透過它所連線的伺服器進行傳播

3.2.1. 設定叢集連線

對於叢集連線,不需要額外的設定,您只需確保以通常的方式定義任何連線器(有關連線器的更多資訊,請參閱 設定傳輸)。然後,這些會由叢集連線配置引用。

3.2.2. 設定用戶端連線

一般用戶端也可以使用可能的伺服器靜態列表。

設定用戶端探索

可以使用帶有 () 的語法在連線 URI 中指定要用於初始連線嘗試的伺服器列表,例如

(tcp://myhost:61616,tcp://myhost2:61616)?reconnectAttempts=5

括號會展開,因此為了方便起見,相同的查詢可以附加在最後一個括號之後。

4. 伺服器端訊息負載平衡

如果在叢集節點之間定義叢集連線,則 Apache ActiveMQ Artemis 將在從用戶端到達特定節點的訊息之間進行負載平衡。

讓我們以一個簡單的四節點叢集 A、B、C 和 D 的範例來說明,它們以對稱叢集(在「對稱叢集」章節中描述)排列。我們在叢集的每個節點上都部署了一個名為 OrderQueue 的佇列。

我們有一個連接到節點 A 的用戶端 Ca,向伺服器發送訂單。我們還有訂單處理器用戶端 Pa、Pb、Pc 和 Pd 連接到每個節點 A、B、C、D。如果在節點 A 上沒有定義叢集連線,則當訂單訊息到達節點 A 時,它們都將最終進入節點 A 上的 OrderQueue,因此只會由連接到節點 A 的訂單處理器用戶端 Pa 使用。

如果我們在節點 A 上定義一個叢集連線,那麼當排序的訊息到達節點 A 時,它們不會全部進入本地 OrderQueue 實例,而是以循環方式在叢集的所有節點之間分發。訊息會從接收節點轉發到叢集的其他節點。這一切都在伺服器端完成,用戶端保持與節點 A 的單一連線。

例如,到達節點 A 的訊息可能會以下列順序在節點之間分發:B、D、C、A、B、D、C、A、B、D。確切的順序取決於節點啟動的順序,但使用的演算法是循環方式。

可以設定 Apache ActiveMQ Artemis 叢集連線,始終以循環方式盲目地負載平衡訊息,而不考慮其他節點上是否有任何相符的取用者,但它們可以比這更聰明一點,並且也可以設定為僅在其他節點有相符的取用者時才分發到其他節點。我們將透過一些範例依序探討這兩種情況,但首先我們將討論一般叢集連線的設定。

4.1. 設定叢集連線

叢集連線將伺服器分組到叢集中,以便可以在叢集節點之間進行訊息負載平衡。讓我們來看一下典型的叢集連線。叢集連線始終在 broker.xmlcluster-connection 元素內定義。每個 Apache ActiveMQ Artemis 伺服器可以定義零個或多個叢集連線。

<cluster-connections>
   <cluster-connection name="my-cluster">
      <address></address>
      <connector-ref>netty-connector</connector-ref>
      <check-period>1000</check-period>
      <connection-ttl>5000</connection-ttl>
      <min-large-message-size>50000</min-large-message-size>
      <call-timeout>5000</call-timeout>
      <retry-interval>500</retry-interval>
      <retry-interval-multiplier>1.0</retry-interval-multiplier>
      <max-retry-interval>5000</max-retry-interval>
      <initial-connect-attempts>-1</initial-connect-attempts>
      <reconnect-attempts>-1</reconnect-attempts>
      <use-duplicate-detection>true</use-duplicate-detection>
      <message-load-balancing>ON_DEMAND</message-load-balancing>
      <max-hops>1</max-hops>
      <confirmation-window-size>32000</confirmation-window-size>
      <call-failover-timeout>30000</call-failover-timeout>
      <notification-interval>1000</notification-interval>
      <notification-attempts>2</notification-attempts>
      <discovery-group-ref discovery-group-name="my-discovery-group"/>
      <client-id></client-id>
   </cluster-connection>
</cluster-connections>

在上面的叢集連線中,所有參數都已明確指定。以下顯示所有可用的配置選項

address

每個叢集連線僅適用於與指定 address 欄位匹配的位址。當位址以這個欄位中指定的字串開頭時,會與叢集連線匹配。叢集連線上的 address 欄位也支援逗號分隔列表和排除語法 !。若要防止位址與此叢集連線匹配,請在叢集連線位址字串前面加上 !

在上面顯示的情況下,叢集連線將負載平衡傳送到所有位址的訊息(因為它是空的)。

位址可以是任何值,並且您可以有多個 address 值不同的叢集連線,同時平衡這些位址的訊息,可能會平衡到不同的伺服器叢集。透過在不同的位址上設定多個叢集連線,單一 Apache ActiveMQ Artemis 伺服器可以有效地同時參與多個叢集。

請小心,不要有多個 address 值重疊的叢集連線,例如 "europe" 和 "europe.news",因為這可能會導致相同的訊息在多個叢集連線之間分發,可能會導致重複傳遞。

範例

  • 'eu' 匹配所有以 'eu' 開頭的位址

  • '!eu' 匹配除以 'eu' 開頭的位址以外的所有位址

  • 'eu.uk,eu.de' 匹配所有以 'eu.uk' 或 'eu.de' 開頭的位址

  • 'eu,!eu.uk' 匹配所有以 'eu' 開頭的位址,但不匹配以 'eu.uk' 開頭的位址

  • 位址排除將始終優先於位址包含。

  • 叢集連線上的位址匹配不支援萬用字元匹配。

connector-ref

這是將傳送到叢集中其他節點的連線器,以便它們具有正確的叢集拓撲。

這個參數是強制性的。

check-period

用於檢查叢集連線是否未能收到來自其他伺服器的 ping 的週期(以毫秒為單位)。預設值為 30000。

connection-ttl

如果叢集連線停止接收來自叢集中特定節點的訊息,則叢集連線應保持活動狀態的時間長度。預設值為 60000。

min-large-message-size

如果訊息大小(以位元組為單位)大於此值,則在透過網路傳送到其他叢集成員時,將會分割成多個區段。預設值為 102400。

call-timeout

當透過叢集連線傳送封包,並且是封鎖呼叫時,即用於確認,則這會是等待回覆的時間長度(以毫秒為單位),然後才會擲回例外。預設值為 30000。

retry-interval

我們之前提到,在內部,叢集連線會導致在叢集節點之間建立橋接器。如果建立叢集連線並且目標節點尚未啟動,或者說正在重新啟動,則來自其他節點的叢集連線將會重試連線到目標,直到它恢復運作,其方式與橋接器相同。

此參數會決定重試嘗試之間的間隔(以毫秒為單位)。它與橋接器上的 retry-interval 具有相同的含義(如 核心橋接器 中所述)。

此參數為選填,其預設值為 500 毫秒。

retry-interval-multiplier

這是一個乘數,用於在每次重新連線嘗試後增加 retry-interval,預設值為 1。

max-retry-interval

重試的最大延遲時間(以毫秒為單位)。預設值為 2000。

initial-connect-attempts

系統最初將嘗試連線叢集中節點的次數。如果達到 max-retry,則此節點將被視為永久關閉,並且系統將不會將訊息路由到此節點。預設值為 -1(無限次重試)。

reconnect-attempts

系統將嘗試重新連線到叢集中節點的次數。如果達到 max-retry,則此節點將被視為永久關閉,並且系統將停止將訊息路由到此節點。預設值為 -1(無限次重試)。

use-duplicate-detection

在內部,叢集連線使用橋接器來連結節點,並且可以設定橋接器,在每個轉發的訊息中加入重複的 ID 屬性。如果橋接器的目標節點崩潰然後恢復,則可能會從來源節點重新傳送訊息。透過啟用重複偵測,任何重複的訊息將會在目標節點接收時被過濾掉並忽略。

此參數的意義與橋接器上的 use-duplicate-detection 相同。有關重複偵測的更多資訊,請參閱重複訊息偵測。預設值為 true

message-load-balancing

此參數決定訊息將如何/是否在叢集的其他節點之間分配。它可以是四個值之一:OFFSTRICTOFF_WITH_REDISTRIBUTIONON_DEMAND (預設值)。此參數取代了已棄用的 forward-when-no-consumers 參數。

如果設定為 OFF,則訊息永遠不會轉發到叢集中的另一個節點。

如果設定為 STRICT,則每個傳入的訊息都會以循環方式輪詢,即使叢集其他節點上的相同佇列可能完全沒有消費者,或者它們可能擁有不符合的訊息篩選器(選取器)。請注意,即使此參數設定為 STRICT,如果其他節點上沒有相同名稱的佇列,Apache ActiveMQ Artemis 也不會將訊息轉發到其他節點。使用 STRICT 就像將舊版的 forward-when-no-consumers 參數設定為 true 一樣。

如果設定為 ON_DEMAND,則 Apache ActiveMQ Artemis 僅會在要轉發到的位址具有擁有消費者的佇列,並且如果這些消費者具有訊息篩選器(選取器),則至少其中一個選取器必須與訊息相符時,才會將訊息轉發到叢集的其他節點。使用 ON_DEMAND 就像將舊版的 forward-when-no-consumers 參數設定為 false 一樣。

如果設定為 OFF_WITH_REDISTRIBUTION,則與 'OFF' 類似,訊息最初不會路由到叢集中的其他節點。但是,如果配置了重新分配,它可以正常方式轉發訊息。這樣,本地消費者將始終具有優先權。

請記住,此訊息轉發/負載平衡是我們所謂的「初始分配」。它與 下方討論重新分配不同。

預設值為 ON_DEMAND

max-hops

當叢集連線決定它可能將訊息負載平衡到哪些節點時,這些節點不必透過叢集連線直接連接到它。可以配置 Apache ActiveMQ Artemis,以便將訊息負載平衡到可能僅透過其他 Apache ActiveMQ Artemis 伺服器作為鏈中的中繼間接連接的節點。

這允許在更複雜的拓撲中配置 Apache ActiveMQ Artemis,並且仍然提供訊息負載平衡。我們將在本章稍後詳細討論。

此參數的預設值為 1,這表示訊息僅負載平衡到直接連接到此伺服器的其他 Apache ActiveMQ Artemis 伺服器。此參數是可選的。

confirmation-window-size

用於從連接的伺服器傳送確認的視窗大小(以位元組為單位)。因此,一旦伺服器接收到 confirmation-window-size 個位元組,它就會通知其用戶端,預設值為 1048576。值為 -1 表示沒有視窗。

producer-window-size

透過叢集連線進行生產者流量控制的大小。預設為 1MB。

call-failover-timeout

call-timeout 類似,但在容錯移轉嘗試期間進行呼叫時使用。預設值為 -1 (無逾時)。

notification-interval

叢集連線在附加到叢集時應廣播自身的頻率(以毫秒為單位)。預設值為 1000。

notification-attempts

叢集連線在連接到叢集時應廣播自身的次數。預設值為 2。

discovery-group-ref

此參數決定使用哪個發現群組來取得此叢集連線將要連線的叢集中其他伺服器的清單。

或者,如果您希望叢集連線使用伺服器的靜態清單進行探索,則可以像這樣操作。

<cluster-connection name="my-cluster">
   ...
   <static-connectors>
      <connector-ref>server0-connector</connector-ref>
      <connector-ref>server1-connector</connector-ref>
   </static-connectors>
</cluster-connection>

在這裡,我們定義了 2 個我們確定至少有一個可用的伺服器。叢集中可能還有更多的伺服器,但一旦建立初始連線,這些伺服器將透過這些連接器之一被發現。

client-id

用於叢集連線的可選識別碼。這可以幫助在遠端代理程式上識別連線(例如,透過網路主控台)。預設值為空(即未設定)。

4.2. 叢集使用者憑證

當在叢集的節點之間建立連線以形成叢集連線時,Apache ActiveMQ Artemis 會使用 broker.xml 中定義的叢集使用者和叢集密碼。

<cluster-user>ACTIVEMQ.CLUSTER.ADMIN.USER</cluster-user>
<cluster-password>CHANGE ME!!</cluster-password>

必須將這些值從其預設值更改,否則遠端用戶端將能夠使用預設值連線到伺服器。如果它們沒有從預設值更改,Apache ActiveMQ Artemis 將會偵測到這一點,並在每次啟動時以警告打擾您。

5. 用戶端負載平衡

透過 Apache ActiveMQ Artemis 用戶端負載平衡,使用單一工作階段工廠建立的後續工作階段可以連接到叢集的不同節點。這允許工作階段平穩地分佈在叢集的節點之間,而不會「聚集」在任何特定節點上。

用戶端工廠要使用的負載平衡策略是可配置的。Apache ActiveMQ Artemis 提供四種開箱即用的負載平衡策略,您也可以實作自己的策略並使用它。

開箱即用的策略是

  • 循環配置。使用此策略,會隨機選擇第一個節點,然後按相同的順序依序選擇每個後續節點。

    例如,節點可能會按 B、C、D、A、B、C、D、A、B 或 D、A、B、C、D、A、B、C、D 或 C、D、A、B、C、D、A、B、C 的順序選擇。

    使用 org.apache.activemq.artemis.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy 作為 <connection-load-balancing-policy-class-name>

  • 隨機。使用此策略,每個節點都是隨機選擇的。

    使用 org.apache.activemq.artemis.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy 作為 <connection-load-balancing-policy-class-name>

  • 隨機黏性。使用此策略,會隨機選擇第一個節點,然後將其重新用於後續連線。

    使用 org.apache.activemq.artemis.api.core.client.loadbalance.RandomStickyConnectionLoadBalancingPolicy 作為 <connection-load-balancing-policy-class-name>

  • 第一個元素。使用此策略,始終返回「第一個」(即第 0 個)節點。

    使用 org.apache.activemq.artemis.api.core.client.loadbalance.FirstElementConnectionLoadBalancingPolicy 作為 <connection-load-balancing-policy-class-name>

您也可以透過實作介面 org.apache.activemq.artemis.api.core.client.loadbalance.ConnectionLoadBalancingPolicy 來實作自己的策略。

指定使用哪個負載平衡策略取決於您使用的是 JMS 還是核心 API。如果您沒有指定策略,則將使用預設策略,即 org.apache.activemq.artemis.api.core.client.loadbalance.RoundRobinConnectionLoadBalancingPolicy

可以在 URI 上設定參數 connectionLoadBalancingPolicyClassName,以設定要使用的負載平衡策略。

tcp://127.0.0.1:61616?connectionLoadBalancingPolicyClassName=org.apache.activemq.artemis.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy

可以透過兩種方式之一確定工廠在其中進行負載平衡的伺服器集合。

  • 在 URL 中明確指定伺服器。這也需要在 URL 上將 useTopologyForLoadBalancing 參數設定為 false

  • 使用探索。這是預設行為。

6. 明確指定叢集成員

有時您想要更明確地定義叢集,也就是控制叢集中哪個伺服器連接到彼此。這通常用於形成非對稱叢集,例如鏈式叢集或環形叢集。這只能透過靜態連接器清單來完成,並按如下方式配置

<cluster-connection name="my-cluster">
   <address/>
   <connector-ref>netty-connector</connector-ref>
   <retry-interval>500</retry-interval>
   <use-duplicate-detection>true</use-duplicate-detection>
   <message-load-balancing>STRICT</message-load-balancing>
   <max-hops>1</max-hops>
   <static-connectors allow-direct-connections-only="true">
      <connector-ref>server1-connector</connector-ref>
   </static-connectors>
</cluster-connection>

在此範例中,我們設定了屬性 allow-direct-connections-only,這表示此伺服器可以建立叢集連線的唯一伺服器是 server1-connector。這表示您可以明確建立想要的任何叢集拓撲。

7. 訊息重新分配

叢集的另一個重要部分是訊息重新分配。稍早我們了解到伺服器端訊息負載平衡如何在叢集中循環配置訊息。如果 message-load-balancingOFFON_DEMAND,則不會將訊息轉發到沒有相符消費者的節點。這很好,並確保訊息不會移至沒有消費者可使用的佇列。但是,有一個情況它無法解決:如果佇列上的消費者在將訊息傳送到節點後關閉,會發生什麼情況?如果佇列上沒有消費者,訊息將不會被使用,並且我們會有飢餓的情況。

這就是訊息重新分配的用武之地。透過訊息重新分配,可以將 Apache ActiveMQ Artemis 配置為自動從沒有消費者或具有不匹配訊息的篩選器的消費者佇列重新分配訊息。訊息會重新路由到叢集中確實具有相符消費者的其他節點。若要啟用此功能,message-load-balancing 必須為 ON_DEMANDOFF_WITH_REDISTRIBUTION

可以配置訊息重新分配,使其在偵測到需要重新分配後立即啟動,或在重新分配之前等待可配置的延遲。預設情況下,訊息重新分配已停用。

可以透過在位址設定中指定重新分配延遲,在每個位址的基礎上配置訊息重新分配。有關配置位址設定的更多資訊,請參閱透過位址設定配置位址和佇列

以下是 broker.xml 中的一個位址設定程式碼片段,展示如何為一組佇列啟用訊息重新分配:

<address-settings>
   <address-setting match="#">
      <redistribution-delay>0</redistribution-delay>
   </address-setting>
</address-settings>

上述的 address-settings 區塊會為任何繫結到任何位址的佇列設定 redistribution-delay0。因此,上述設定會為所有位址啟用立即(無延遲)重新分配。

屬性 match 可以是完全符合的字串,也可以是符合 Apache ActiveMQ Artemis 萬用字元語法(在 萬用字元語法 中描述)的字串。

元素 redistribution-delay 定義了偵測到需要重新分配和實際嘗試重新分配之間的延遲時間(以毫秒為單位)。延遲時間為零表示訊息將立即重新分配。值為 -1 表示訊息永遠不會被重新分配。預設值為 -1

在重新分配之前引入延遲通常是有意義的,因為常見的情況是消費者關閉,但很快又在同一個佇列上建立另一個消費者,在這種情況下,您可能不希望立即重新分配,因為新的消費者很快就會到達。

8. 叢集拓撲

Apache ActiveMQ Artemis 叢集可以以許多不同的拓撲結構連接在一起,讓我們在這裡考慮兩個最常見的拓撲結構

8.1. 對稱叢集

對稱叢集可能是最常見的叢集拓撲。

在對稱叢集中,叢集中的每個節點都連接到叢集中的所有其他節點。換句話說,叢集中的每個節點與所有其他節點之間的距離都不超過一個躍點。

為了形成對稱叢集,叢集中的每個節點都會定義一個叢集連線,並將屬性 max-hops 設定為 1。通常,叢集連線將使用伺服器探索來了解它應該連線到叢集中的哪些其他伺服器,儘管也可以在叢集連線中明確定義每個目標伺服器,例如,如果您的網路上無法使用 UDP。

在對稱叢集中,每個節點都知道所有其他節點上存在的所有佇列以及它們擁有的消費者。有了這些知識,它可以決定如何在節點之間進行負載平衡和重新分配訊息。

在建立對稱叢集時,請不要忘記此警告

8.2. 鏈狀叢集

在鏈狀叢集中,叢集中的每個節點並非直接連接到叢集中的所有節點,而是節點形成一條鏈,鏈的兩端各有一個節點,而所有其他節點僅連接到鏈中的前一個和下一個節點。

一個例子是由節點 A、B 和 C 組成的三節點鏈。節點 A 託管在一個網路中,並且有許多生產者客戶端連接到它,發送訂單訊息。由於公司政策,訂單消費者客戶端需要託管在不同的網路中,並且該網路只能通過第三個網路訪問。在此設定中,節點 B 作為中介,沒有生產者或消費者在其上。任何到達節點 A 的訊息都會轉發到節點 B,然後節點 B 會將它們轉發到節點 C,在節點 C 上它們可以被消費。節點 A 不需要直接連接到 C,但所有節點仍然可以作為叢集的一部分。

若要以這種方式設定叢集,節點 A 會定義一個連接到節點 B 的叢集連線,而節點 B 會定義一個連接到節點 C 的叢集連線。在這種情況下,我們只需要一個方向的叢集連線,因為我們只從節點 A->B->C 移動訊息,而永遠不會從 C->B->A 移動。

對於此拓撲,我們將 max-hops 設定為 2。當值為 2 時,關於節點 C 上存在的佇列和消費者的知識將從節點 C 傳播到節點 B,再到節點 A。然後,節點 A 會知道在訊息到達時將其分發到節點 B,即使節點 B 本身沒有消費者,它也會知道更遠的一個躍點是節點 C,它確實有消費者。

8.3. 縮減規模

Apache ActiveMQ Artemis 支援縮減叢集規模,而不會遺失訊息(即使是非持久訊息)。這在某些環境(例如雲端)中特別有用,在這些環境中,叢集的大小可能會相對頻繁地變化。在擴展叢集(即添加節點)時,不會有訊息遺失的風險,但是在縮減叢集(即移除節點)時,除非 Broker 將它們發送到叢集中的另一個節點,否則這些節點上的訊息將會遺失。可以將 Apache ActiveMQ Artemis 配置為執行此操作。

要啟用此行為,請在 live-only ha-policy 中設定 scale-down,例如:

<ha-policy>
   <live-only>
      <scale-down>
         <enabled>true</enabled>
         <discovery-group-ref discovery-group-name="my-discovery-group"/>
      </scale-down>
   </live-only>
</ha-policy>

如果 scale-down/enabledtrue,則當伺服器正常關閉(即在沒有崩潰的情況下停止)時,它會找到叢集中的另一個節點,並將其所有訊息(包括持久和非持久訊息)發送到該節點。這些訊息會依序處理,並進入其他節點上各自佇列的尾端(就像訊息第一次從外部客戶端發送一樣)。

可以通過幾種不同的方式配置縮減規模操作的目標。上面的範例使用 discovery-group-ref 來參考 discovery-group,該 discovery-group 將用於尋找目標 Broker。這應該與您的 cluster-connection 參考的 discovery-group 相同。您也可以指定 connector 元素的靜態清單,例如:

<connectors>
  ...
  <connector name="server0-connector">tcp://server0:61616</connector>
</connectors>
...
<ha-policy>
  <live-only>
    <scale-down>
      <enabled>true</enabled>
      <connectors>
        <connector-ref>server0-connector</connector-ref>
      </connectors>
    </scale-down>
  </live-only>
</ha-policy>

也可以指定 group-name。如果指定了此項,則訊息只會發送到叢集中另一個使用與正在關閉的伺服器相同 group-name 的節點,例如:

<ha-policy>
   <live-only>
      <scale-down>
         <enabled>true</enabled>
         <group-name>my-group</group-name>
         <discovery-group-ref discovery-group-name="my-discovery-group"/>
      </scale-down>
   </live-only>
</ha-policy>

如果叢集節點使用不同的 group-name 值分組在一起,請注意。如果單個組中的所有節點都關閉,則該節點/組中的訊息將會遺失。