訊息重新傳遞和 DLQ 處理
開發者 > 開發者指南 > 設計文件 > 訊息重新傳遞和 DLQ 處理
概述
當發生以下任何情況時,訊息會重新傳遞給客戶端
- 使用交易式會話且呼叫了
rollback()
。 - 在呼叫
commit()
之前關閉了交易式會話。 - 會話正在使用
CLIENT_ACKNOWLEDGE
且呼叫了Session.recover()
。 - 客戶端連線逾時(可能是執行的程式碼耗時超過了設定的逾時時間)。
代理程式會在他的 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 開始,可以使用
maxProducersToAudit
和 maxAuditDepth
屬性來設定稽核的限制。可以使用 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
。
如需更多資訊,請參閱 DiscardingDLQBrokerPlugin 和 DiscardingDLQBroker 的原始碼
代理程式重新傳遞 (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
必須啟用,此功能才能運作。