SpringCloud 系統(tǒng)錯(cuò)誤處理

2023-11-26 16:18 更新

系統(tǒng)級錯(cuò)誤處理意味著將錯(cuò)誤傳遞回消息傳遞系統(tǒng),并且鑒于并非每個(gè)消息傳遞系統(tǒng)都相同,因此各個(gè)粘合劑的功能可能有所不同。

也就是說,在本節(jié)中,我們解釋了系統(tǒng)級錯(cuò)誤處理背后的一般思想,并以Rabbit活頁夾為例。注意:Kafka活頁夾提供了類似的支持,盡管某些配置屬性確實(shí)有所不同。另外,有關(guān)更多詳細(xì)信息和配置選項(xiàng),請參見各個(gè)活頁夾的文檔。

如果未配置內(nèi)部錯(cuò)誤處理程序,則錯(cuò)誤將傳播到綁定程序,而綁定程序隨后會(huì)將這些錯(cuò)誤傳播回消息傳遞系統(tǒng)。根據(jù)消息傳遞系統(tǒng)的功能,此類系統(tǒng)可能會(huì)丟棄該消息,重新排隊(duì)該消息以進(jìn)行重新處理或將失敗的消息發(fā)送給DLQ。Rabbit和Kafka都支持這些概念。但是,其他聯(lián)編程序可能沒有,因此請參閱您單獨(dú)的聯(lián)編程序的文檔,以獲取有關(guān)受支持的系統(tǒng)級錯(cuò)誤處理選項(xiàng)的詳細(xì)信息。

刪除失敗的消息

默認(rèn)情況下,如果未提供其他系統(tǒng)級配置,則消息傳遞系統(tǒng)將丟棄失敗的消息。盡管在某些情況下可以接受,但在大多數(shù)情況下是不可接受的,我們需要一些恢復(fù)機(jī)制來避免消息丟失。

DLQ-死信隊(duì)列

DLQ允許將失敗的消息發(fā)送到特殊目標(biāo):-Dead Letter Queue。

配置后,失敗的消息將發(fā)送到此目標(biāo),以進(jìn)行后續(xù)的重新處理或?qū)徍伺c對帳。

例如,繼續(xù)前面的示例,并使用Rabbit活頁夾設(shè)置DLQ,您需要設(shè)置以下屬性:

spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true

請記住,在以上屬性中,input對應(yīng)于輸入目標(biāo)綁定的名稱。consumer指示它是消費(fèi)者屬性,auto-bind-dlq指示綁定程序?yàn)?code class="literal" i="1670">input目標(biāo)配置DLQ,這將導(dǎo)致名為input.myGroup.dlq的附加Rabbit隊(duì)列。

配置完成后,所有失敗的消息都會(huì)通過錯(cuò)誤消息路由到此隊(duì)列,類似于以下內(nèi)容:

delivery_mode:	1
headers:
x-death:
count:	1
reason:	rejected
queue:	input.hello
time:	1522328151
exchange:
routing-keys:	input.myGroup
Payload {"name”:"Bob"}

從上面可以看到,原始消息會(huì)保留下來以供進(jìn)一步操作。

但是,您可能已經(jīng)注意到的一件事是,有關(guān)消息處理的原始問題的信息有限。例如,您看不到與原始錯(cuò)誤相對應(yīng)的堆棧跟蹤。要獲取有關(guān)原始錯(cuò)誤的更多相關(guān)信息,您必須設(shè)置一個(gè)附加屬性:

spring.cloud.stream.rabbit.bindings.input.consumer.republish-to-dlq=true

這樣做會(huì)強(qiáng)制內(nèi)部錯(cuò)誤處理程序在將錯(cuò)誤消息發(fā)布到DLQ之前攔截該錯(cuò)誤消息并向其添加其他信息。配置完成后,您會(huì)看到錯(cuò)誤消息包含與原始錯(cuò)誤有關(guān)的更多信息,如下所示:

delivery_mode:	2
headers:
x-original-exchange:
x-exception-message:	has an error
x-original-routingKey:	input.myGroup
x-exception-stacktrace:	org.springframework.messaging.MessageHandlingException: nested exception is
      org.springframework.messaging.MessagingException: has an error, failedMessage=GenericMessage [payload=byte[15],
      headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=input.hello, amqp_deliveryTag=1,
      deliveryAttempt=3, amqp_consumerQueue=input.hello, amqp_redelivered=false, id=a15231e6-3f80-677b-5ad7-d4b1e61e486e,
      amqp_consumerTag=amq.ctag-skBFapilvtZhDsn0k3ZmQg, contentType=application/json, timestamp=1522327846136}]
      at org.spring...integ...han...MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:107)
      at. . . . .
Payload {"name”:"Bob"}

這有效地結(jié)合了應(yīng)用程序級和系統(tǒng)級的錯(cuò)誤處理,以進(jìn)一步協(xié)助下游故障排除機(jī)制。

重新排隊(duì)失敗的消息

如前所述,當(dāng)前支持的活頁夾(Rabbit和Kafka)依靠RetryTemplate來促進(jìn)成功的消息處理。有關(guān)詳細(xì)信息,請參見“重試模板”。但是,對于max-attempts屬性設(shè)置為1的情況,將禁用消息的內(nèi)部重新處理。此時(shí),您可以通過指示消息傳遞系統(tǒng)重新排隊(duì)失敗的消息來促進(jìn)消息的重新處理(重試)。重新排隊(duì)后,失敗的消息將被發(fā)送回原始處理程序,從而創(chuàng)建一個(gè)重試循環(huán)。

如果錯(cuò)誤的性質(zhì)與某些資源的偶發(fā)性但短期不可用有關(guān),則此選項(xiàng)可能是可行的。

為此,必須設(shè)置以下屬性:

spring.cloud.stream.bindings.input.consumer.max-attempts=1
spring.cloud.stream.rabbit.bindings.input.consumer.requeue-rejected=true

在前面的示例中,max-attempts設(shè)置為1,實(shí)際上禁用了內(nèi)部重試,而requeue-rejected重新排隊(duì)拒絕消息的縮寫)被設(shè)置為true設(shè)置后,失敗的消息將重新提交給同一處理程序并連續(xù)循環(huán),直到處理程序拋出AmqpRejectAndDontRequeueException為止,從本質(zhì)上講,您可以在處理程序本身內(nèi)構(gòu)建自己的重試邏輯。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)