我們將高可用性 (HA) 定義為系統在一個或多個伺服器發生故障後仍能繼續運作的能力

高可用性的一部分是故障轉移,我們將其定義為在伺服器發生故障時,用戶端連線從一個伺服器移轉到另一個伺服器的能力,以便用戶端應用程式可以繼續運作

1. 術語

為了能一致地討論設定和執行期行為,我們需要定義幾個名詞和形容詞。這些術語將在整個文件、設定、原始碼和執行期記錄中使用。

1.1. 設定

這些名詞識別代理程式的設定方式,例如在 broker.xml 中。設定允許將代理程式配對為主要/備份(即代理程式的HA 配對)。

主要

這識別高可用性設定中的主要代理程式。通常,此代理程式上的硬體效能會高於備份代理程式上的硬體。通常,此代理程式會在備份之前啟動,並且大部分時間都處於活動狀態。

每個主要伺服器可以與一個備份伺服器配對。可以設定其他備份,但主要伺服器只會與一個配對。當主要伺服器發生故障時,備份伺服器將接管。此時,如果有設定其他備份,則接管的備份伺服器將與其中一個配對。

備份

這識別當主要代理程式在高可用性設定中發生故障時,應接管的代理程式。通常,此代理程式上的硬體效能會低於主要代理程式上的硬體。通常,此代理程式會在主要代理程式之後啟動,並且大部分時間都處於被動狀態。

1.2. 執行期

這些形容詞描述代理程式在執行期的行為。例如,您可能有一個被動主要或一個活動備份。

活動

這識別高可用性設定中正在接受遠端連線的代理程式。例如,考慮主要代理程式發生故障且其備份已接管的情況。此時,備份會被描述為活動,因為它正在接受遠端連線。

被動

這識別高可用性設定中接受遠端連線的代理程式。例如,考慮主要代理程式已啟動,然後備份代理程式已啟動的情況。備份代理程式將處於被動狀態,因為它不接受遠端連線。它正在等待主要伺服器發生故障,然後才會啟動並開始接受遠端連線。

2. HA 原則

Apache ActiveMQ Artemis 支援兩個主要原則來備份伺服器

  • 共用儲存

  • 複寫

這些是透過 ha-policy 設定元素進行設定。

備份內容為何?

只有寫入儲存體的訊息資料才能在故障轉移後存留。任何未寫入儲存體的訊息資料在故障轉移後都無法使用。

需要叢集

需要正確的叢集設定作為 HA 設定的先決條件。叢集設定允許伺服器向其主要/備份(或叢集中的任何其他節點)宣告其存在。

在技術上,還有第三個原則稱為 primary-only,它完全省略了備份。這用於設定 縮減規模。如果未提供任何原則,則這是預設原則。

2.1. 共用儲存

使用共用儲存時,主要和備份伺服器都使用共用檔案系統來共用相同的完整資料目錄。這包括分頁目錄、日誌目錄、大型訊息和繫結日誌。

當主要伺服器發生故障時,它會釋放其在共用日誌上的鎖定,並允許備份伺服器啟動。然後,備份伺服器將從共用檔案系統載入資料,並接受來自用戶端的遠端連線。

通常,這會是某種高效能儲存區域網路 (SAN)。網路附加儲存 (NAS),如 NFS 掛載,是可行的,但不會提供最佳效能。

共用儲存設定的一個主要優點是主要和備份節點之間不會發生複寫,這表示它在正常運作期間不會因複寫的額外負荷而受到任何效能損失。

共用儲存相對於複寫的一個潛在重大缺點是它需要共用檔案系統,並且當備份伺服器啟動時,它需要從共用儲存載入日誌,這可能需要一些時間,具體取決於儲存中的資料量和儲存的速度。

如果您在正常運作期間需要最高的效能,請取得快速 SAN 的存取權,並處理稍微慢一點的故障轉移(取決於資料量)。

那腦裂呢?

共用儲存設定自然對 腦裂免疫。

2.1.1. 共用儲存設定

主要和備份伺服器都必須將日誌目錄的位置設定為相同的共用位置(如持久性文件中所述)。

主要

主要代理程式需要在 broker.xml 中進行此基本設定

<ha-policy>
   <shared-store>
      <primary/>
   </shared-store>
</ha-policy>
其他參數
failover-on-shutdown

此代理程式的正常關閉是否會導致備份啟動。

如果為 false,則如果此代理程式正常關閉(例如使用 Ctrl-C),備份伺服器將保持被動狀態。請注意,如果為 false 並且您希望發生故障轉移,則可以使用管理 API,如此處所述。

如果為 true,則當此伺服器停止時,備份將啟動。

預設值為 false

wait-for-activation

此設定僅適用於內嵌使用案例,其中主要代理程式已發生故障,備份已啟動,且主要代理程式已重新啟動。預設情況下,當叫用 org.apache.activemq.artemis.core.server.ActiveMQServer.start() 時,代理程式將會封鎖,直到主要代理程式實際從備份接管(即透過故障恢復或備份實際停止)。將 wait-for-activation 設定為 false 可防止 start() 封鎖,以便將控制權傳回給呼叫者。呼叫者可以使用 waitForActivation() 來等待直到代理程式啟動,或僅使用 getState() 來檢查目前狀態。預設值為 true

備份

備份需要在 broker.xml 中進行此基本設定

<ha-policy>
   <shared-store>
      <backup/>
   </shared-store>
</ha-policy>
其他參數
allow-failback

當此備份的主要伺服器重新啟動並請求接管其位置時,此備份是否會自動停止。使用案例是當主要伺服器停止且其備份接管其職責時,稍後主要伺服器重新啟動並請求現在處於活動狀態的備份停止,以便主要伺服器可以再次接管。預設值為 true

failover-on-shutdown

此代理程式的正常關閉是否會導致備份啟動。

如果為 false,則如果此代理程式正常關閉(例如使用 Ctrl-C),備份伺服器將保持被動狀態。請注意,如果為 false 並且您希望發生故障轉移,則可以使用管理 API,如此處所述。

如果為 true,則當此伺服器停止時,備份將啟動。

預設值為 false

這僅適用於此備份由於其主要伺服器發生故障而啟動時。
scale-down

如果提供,則此備份會縮減規模,而不是在故障轉移後變為活動狀態。這實際上僅適用於共置設定,其中備份會將其訊息縮減規模到同一 JVM 中的主要代理程式。

restart-backup

此備份是否會在因故障恢復或縮減規模而停止後重新啟動。預設值為 false

NFS 掛載建議

如果您選擇使用 NFS 來實作共用儲存設定,以下是一些建議的設定選項。這些設定旨在提高可靠性,並協助代理程式快速偵測到 NFS 的問題並自行關閉,以便用戶端可以故障轉移到運作中的代理程式。

sync

指定所有變更立即刷新到磁碟。

intr

允許在伺服器關閉或無法連線時中斷 NFS 要求。

noac

停用屬性快取。需要此行為才能在多個用戶端之間實現屬性快取一致性。

soft

指定如果 NFS 伺服器無法使用,應報告錯誤,而不是等待伺服器重新上線。

lookupcache=none

停用查詢快取。

timeo=n

NFS 用戶端(即代理程式)在重試要求之前等待 NFS 伺服器回應的時間(以十分之一秒為單位)。對於透過 TCP 的 NFS,預設的 timeo 值為 600(60 秒)。對於透過 UDP 的 NFS,用戶端使用自適應演算法來估計常用要求類型(例如讀取和寫入要求)的適當逾時值。

retrans=n

NFS 用戶端在嘗試進一步復原動作之前,重試請求的次數。

設定 timeoretrans 時,請使用合理的值。預設的 timeo 等待時間為 600 毫秒 (60 秒),搭配 retrans 值為 5 次重試,可能會導致代理程式在偵測到 NFS 連線中斷時,需要等待五分鐘。您可能不希望代理程式上所有與儲存相關的操作,在用戶端等待回應時被封鎖這麼久。調整這些值以平衡您環境中的延遲和可靠性。

2.2. 複寫

使用複寫時,主要伺服器和備份伺服器不會共用相同的資料目錄。所有資料同步都透過網路進行。因此,主要伺服器接收到的所有 (持久性) 資料都將被複製到備份伺服器。

請注意,在啟動時,備份伺服器首先需要從主要伺服器同步所有現有資料,才能在主要伺服器發生故障時取代它。因此,與使用共用儲存不同,備份伺服器在完成與主要伺服器的資料同步之前,不會完全運作。這需要花費的時間取決於要同步的資料量和連線速度。

一般來說,同步會與目前的網路流量並行發生,因此不會對目前的用戶端造成任何阻礙。但是,在這個過程的結尾有一個關鍵時刻,複寫伺服器必須完成同步並確保備份伺服器確認已完成。複寫伺服器和備份伺服器之間的這種交換將會封鎖任何與日誌相關的操作。此交換將會封鎖的最長時間由 initial-replication-sync-timeout 組態元素控制。

由於複寫會在備份伺服器建立資料副本,因此在成功容錯移轉的情況下,備份伺服器的資料會比主要伺服器的資料新。如果您將備份設定為允許故障回復到主要伺服器,那麼當主要伺服器重新啟動時,它將會處於被動狀態,而處於作用中的備份伺服器會將其資料與被動的主要伺服器同步,然後停止以允許被動的主要伺服器再次變成作用中。如果兩個伺服器都關閉,則管理員將必須判斷哪一個伺服器擁有最新的資料。

與共用儲存的重要差異

如果共用儲存備份沒有找到主要伺服器,它將會像主要伺服器一樣啟動並服務用戶端請求。

但是,在複寫的情況下,備份伺服器只會持續等待與主要伺服器配對,因為備份伺服器不知道其資料是否為最新。它無法單方面決定啟動。若要使用其目前的資料啟動複寫備份伺服器,管理員必須變更其組態,將其變更為主要伺服器,方法是將 backup 變更為 primary

2.2.1. 分裂腦

「分裂腦」是一個潛在的問題,瞭解這一點很重要。一整章專門介紹解釋其內容,以及如何在較高層次上減輕其影響。一旦您閱讀過它,您將會瞭解仲裁投票可插入鎖定管理員組態之間的主要差異,這些差異將在後續章節中提及。

2.2.2. 複寫組態

在共用儲存組態中,代理程式會根據它們的共用儲存裝置彼此配對。但是,由於複寫組態沒有此類共用儲存裝置,它們必須以其他方式找到彼此。可以使用 primarybackup 元素中的相同 group-name,將伺服器明確地分組在一起。備份伺服器只會連線到與之共用相同節點群組名稱的主要伺服器。

group-name 範例

假設您有 5 個主要伺服器和 6 個備份伺服器

  • primary1primary2primary3:具有 group-name=fish

  • primary4primary5:具有 group-name=bird

  • backup1backup2backup3backup4:具有 group-name=fish

  • backup5backup6:具有 group-name=bird

加入叢集後,具有 group-name=fish 的備份伺服器將會搜尋具有 group-name=fish 的主要伺服器進行配對。由於備份伺服器多了一個,fish 將會保留一個備用備份伺服器。

具有 group-name=bird 的 2 個備份伺服器 (backup5backup6) 將會與主要伺服器 primary4primary5 配對。

如果未設定 group-name,則備份伺服器將會搜尋它可以在叢集中找到的任何主要伺服器。它會嘗試與每個主要伺服器複寫,直到找到沒有設定目前備份伺服器的主要伺服器。如果沒有可用的主要伺服器,它將會等待叢集拓樸變更,並重複此過程。

主要伺服器

主要代理程式需要在 broker.xml 中進行此基本設定

<ha-policy>
   <replication>
      <primary/>
   </replication>
</ha-policy>
其他參數
group-name

如果設定,備份伺服器將只會與具有相符群組名稱的主要伺服器配對。請參閱上方以瞭解更多詳細資料。對於仲裁投票和可插入鎖定管理員均有效。

cluster-name

用於複寫的 cluster-connection 名稱。如果您設定多個叢集連線,則此設定是唯一必要的。如果已設定,則當連線到叢集以探索是否有作用中的伺服器已在執行時,將會使用具有此名稱的叢集組態的連接器組態,請參閱 check-for-active-server。如果未設定,則會使用預設的叢集連線組態 (也就是第一個設定的叢集連線)。對於仲裁投票和可插入鎖定管理員均有效。

max-saved-replicated-journals-size

此選項指定當伺服器以被動備份身分啟動時,將會保留多少個複寫備份目錄。每次當伺服器以這種方式啟動時,所有先前的資料都會移至 oldreplica.{id} 目錄,其中 {id} 是遞增的備份索引。此參數設定磁碟上保留的此類目錄的最大數目。對於仲裁投票和可插入鎖定管理員均有效。

check-for-active-server

在啟動時是否使用我們自己的伺服器 ID 檢查叢集中是否有作用中的伺服器。這是在發生容錯移轉且主要伺服器重新啟動時,避免分裂腦的重要選項。預設值為 false。僅適用於仲裁投票。

initial-replication-sync-timeout

複寫伺服器在初始複寫過程完成時,會等待備份伺服器確認它已接收所有必要資料的時間。預設值為 30000;以毫秒為單位。對於仲裁投票和可插入鎖定管理員均有效。

在此間隔期間,任何與日誌相關的操作都會被封鎖。
vote-on-replication-failure

如果遺失複寫,此主要代理程式是否應投票保持作用中。預設值為 false。僅適用於仲裁投票。

quorum-size

遺失複寫後用於投票的仲裁大小,-1 表示使用目前的叢集大小。預設值為 -1。僅適用於仲裁投票。

vote-retries

如果我們以備份身分啟動,並且遺失與主要伺服器的連線,在重新啟動之前,我們應該嘗試投票仲裁多少次?預設值為 12。僅適用於仲裁投票。

vote-retry-wait

每次投票嘗試之間等待的時間 (以毫秒為單位)。預設值為 5000。僅適用於仲裁投票。

quorum-vote-wait

等待投票結果的時間 (以秒為單位)。預設值為 30。僅適用於仲裁投票。

retry-replication-wait

如果我們以備份身分啟動,在無法找到主要伺服器之後,再次嘗試複寫之前要等待的時間 (以毫秒為單位)。預設值為 2000。對於仲裁投票和可插入鎖定管理員均有效。

manager

此元素控制且是可插入鎖定管理員組態的必要元素。它有兩個子元素

  • class-name - 實作 org.apache.activemq.artemis.lockmanager.DistributedLockManager 的類別名稱。預設值為 org.apache.activemq.artemis.lockmanager.zookeeper.CuratorDistributedLockManager,它會與 ZooKeeper 整合

  • properties - property 元素的清單,每個元素都具有 keyvalue 屬性,用於設定外掛程式。

    以下是一個簡單的範例

    <ha-policy>
       <replication>
          <primary>
             <manager>
                <class-name>org.foo.MyQuorumVotingPlugin</class-name>
                <properties>
                   <property key="property1" value="value1"/>
                   <property key="property2" value="value2"/>
                </properties>
             </manager>
          </primary>
       </replication>
    </ha-policy>
coordination-id

這是用於競爭的主要代理程式。僅在使用可插入鎖定管理員時有效。

備份伺服器

備份需要在 broker.xml 中進行此基本設定

<ha-policy>
   <replication>
      <backup/>
   </replication>
</ha-policy>
其他參數
group-name

如果設定,備份伺服器將只會與具有相符群組名稱的主要伺服器配對。請參閱上方以瞭解更多詳細資料。對於仲裁投票和可插入鎖定管理員均有效。

cluster-name

用於複寫的 cluster-connection 名稱。如果您設定多個叢集連線,則此設定是唯一必要的。如果已設定,則當連線到叢集以探索是否有作用中的伺服器已在執行時,將會使用具有此名稱的叢集組態的連接器組態,請參閱 check-for-active-server。如果未設定,則會使用預設的叢集連線組態 (也就是第一個設定的叢集連線)。對於仲裁投票和可插入鎖定管理員均有效。

max-saved-replicated-journals-size

此選項指定當伺服器以被動備份身分啟動時,將會保留多少個複寫備份目錄。每次當伺服器以這種方式啟動時,所有先前的資料都會移至 oldreplica.{id} 目錄,其中 {id} 是遞增的備份索引。此參數設定磁碟上保留的此類目錄的最大數目。對於仲裁投票和可插入鎖定管理員均有效。

scale-down

如果提供,則此備份會縮減規模,而不是在故障轉移後變為活動狀態。這實際上僅適用於共置設定,其中備份會將其訊息縮減規模到同一 JVM 中的主要代理程式。

restart-backup

如果此伺服器是備份伺服器,它是否會在因故障回復或縮減規模而停止後重新啟動。預設值為 false

allow-failback

當主要伺服器重新啟動並要求接管其位置時,此備份伺服器是否會自動停止。使用案例是當主要伺服器停止且其備份伺服器接管其職責時,稍後主要伺服器重新啟動並要求現在處於作用中的備份伺服器停止,以便主要伺服器可以再次接管。預設值為 true。對於仲裁投票和可插入鎖定管理員均有效。

initial-replication-sync-timeout

在容錯移轉之後,當備份伺服器已啟動時,當主要伺服器重新啟動並連線為備份伺服器時 (例如,為了故障回復),會強制執行此作業。複寫伺服器在初始複寫過程完成時,會等待備份伺服器確認它已接收所有必要資料的時間。預設值為 30000;以毫秒為單位。對於仲裁投票和可插入鎖定管理員均有效。

在此間隔期間,任何與日誌相關的操作都會被封鎖。
vote-on-replication-failure

如果遺失複寫,此主要代理程式是否應投票保持作用中。預設值為 false。僅適用於仲裁投票。

quorum-size

遺失複寫後用於投票的仲裁大小,-1 表示使用目前的叢集大小。預設值為 -1。僅適用於仲裁投票。

vote-retries

如果我們以備份身分啟動,並且遺失與主要伺服器的連線,在重新啟動之前,我們應該嘗試投票仲裁多少次。預設值為 12。僅適用於仲裁投票。

vote-retry-wait

每次投票嘗試之間等待的時間 (以毫秒為單位)。預設值為 5000。僅適用於仲裁投票。

quorum-vote-wait

等待投票結果的時間 (以秒為單位)。預設值為 30。僅適用於仲裁投票。

retry-replication-wait

如果我們以備份身分啟動,在無法找到主要伺服器之後,再次嘗試複寫之前要等待的時間 (以毫秒為單位)。預設值為 2000。對於仲裁投票和可插入鎖定管理員均有效。

manager

此元素控制且是可插入鎖定管理員組態的必要元素。它有兩個子元素

  • class-name - 實作 org.apache.activemq.artemis.lockmanager.DistributedLockManager 的類別名稱。預設值為 org.apache.activemq.artemis.lockmanager.zookeeper.CuratorDistributedLockManager,它會與 ZooKeeper 整合

  • properties - property 元素的清單,每個元素都具有 keyvalue 屬性,用於設定外掛程式。

    以下是一個簡單的範例

    <ha-policy>
       <replication>
          <backup>
             <manager>
                <class-name>org.foo.MyQuorumVotingPlugin</class-name>
                <properties>
                   <property key="property1" value="value1"/>
                   <property key="property2" value="value2"/>
                </properties>
             </manager>
             <allow-failback>true</allow-failback>
          </backup>
       </replication>
    </ha-policy>

2.2.3. Apache ZooKeeper 整合

預設的可插入鎖定管理員實作使用 Apache CuratorApache ZooKeeper 整合。

ZooKeeper 外掛程式組態

以下是基本的組態範例

<ha-policy>
   <replication>
      <primary>
         <manager>
            <class-name>org.apache.activemq.artemis.lockmanager.zookeeper.CuratorDistributedLockManager</class-name>
            <properties>
               <property key="connect-string" value="127.0.0.1:6666,127.0.0.1:6667,127.0.0.1:6668"/>
            </properties>
         </manager>
      </primary>
   </replication>
</ha-policy>

+ 注意:這裡技術上不需要 class-name,因為正在使用預設值,但為了清楚起見,因此包含它。

可用屬性
connect-string

(無預設值)

session-ms

(預設值為 18000 毫秒)

session-percent

(預設值為 33);應 ≤ 預設值 (如需更多資訊,請參閱 TN14)

connection-ms

(預設值為 8000 毫秒)

retries

(預設值為 1)

retries-ms

(預設值為 1000 毫秒)

namespace

(無預設值)

提高可靠性

ZooKeeper 集合的組態由使用者負責,但以下是一些提高仲裁服務可靠性的建議

  • 根據 ZooKeeper 3.6.3 管理指南,代理程式 (Broker) 的 session_ms 值必須 ≥ 2 * 伺服器 Tick 時間≤ 20 * 伺服器 Tick 時間。這會直接影響備份伺服器容錯移轉至隔離/已終止/無回應的主要伺服器的速度。數值越高,速度越慢。

  • 為了讓 ZooKeeper 的心跳協定可靠運作,代理程式機器的 GC (垃圾收集) 暫停時間應保持在 session_ms 的 1/3 以內。如果無法達到,最好增加 session_ms 值,以接受較慢的容錯移轉速度。

  • ZooKeeper 必須有足夠的資源來保持 GC (和 OS) 暫停時間遠小於伺服器 Tick 時間。請仔細考慮是否應讓代理程式和 ZooKeeper 節點共享同一台實體機器,這取決於代理程式的預期負載。

  • 網路隔離保護需要配置 ≥3 個 ZooKeeper 節點。

如先前所述,session-ms 會影響容錯移轉的持續時間。被動代理程式可以在 session-ms 過期後啟動,或者在主動代理程式自願放棄其角色時(例如,在容錯回復/手動停止代理程式期間,會立即發生)。

對於前一種情況(當主動代理程式不再存在時,會發生 Session 過期),被動代理程式可以透過以下方式偵測無回應的主動代理程式:

  1. 叢集連線 PING (受 connection-ttl 設定影響)

  2. 關閉 TCP 連線通知 (取決於 TCP 設定和網路堆疊/拓撲)

建議將 connection-ttl 調低,以盡快嘗試容錯移轉,同時考慮到整個容錯移轉持續時間不能短於設定的 session-ms

備份伺服器仍然需要仔細配置 connection-ttl,以便在容錯移轉之前,及時向仲裁管理器發送成為主動伺服器的請求。

2.2.4. 競爭的主代理程式

當將仲裁委派給可插拔的實作時,主動和備份的角色變得不那麼重要。有可能讓兩個代理程式競爭啟動,勝出的代理程式會啟動成為主動伺服器,而敗者則擔任備份角色。在重新啟動時,任何擁有最新日誌的對等伺服器都可以啟動。關鍵是代理程式需要事先知道它們將協調哪個身分。在複製的 primary ha-policy 中,我們可以將 coordination-id 明確設定為叢集中所有對等節點的共同值。

<ha-policy>
   <replication>
      <primary>
         <manager>
            <class-name>org.apache.activemq.artemis.lockmanager.zookeeper.CuratorDistributedLockManager</class-name>
            <properties>
               <property key="connect-string" value="127.0.0.1:6666,127.0.0.1:6667,127.0.0.1:6668"/>
            </properties>
         </manager>
         <coordination-id>peer-journal-001</coordination-id>
      </primary>
   </replication>
</ha-policy>
作為 coordination-id 提供的字串值將在內部轉換為 16 位元組的 UUID,因此可能無法立即識別或對人類來說是可讀的。但是,它將確保所有「對等節點」進行協調。

3. 回復到主要伺服器

在主要伺服器發生故障且備份伺服器接管其職責後,您可能需要重新啟動主要伺服器並讓用戶端回復。

3.1. 使用共享儲存進行回復

在共享儲存的情況下,您有幾個選項:

  1. 只需重新啟動主要伺服器並終止備份伺服器即可。您可以透過終止進程本身來完成。

  2. 或者,您可以在已成為主動伺服器的備份伺服器上將 allow-failback 設定為 true,這會強制備份伺服器自動停止。此設定如下所示:

    <ha-policy>
       <shared-store>
          <backup>
             <allow-failback>true</allow-failback>
          </backup>
       </shared-store>
    </ha-policy>

在共享儲存的情況下,也可以在正常伺服器關閉時觸發容錯移轉,若要啟用此功能,請在 primarybackupha-policy 設定中將以下屬性設定為 true,如下所示:

<ha-policy>
   <shared-store>
      <primary>
         <failover-on-shutdown>true</failover-on-shutdown>
      </primary>
   </shared-store>
</ha-policy>

預設情況下,此設定為 false。如果碰巧您已將此設定為 false,但仍然想正常停止伺服器並觸發容錯移轉,則可以使用 管理 中說明的方式,使用管理 API 來執行。

您還可以強制主動備份伺服器在主要伺服器恢復運作時關閉,從而允許主要伺服器自動接管,方法是在 broker.xml 設定檔中設定以下屬性,如下所示:

<ha-policy>
   <shared-store>
      <backup>
         <allow-failback>true</allow-failback>
      </backup>
   </shared-store>
</ha-policy>

3.2. 使用複製進行回復

與共享儲存一樣,可以為仲裁投票和可插拔鎖管理器複製設定設定 allow-failback 選項。

3.2.1. 仲裁投票

<ha-policy>
   <replication>
      <backup>
         <allow-failback>true</allow-failback>
      </backup>
   </replication>
</ha-policy>

對於仲裁投票複製,您需要在 primary 設定中設定一個額外的屬性 check-for-active-servertrue。如果設定為 true,則在啟動期間,主要伺服器將首先使用其節點 ID 在叢集中搜尋另一個活動的伺服器。如果找到,它將聯絡該伺服器並嘗試「回復」。由於這是一個遠端複製場景,主要伺服器必須將其資料與使用其 ID 運行的備份伺服器同步。一旦它們同步完成,它將要求另一台伺服器 (它假設這是一台接管其職責的備份伺服器) 關閉,以便它接管。這是必要的,否則主要伺服器將無法知道是否發生了容錯移轉,如果發生了,接管其職責的伺服器是否仍在運行。若要在您的 broker.xml 設定檔中設定此選項,如下所示:

<ha-policy>
   <replication>
      <primary>
         <check-for-active-server>true</check-for-active-server>
      </primary>
   </replication>
</ha-policy>

請注意,如果在發生容錯移轉後重新啟動主要伺服器,則 check-for-active-server 必須true。否則,主要伺服器將重新啟動並提供備份伺服器已處理的相同訊息,導致重複。

3.2.2. 可插拔鎖管理器

仲裁投票複製與鎖管理器複製之間的一個主要區別是,對於仲裁投票,如果主要伺服器無法聯絡到任何具有其節點 ID 的活動伺服器,則它會單方面啟動。使用可插拔鎖管理器時,協調的職責會委派給第三方。沒有單方面的決定。只有當主要伺服器知道它擁有由其節點 ID 識別的最新版本日誌時,才會啟動。

簡而言之:使用可插拔鎖管理器時,主要伺服器在未經允許的情況下無法啟動

以下是一個設定範例:

<ha-policy>
   <replication>
      <manager>
        <!-- some meaningful configuration -->
      </manager>
      <primary>
         <!-- no need to check-for-active-server anymore -->
      </primary>
   </replication>
</ha-policy>

3.3. 所有共享儲存設定

3.3.1. 主要

以下列出了 HA 策略共享儲存的 primary 的所有 ha-policy 設定元素:

failover-on-shutdown

此代理程式的正常關閉是否會導致備份啟動。

如果為 false,則如果此代理程式正常關閉(例如使用 Ctrl-C),備份伺服器將保持被動狀態。請注意,如果為 false 並且您希望發生故障轉移,則可以使用管理 API,如此處所述。

如果為 true,則當此伺服器停止時,備份將啟動。

預設值為 false

wait-for-activation

如果設定為 true,則伺服器啟動將等待直到其啟動。如果設定為 false,則伺服器啟動將在背景中完成。預設值為 true

3.3.2. 備份

以下列出了 HA 策略共享儲存的 backup 的所有 ha-policy 設定元素:

failover-on-shutdown

此代理程式的正常關閉是否會導致備份啟動。

如果為 false,則如果此代理程式正常關閉(例如使用 Ctrl-C),備份伺服器將保持被動狀態。請注意,如果為 false 並且您希望發生故障轉移,則可以使用管理 API,如此處所述。

如果為 true,則當此伺服器停止時,備份將啟動。

預設值為 false

allow-failback

當另一個伺服器發出接管其位置的請求時,伺服器是否會自動停止。使用案例是備份伺服器已容錯移轉。

3.3.3. 共置備份伺服器

在單獨執行時,也可以將備份伺服器與另一個主要伺服器共置在同一個 JVM 中。可以將主要伺服器設定為請求叢集中的另一個主要伺服器在同一個 JVM 中啟動備份伺服器,無論是使用共享儲存還是複製。新的備份伺服器將繼承其建立它的主要伺服器的設定,除了其名稱 (將設定為 colocated_backup_n,其中 n 是伺服器已建立的備份數量) 以及任何目錄和其連接器和接受器 (稍後在本章中討論) 外。還可以將主要伺服器設定為允許來自備份伺服器的請求,以及主要伺服器可以啟動的備份數量。這樣,您可以將備份均勻地分配到整個叢集。這是透過 broker.xml 檔案中的 ha-policy 元素設定的,如下所示:

<ha-policy>
   <replication>
      <colocated>
         <request-backup>true</request-backup>
         <max-backups>1</max-backups>
         <backup-request-retries>-1</backup-request-retries>
         <backup-request-retry-interval>5000</backup-request-retry-interval>
         <primary/>
         <backup/>
      </colocated>
   </replication>
</ha-policy>

上述範例設定為使用複製,在這種情況下,primarybackup 設定必須與前一章中介紹的正常複製設定匹配。也支援 shared-store

ActiveMQ Artemis ha-colocated.png

3.4. 設定連接器和接受器

如果 HA 策略是 colocated,則 connectorsacceptors 將繼承自建立它的主要伺服器,並根據 backup-port-offset 設定元素的設定進行偏移。如果將其設定為 100 (預設值),且連接器使用 61616 端口,則對於建立的第一個伺服器,將設定為 61716,對於第二個伺服器,將設定為 61816,依此類推。

對於 INVM 連接器和接受器,其 ID 將附加 colocated_backup_n,其中 n 是備份伺服器編號。

3.5. 遠端連接器

有些已設定的連接器可能是用於外部伺服器,因此應排除在偏移之外。例如,叢集連線用於為複製備份伺服器進行仲裁投票的連接器,可以透過將其添加到 ha-policy 設定中來省略偏移,如下所示:

<ha-policy>
   <replication>
      <colocated>
         ...
         <excludes>
            <connector-ref>remote-connector</connector-ref>
         </excludes>
         ...
      </colocated>
   </replication
</ha-policy>

3.6. 設定目錄

日誌、大型訊息和分頁的目錄將根據 HA 策略進行設定。如果採用共享儲存,則請求伺服器將通知目標伺服器要使用的目錄。如果設定了複製,則目錄將繼承自建立伺服器,但會附加新備份的名稱。

下表列出了共置策略的所有 ha-policy 設定元素:

request-backup

如果為 true,則伺服器將在另一個節點上請求備份。

backup-request-retries

主要伺服器嘗試請求備份的次數,-1 表示永遠。

backup-request-retry-interval

在嘗試請求備份伺服器之間等待重試的時間。

max-backups

主要伺服器可以建立的備份數量。

backup-port-offset

建立新備份伺服器時,用於連接器和接受器的偏移量。

4. 縮減規模

除了使用主要/備份群組之外,另一種替代方案是設定縮減(scaledown)。當設定為縮減時,伺服器可以將其所有訊息和交易狀態複製到另一個活動伺服器。這樣做的好處是不需要完整備份來提供某種形式的高可用性 (HA),但這種方法也有缺點,第一個缺點是它僅處理伺服器停止,而不是伺服器崩潰。這裡的重點是,如果您設定備份來縮減。

另一個缺點是可能會遺失訊息順序。這會在以下情況發生:假設您有 2 個活動伺服器,且訊息從單一生產者均勻分佈在伺服器之間,如果其中一個伺服器縮減,則發回另一個伺服器的訊息將在已經存在的訊息之後進入佇列,因此伺服器 1 可能有訊息 1、3、5、7、9,而伺服器 2 將有 2、4、6、8、10,如果伺服器 2 縮減,則伺服器 1 中的順序將為 1、3、5、7、9、2、4、6、8、10。

ActiveMQ Artemis ha-scaledown.png

活動伺服器縮減的設定如下所示

<ha-policy>
   <primary-only>
      <scale-down>
         <connectors>
            <connector-ref>server1-connector</connector-ref>
         </connectors>
      </scale-down>
   </primary-only>
</ha-policy>

在此實例中,伺服器設定為使用特定的連接器來縮減,如果未指定連接器,則會選擇第一個 INVM 連接器,這是為了使備份伺服器更容易設定縮減。也可以使用探索來縮減,如下所示

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

4.1. 使用群組縮減

也可以設定伺服器僅縮減到屬於同一群組的伺服器。這可以透過設定群組來完成,如下所示

<ha-policy>
   <primary-only>
      <scale-down>
         ...
         <group-name>my-group</group-name>
      </scale-down>
   </primary-only>
</ha-policy>

在此情況下,只有屬於 my-group 群組的伺服器才會縮減到該群組

4.2. 縮減與備份

也可以透過備份伺服器將縮減與 HA 混合使用。如果設定備份進行縮減,則在容錯移轉發生後,備份伺服器將立即縮減到另一個活動伺服器,而不是完全啟動。最適合的設定是使用 colocated 方法。這表示當您啟動主要伺服器時,它們將自動備份,並且當它們關閉時,它們的訊息將在另一個活動伺服器上可用。典型的設定如下所示

<ha-policy>
   <replication>
      <colocated>
         <backup-request-retries>44</backup-request-retries>
         <backup-request-retry-interval>33</backup-request-retry-interval>
         <max-backups>3</max-backups>
         <request-backup>false</request-backup>
         <backup-port-offset>33</backup-port-offset>
         <primary>
            <group-name>purple</group-name>
            <check-for-active-server>true</check-for-active-server>
            <cluster-name>abcdefg</cluster-name>
         </primary>
         <backup>
            <group-name>tiddles</group-name>
            <max-saved-replicated-journals-size>22</max-saved-replicated-journals-size>
            <cluster-name>33rrrrr</cluster-name>
            <restart-backup>false</restart-backup>
            <scale-down>
               <!--a grouping of servers that can be scaled down to-->
               <group-name>boo!</group-name>
               <!--either a discovery group-->
               <discovery-group-ref discovery-group-name="wahey"/>
            </scale-down>
         </backup>
      </colocated>
   </replication>
</ha-policy>

4.3. 縮減與用戶端

當伺服器停止並準備縮減時,它會向所有用戶端傳送訊息,通知它們它正在縮減到哪個伺服器,然後斷開它們的連線。此時,用戶端將重新連線,但是只有在伺服器完成縮減程序後才會成功。這是為了確保當用戶端重新連線時,任何狀態(例如佇列或交易)都存在。重新連線時會套用正常的重新連線設定,因此這些設定應足夠高,以處理縮減所需的時間。

5. 用戶端容錯移轉

Apache ActiveMQ Artemis 用戶端可以設定為接收所有主要和備份伺服器的資訊,以便在發生連線失敗時,用戶端會偵測到此情況並重新連線到備份伺服器。然後,備份伺服器將自動重新建立容錯移轉之前在每個連線上存在的任何會話和消費者,從而讓使用者不必手動編寫重新連線邏輯。如需更多詳細資訊,請參閱 用戶端容錯移轉

關於無縫容錯移轉的說明

Apache ActiveMQ Artemis 不會在活動伺服器和被動伺服器之間複製完整的伺服器狀態。當核心用戶端在備份上自動建立新會話時,該會話將不包含任何關於先前會話中已傳送或已確認訊息的資訊。如果在容錯移轉時未寫入儲存,則任何進行中的傳送或確認也會遺失。

理論上,我們可以提供 100% 透明的無縫容錯移轉,從而避免遺失任何訊息或確認。但是,這需要付出巨大的代價:複製完整的伺服器狀態(包括佇列、會話等)。這將需要將主要伺服器上的每個操作以完全相同的全域順序複製到備份伺服器,以確保狀態一致。這在效能和可擴展性方面非常難以實現,尤其是在考慮到多個執行緒同時變更活動伺服器的狀態時。

可以使用諸如虛擬同步之類的技術來提供複製完整狀態機,但是這無法很好地擴展,並且有效地將所有操作序列化為單一執行緒,從而大大降低並行性。

存在用於多執行緒使用案例的其他技術,例如複製鎖定狀態或執行緒排程,但是在 Java 層級很難實現這一點。

因此,已決定不值得為了 100% 透明的容錯移轉而大幅降低效能和並行性。即使沒有 100% 透明的容錯移轉,也可以透過使用重複偵測和重試交易的組合來保證一次且僅一次的傳遞,即使在發生故障的情況下也是如此。但是,這對於用戶端程式碼而言並非 100% 透明。

5.1. 處理容錯移轉期間的封鎖呼叫

如果用戶端程式碼處於對伺服器的封鎖呼叫中,等待回應以繼續執行,則當容錯移轉發生時,新會話將不知道正在進行的呼叫。否則,此呼叫可能會永遠掛起,等待永遠不會到來的回應。

為了防止這種情況,Apache ActiveMQ Artemis 會透過使它們擲回 javax.jms.JMSException(如果使用 JMS)或錯誤碼為 ActiveMQException.UNBLOCKEDActiveMQException,來取消封鎖容錯移轉時正在進行的任何封鎖呼叫。由用戶端程式碼來捕獲此例外狀況,並在需要時重試任何操作。

如果被取消封鎖的方法是呼叫 commit() 或 prepare(),則交易將自動回滾,並且 Apache ActiveMQ Artemis 將擲回 javax.jms.TransactionRolledBackException(如果使用 JMS)或錯誤碼為 ActiveMQException.TRANSACTION_ROLLED_BACKActiveMQException(如果使用核心 API)。

5.2. 處理容錯移轉與交易

如果會話是交易性的,並且訊息已在目前交易中傳送或確認,則伺服器無法確定在容錯移轉期間是否遺失了已傳送的訊息或確認。

因此,交易將被標記為僅回滾,並且任何後續嘗試提交它都將擲回 javax.jms.TransactionRolledBackException(如果使用 JMS)或錯誤碼為 ActiveMQException.TRANSACTION_ROLLED_BACKActiveMQException(如果使用核心 API)。

此規則的注意事項是,當透過 JMS 或核心 API 使用 XA 時。如果使用 2 階段提交,並且已呼叫 prepare,則回滾可能會導致 HeuristicMixedException。因此,提交將擲回 XAException.XA_RETRY 例外狀況。這會通知交易管理員,應在稍後的時間點重試提交,其副作用是任何非持久訊息都將遺失。為了避免這種情況,請在使用 XA 時使用持久訊息。由於確認會在呼叫 prepare 之前刷新到伺服器,因此確認沒有問題。

由使用者來捕獲例外狀況,並根據需要執行任何用戶端本地回滾程式碼。無需手動回滾會話,它已經回滾。然後,使用者可以僅在同一會話上再次重試交易操作。

Apache ActiveMQ Artemis 附帶一個功能完善的範例,說明如何執行此操作,請參閱 範例章節。

如果在執行提交呼叫時發生容錯移轉,則伺服器(如先前所述)將取消封鎖呼叫以防止掛起,因為不會傳回任何回應。在這種情況下,用戶端很難確定交易提交是否在發生故障之前實際處理完畢。

如果透過 JMS 或核心 API 使用 XA,則會擲回 XAException.XA_RETRY。這是為了通知交易管理員應在某個時間點進行重試。在稍後的時間點,交易管理員將重試提交。如果未發生原始提交,則它仍然存在並提交,如果它不存在,則假定它已提交,儘管交易管理員可能會記錄警告。

為了補救這種情況,用戶端可以簡單地在交易中啟用重複偵測(重複訊息偵測),並在呼叫取消封鎖後再次重試交易操作。如果交易確實已在容錯移轉之前成功提交,則在重試交易時,重複偵測將確保交易中重新傳送的任何持久訊息在伺服器上被忽略,以防止它們被多次傳送。

透過捕獲回滾例外狀況並重試,捕獲未封鎖的呼叫並啟用重複偵測,可以在發生故障的情況下為訊息提供一次且僅一次的傳遞保證,從而保證 100% 不會遺失或重複訊息。

5.2.1. 處理容錯移轉與非交易性會話

如果會話是非交易性的,則在發生容錯移轉時可能會遺失訊息或確認。

如果您也希望為非交易會話提供一次且僅一次的傳遞保證,請啟用重複偵測,並捕獲 處理容錯移轉期間的封鎖呼叫 中所述的取消封鎖例外狀況

5.2.2. 使用用戶端連接器進行容錯移轉

Apache ActiveMQ Artemis 客戶端會從叢集代理程式發送的拓樸更新中檢索備份連接器。如果客戶端的連線選項與叢集代理程式的選項不符,客戶端可以定義一個客戶端連接器,該連接器將取代拓樸中的連接器。若要定義客戶端連接器,它必須具有與代理程式的 cluster-connection 中定義的連接器名稱相符的名稱,例如,假設有一個主要代理程式的叢集連接器名稱為 node-0,而備份代理程式的 cluster-connector 名稱為 node-1,則客戶端連線 URL 必須定義兩個名稱為 node-0node-1 的連接器。

主要代理程式設定

<connectors>
   <!-- Connector used to be announced through cluster connections and notifications -->
   <connector name="node-0">tcp://127.0.0.1:61616</connector>
</connectors>
...
<cluster-connections>
   <cluster-connection name="my-cluster">
      <connector-ref>node-0</connector-ref>
      ...
   </cluster-connection>
</cluster-connections>

備份代理程式設定

<connectors>
    <!-- Connector used to be announced through cluster connections and notifications -->
    <connector name="node-1">tcp://127.0.0.1:61617</connector>
</connectors>
<cluster-connections>
   <cluster-connection name="my-cluster">
      <connector-ref>node-1</connector-ref>
      ...
   </cluster-connection>
</cluster-connections>

客戶端連線 URL

(tcp://127.0.0.1:61616?name=node-0,tcp://127.0.0.1:61617?name=node-1)?ha=true&reconnectAttempts=-1

5.3. 取得連線失敗通知

JMS 提供了一種標準機制,用於非同步取得連線失敗的通知:java.jms.ExceptionListener。請查閱 JMS javadoc 或任何良好的 JMS 教學,以取得有關如何使用此機制的更多資訊。

Apache ActiveMQ Artemis 核心 API 也提供了類似的功能,形式為 org.apache.activemq.artemis.core.client.SessionFailureListener 類別。

任何 ExceptionListener 或 SessionFailureListener 實例都會在連線失敗時始終由 ActiveMQ Artemis 呼叫,**無論** 連線是否成功容錯移轉、重新連線或重新附加。然而,您可以透過 SessionfailureListenerconnectionFailed 中傳入的 failedOver 旗標,或檢查 javax.jms.JMSException 的錯誤代碼(將會是以下其中一個)來判斷是否發生重新連線或重新附加。

JMSException 錯誤代碼

FAILOVER

已發生容錯移轉,並且我們已成功重新附加或重新連線。

DISCONNECT

未發生容錯移轉,並且我們已斷線。

5.4. 應用程式層級容錯移轉

在某些情況下,您可能不希望自動客戶端容錯移轉,而寧願自己處理任何連線失敗,並在自己的失敗處理程式中編寫自己的手動重新連線邏輯。我們將此定義為應用程式層級容錯移轉,因為容錯移轉是在使用者應用程式層級處理的。

若要實作應用程式層級容錯移轉,如果您使用的是 JMS,則需要在 JMS 連線上設定一個 ExceptionListener 類別。當偵測到連線失敗時,Apache ActiveMQ Artemis 將會呼叫 ExceptionListener。在您的 ExceptionListener 中,您將會關閉舊的 JMS 連線,可能會從 JNDI 查詢新的連線工廠實例,並建立新的連線。

如需應用程式層級容錯移轉的工作範例,請參閱應用程式層級容錯移轉範例

如果您使用的是核心 API,則程序非常相似:您會在核心 ClientSession 實例上設定一個 FailureListener