訊息重新傳遞和 DLQ 處理

開發者 > 開發者指南 > 設計文件 > 訊息重新傳遞和 DLQ 處理

概述

當發生以下任何情況時,訊息會重新傳遞給客戶端

  1. 使用交易式會話且呼叫了 rollback()
  2. 在呼叫 commit() 之前關閉了交易式會話。
  3. 會話正在使用 CLIENT_ACKNOWLEDGE 且呼叫了 Session.recover()
  4. 客戶端連線逾時(可能是執行的程式碼耗時超過了設定的逾時時間)。

代理程式會在他的 BrokerInfo 命令封包中傳輸他偏好的預設傳遞原則給客戶端連線。但客戶端可以使用 ActiveMQConnection.getRedeliveryPolicy() 方法覆寫原則設定

RedeliveryPolicy policy = connection.getRedeliveryPolicy();
policy.setInitialRedeliveryDelay(500);
policy.setBackOffMultiplier(2);
policy.setUseExponentialBackOff(true);
policy.setMaximumRedeliveries(2);

一旦訊息的重新傳遞嘗試次數超過為 重新傳遞原則設定的 maximumRedeliveries,就會將「毒藥 ACK」傳送回代理程式,讓他知道該訊息被視為毒藥。然後,代理程式會取得該訊息並將其傳送至死信佇列,以便稍後進行分析。

ActiveMQ Classic 中的預設死信佇列稱為 ActiveMQ.DLQ;所有無法傳遞的訊息都會被傳送到此佇列,這可能難以管理。因此,您可以在 activemq.xml 設定檔的目的地原則映射中設定 individualDeadLetterStrategy,這可讓您為給定的佇列或主題指定特定的死信佇列前綴。如果您願意,可以使用萬用字元來套用此策略,以便所有佇列都有自己的死信佇列,如下例所示。

<broker>
  
  <destinationPolicy>
    <policyMap>
      <policyEntries>
        <!-- Set the following policy on all queues using the '>' wildcard -->
        <policyEntry queue=">">
          <deadLetterStrategy>
            <!--
              Use the prefix 'DLQ.' for the destination name, and make
              the DLQ a queue rather than a topic
            -->
            <individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="true"/>
          </deadLetterStrategy>
        </policyEntry>
      </policyEntries>
    </policyMap>
  </destinationPolicy>
  
</broker>

請參閱 重新傳遞原則 章節,以取得有關原則選項的更多詳細資訊。

自動捨棄過期的訊息

有些人只需要捨棄過期的訊息,而不是將其傳送到 DLQ,即完全跳過 DLQ。這簡化了 DLQ 的管理,因此您不必篩選大量的過期訊息來尋找真正有問題的訊息。要告知 ActiveMQ Classic 只捨棄過期的訊息,請在死信策略上將 processExpired 屬性設定為 false

<broker>
  
  <destinationPolicy>
   <policyMap>
     <policyEntries>
       <!-- Set the following policy on all queues using the '>' wildcard -->
       <policyEntry queue=">">
         <!-- 
           Tell the dead letter strategy not to process expired messages
           so that they will just be discarded instead of being sent to
           the DLQ 
         -->
         <deadLetterStrategy>
           <sharedDeadLetterStrategy processExpired="false" />
         </deadLetterStrategy>
       </policyEntry>
     </policyEntries>
   </policyMap>
  </destinationPolicy>
  
</broker>

將非持久性訊息放入死信佇列

預設情況下,ActiveMQ Classic 不會將無法傳遞的非持久性訊息放入死信佇列。此行為的理由是,如果應用程式不在乎是否將訊息設定為持久性,那麼記錄該訊息無法傳遞就沒有什麼價值。如果您確實想要將非持久性訊息放入死信佇列,則應在死信策略上設定 processNonPersistent="true"

<broker>
  
  <destinationPolicy>
   <policyMap>
     <policyEntries>
       <!-- Set the following policy on all queues using the '>' wildcard -->
       <policyEntry queue=">">
         <!-- 
           Tell the dead letter strategy to also place non-persisted messages 
           onto the dead-letter queue if they can't be delivered.
         -->
         <deadLetterStrategy>
           <sharedDeadLetterStrategy processNonPersistent="true" />
         </deadLetterStrategy>
       </policyEntry>
     </policyEntries>
   </policyMap>
  </destinationPolicy>
  
</broker>

設定 DLQ 中訊息的到期時間

預設情況下,ActiveMQ Classic 將永遠不會使傳送到 DLQ 的訊息過期。但是,從 ActiveMQ Classic 5.12 開始,deadLetterStrategy 支援 expiration 屬性,其值以毫秒為單位。

請謹慎選擇如何套用此設定。尤其不要透過在預設或包含萬用字元原則項目上設定到期時間,將到期時間套用至您的 DLQ 目的地。

如果 DLQ 項目到期並轉送到具有到期時間的相同或另一個 DLQ,您將會引入一個循環,如果策略稽核已停用或其滑動視窗超出限制,則可能會產生問題。

<broker>
  
  <destinationPolicy>
   <policyMap>
     <policyEntries>
       <policyEntry queue="QueueWhereItIsOkToExpireDLQEntries">
         <deadLetterStrategy>
           <.... expiration="300000"/>
         </deadLetterStrategy>
       </policyEntry>
     </policyEntries>
   </policyMap>
  </destinationPolicy>
  
</broker>

訊息稽核

死信策略具有預設啟用的訊息稽核。這可防止將重複的訊息新增至設定的 DLQ。從 5.15.0 開始,可以使用

maxProducersToAuditmaxAuditDepth 屬性來設定稽核的限制。可以使用 enableAudit="false" 來停用稽核

捨棄 DLQ 外掛程式

從 ActiveMQ Classic 5.9 開始,目的地 policyEntry 支援捨棄的 deadLetterStrategy

<deadLetterStrategy>
  <discarding/>
</deadLetterStrategy>

這與外掛程式的作用相同,但以每個目的地為基礎。外掛程式基於規則運算式的比對比目的地比對更強大,因此在某些情況下,外掛程式可能仍然有用。

一個非常簡單但非常實用的代理程式外掛程式。此外掛程式允許根據 Java SE 規則運算式設定佇列和主題,全部或比對,以捨棄已傳送到 DLQ 的訊息。當使用持續未處理訊息限制策略或其他清除規則時,這非常有用,但您不想因為需要另一個消費者來清除 DLQ 而產生額外負擔。

以下是捨棄所有內容的基本設定範例

<beans> 
  <broker>
    <plugins>
      <discardingDLQBrokerPlugin dropAll="true" dropTemporaryTopics="true" dropTemporaryQueues="true"/>
    </plugins>
  </broker>
</beans>

以下是一個稍微複雜的範例

<beans> 
  <broker>
    <plugins>
      <discardingDLQBrokerPlugin dropOnly="MY.EXAMPLE.TOPIC.29 MY.EXAMPLE.QUEUE.87" reportInterval="1000"/>
    </plugins>
  </broker>
</beans>
  • 請注意,目的地名稱是以空格分隔。
  • reportInterval 屬性用於表示我們輸出已捨棄多少訊息的頻率 - 使用 0 停用。

以下是一個更複雜的範例

<beans> 
  <broker>
    <plugins>
      <discardingDLQBrokerPlugin dropOnly="MY.EXAMPLE.TOPIC.[0-9]{3} MY.EXAMPLE.QUEUE.[0-9]{3}" reportInterval="3000"/>
    </plugins>
  </broker>
</beans>
  • 請注意,目的地名稱使用規則運算式。這些比對每個目的地名稱結尾的數字 000..999

如需更多資訊,請參閱 DiscardingDLQBrokerPluginDiscardingDLQBroker 的原始碼

代理程式重新傳遞 (v5.7)

通常,消費者會處理重新傳遞,以便在訊息在代理程式上顯示為未處理時,維持訊息順序。這表示重新傳遞僅限於單一消費者,除非該消費者終止。這樣,代理程式就不知道重新傳遞。透過代理程式重新傳遞,可以在延遲後使用重新傳送,讓代理程式重新傳遞訊息。這是透過代理程式外掛程式實作的,該外掛程式透過排程器處理重新傳遞的死信處理。當總訊息順序不重要,並且需要在消費者之間實現吞吐量和負載分佈時,這非常有用。透過代理程式重新傳遞,可以立即重新分派傳遞給指定消費者的失敗訊息。

此功能透過 XML 設定啟用,如下所示

<broker schedulerSupport="true">
        
        <plugins>
            <redeliveryPlugin fallbackToDeadLetter="true" 
                              sendToDlqIfMaxRetriesExceeded="true">
                <redeliveryPolicyMap>
                    <redeliveryPolicyMap>
                        <redeliveryPolicyEntries>
                            <!-- a destination specific policy -->
                            <redeliveryPolicy queue="SpecialQueue" 
                                              maximumRedeliveries="4" 
                                              redeliveryDelay="10000"/>
                        </redeliveryPolicyEntries>
                        
                        <defaultEntry>
                            <!-- the fallback policy for all other destinations -->
                            <redeliveryPolicy maximumRedeliveries="4" 
                                              initialRedeliveryDelay="5000"
                                              redeliveryDelay="10000"/>
                        </defaultEntry>
                    </redeliveryPolicyMap>
                </redeliveryPolicyMap>
            </redeliveryPlugin>
        </plugins>
        
</broker> 

已擴充熟悉的 重新傳遞原則,以接受相符的目的地。fallbackToDeadLetter 控制當沒有相符的目的地重新傳遞原則時要採取的動作。預設為 true,因此會進行正常的 DLQ 處理。sendToDlqIfMaxRetriesExceeded 控制當超過重試限制時要採取的動作。預設為 true,因此會進行正常的 DLQ 處理。當 false 時,會捨棄訊息。

ActiveMQ Classic 的 schedulerSupport 必須啟用,此功能才能運作。

Apache、ActiveMQ、Apache ActiveMQ、Apache 羽毛標誌和 Apache ActiveMQ 專案標誌是 Apache 軟體基金會的商標。版權所有 © 2024,Apache 軟體基金會。在 Apache 授權 2.0 下授權。