SpringCloud 系统错误处理
系统级错误处理意味着将错误传递回消息传递系统,并且鉴于并非每个消息传递系统都相同,因此各个粘合剂的功能可能有所不同。
也就是说,在本节中,我们解释了系统级错误处理背后的一般思想,并以Rabbit活页夹为例。注意:Kafka活页夹提供了类似的支持,尽管某些配置属性确实有所不同。另外,有关更多详细信息和配置选项,请参见各个活页夹的文档。
如果未配置内部错误处理程序,则错误将传播到绑定程序,而绑定程序随后会将这些错误传播回消息传递系统。根据消息传递系统的功能,此类系统可能会丢弃该消息,重新排队该消息以进行重新处理或将失败的消息发送给DLQ。Rabbit和Kafka都支持这些概念。但是,其他联编程序可能没有,因此请参阅您单独的联编程序的文档,以获取有关受支持的系统级错误处理选项的详细信息。
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
为止,从本质上讲,您可以在处理程序本身内构建自己的重试逻辑。
更多建议: