SpringCloud 系统错误处理

2023-11-26 16:18 更新

系统级错误处理意味着将错误传递回消息传递系统,并且鉴于并非每个消息传递系统都相同,因此各个粘合剂的功能可能有所不同。

也就是说,在本节中,我们解释了系统级错误处理背后的一般思想,并以Rabbit活页夹为例。注意:Kafka活页夹提供了类似的支持,尽管某些配置属性确实有所不同。另外,有关更多详细信息和配置选项,请参见各个活页夹的文档。

如果未配置内部错误处理程序,则错误将传播到绑定程序,而绑定程序随后会将这些错误传播回消息传递系统。根据消息传递系统的功能,此类系统可能会丢弃该消息,重新排队该消息以进行重新处理或将失败的消息发送给DLQRabbit和Kafka都支持这些概念。但是,其他联编程序可能没有,因此请参阅您单独的联编程序的文档,以获取有关受支持的系统级错误处理选项的详细信息。

删除失败的消息

默认情况下,如果未提供其他系统级配置,则消息传递系统将丢弃失败的消息。尽管在某些情况下可以接受,但在大多数情况下是不可接受的,我们需要一些恢复机制来避免消息丢失。

DLQ-死信队列

DLQ允许将失败的消息发送到特殊目标:-Dead Letter Queue

配置后,失败的消息将发送到此目标,以进行后续的重新处理或审核与对帐。

例如,继续前面的示例,并使用Rabbit活页夹设置DLQ,您需要设置以下属性:

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

请记住,在以上属性中,input对应于输入目标绑定的名称。consumer指示它是消费者属性,auto-bind-dlq指示绑定程序为input目标配置DLQ,这将导致名为input.myGroup.dlq的附加Rabbit队列。

配置完成后,所有失败的消息都会通过错误消息路由到此队列,类似于以下内容:

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

从上面可以看到,原始消息会保留下来以供进一步操作。

但是,您可能已经注意到的一件事是,有关消息处理的原始问题的信息有限。例如,您看不到与原始错误相对应的堆栈跟踪。要获取有关原始错误的更多相关信息,您必须设置一个附加属性:

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

这样做会强制内部错误处理程序在将错误消息发布到DLQ之前拦截该错误消息并向其添加其他信息。配置完成后,您会看到错误消息包含与原始错误有关的更多信息,如下所示:

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"}

这有效地结合了应用程序级和系统级的错误处理,以进一步协助下游故障排除机制。

重新排队失败的消息

如前所述,当前支持的活页夹(Rabbit和Kafka)依靠RetryTemplate来促进成功的消息处理。有关详细信息请参见“重试模板”但是,对于max-attempts属性设置为1的情况,将禁用消息的内部重新处理。此时,您可以通过指示消息传递系统重新排队失败的消息来促进消息的重新处理(重试)。重新排队后,失败的消息将被发送回原始处理程序,从而创建一个重试循环。

如果错误的性质与某些资源的偶发性但短期不可用有关,则此选项可能是可行的。

为此,必须设置以下属性:

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

在前面的示例中,max-attempts设置为1,实际上禁用了内部重试,而requeue-rejected重新排队拒绝消息的缩写)被设置为true设置后,失败的消息将重新提交给同一处理程序并连续循环,直到处理程序抛出AmqpRejectAndDontRequeueException为止,从本质上讲,您可以在处理程序本身内构建自己的重试逻辑。

以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号