简体   繁体   English

Spring 云 Stream - 如何处理下游块?

[英]Spring Cloud Stream - how to handle downstream blocks?

During a planned downtime for our Kafka cluster, we basically encountered the following issue How to specify timeout for sending message to RabbitMQ using Spring Cloud Stream?在我们的 Kafka 集群计划停机期间,我们基本上遇到了以下问题如何使用 Spring Cloud Stream 指定向 RabbitMQ 发送消息的超时时间? (with Kafka rather than RabbitMQ, obviously). (显然,使用 Kafka 而不是 RabbitMQ)。

The answer from @GaryRussell: @GaryRussell 的回答:

The channel sendTimeout only applies if the channel itself can block, eg a QueueChannel with a bounded queue that is currently full;通道sendTimeout仅适用于通道本身可以阻塞的情况,例如当前已满的有界队列的QueueChannel the caller will block until either space becomes available in the queue, or the timeout occurs.调用者将阻塞,直到队列中有可用空间,或者发生超时。

In this case, the block is downstream of the channel so the sendTimeout is irrelevant (in any case, it's a DirectChannel which can't block anyway, the subscribed handler is called directly on the calling thread).在这种情况下,块位于通道的下游,因此 sendTimeout 是无关紧要的(无论如何,它是一个 DirectChannel,无论如何都不能阻塞,订阅的处理程序直接在调用线程上调用)。

The actual blocking you are seeing is most likely in the socket.write() in the rabbitmq client, which does not have a timeout and is not interruptible;您看到的实际阻塞很可能在 rabbitmq 客户端中的socket.write()中,它没有超时且不可中断; there is nothing that can be done by the calling thread to "time out" the write.调用线程无法执行任何操作来“超时”写入。

The only possible solution I am aware of is to force close the rabbit connection by calling resetConnection() on the connection factory.我知道的唯一可能的解决方案是通过在连接工厂上调用resetConnection()来强制关闭兔子连接。

explains quite well why the method in question ( org.springframework.integration.channel.AbstractSubscribableChannel#doSend ) does not take the timeout into account.很好地解释了为什么有问题的方法( org.springframework.integration.channel.AbstractSubscribableChannel#doSend )没有考虑timeout However, this still seems a bit odd to me.但是,这对我来说仍然有点奇怪。

In spring-integration-kafka-3.2.1.RELEASE-sources.jar./org/springframework/integration/kafka/outbound/KafkaProducerMessageHandler:java:566 , we can see that, if sync behaviour is desired:spring-integration-kafka-3.2.1.RELEASE-sources.jar./org/springframework/integration/kafka/outbound/KafkaProducerMessageHandler:java:566中,我们可以看到,如果需要sync行为:

565    if (this.sync) {
566        Long sendTimeout = this.sendTimeoutExpression.getValue(this.evaluationContext, message, Long.class);
567        if (sendTimeout == null || sendTimeout < 0) {
568            future.get();
569        }
570        else {
571            try {
572                future.get(sendTimeout, TimeUnit.MILLISECONDS);
573            }
574            catch (TimeoutException te) {
575                throw new MessageTimeoutException(message, "Timeout waiting for response from KafkaProducer", te);
576            }
577        }
578    }

is called, where a timeout is taken into consideration.被调用,其中考虑了超时。 The sendTimeoutExpression is assigned to a default Value: sendTimeoutExpression被分配给一个默认值:

    private static final long DEFAULT_SEND_TIMEOUT = 10000;
    private Expression sendTimeoutExpression = new ValueExpression<>(DEFAULT_SEND_TIMEOUT);

however, our stack trace reveals something different:然而,我们的堆栈跟踪揭示了一些不同的东西:

"pool-1-thread-3" - Thread t@108
   java.lang.Thread.State: TIMED_WAITING
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for <4ebda621> (a org.springframework.util.concurrent.SettableListenableFuture$SettableTask)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
    at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:426)
    at java.util.concurrent.FutureTask.get(FutureTask.java:204)
    at org.springframework.util.concurrent.SettableListenableFuture.get(SettableListenableFuture.java:134)
*   at org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler.processSendResult(KafkaProducerMessageHandler.java:572)
    at org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler.handleRequestMessage(KafkaProducerMessageHandler.java:414)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:134)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:69)
    at org.springframework.cloud.stream.binder.AbstractMessageChannelBinder$SendingHandler.handleMessageInternal(AbstractMessageChannelBinder.java:1035)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:69)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:115)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:133)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:106)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:72)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:570)

The invocation marked with * corresponds to the future.get(sendTimeout, TimeUnit.MILLISECONDS);标有*的调用对应于future.get(sendTimeout, TimeUnit.MILLISECONDS); call.称呼。

Seeing how the underlying client seems to support it (given by the fact that the future.get() call supports a timeout), how this be set?看到底层客户端似乎如何支持它(鉴于future.get()调用支持超时这一事实),如何设置? The only two properties I can find in the binder references (see here ) are spring.cloud.stream.kafka.binder.healthTimeout and batchTimeout , which as far as I can tell, do not influence this setting.我可以在活页夹参考资料中找到的唯一两个属性(参见此处)是spring.cloud.stream.kafka.binder.healthTimeoutbatchTimeout ,据我所知,这不会影响此设置。

Seeing how the KafkaProducerMessageHandler is constructed in org.springframework.cloud.stream.binder.kafka.KafkaMessageChannelBinder.ProducerConfigurationMessageHandler , a private class, bean overridding is seemingly not the recommended way.看看org.springframework.cloud.stream.binder.kafka.KafkaMessageChannelBinder.ProducerConfigurationMessageHandlerKafkaProducerMessageHandler是如何构建的,一个私有的 class,bean 覆盖似乎不是推荐的方式。

It doesn't appear to be documented, but similar to the listener container customizer https://docs.spring.io/spring-cloud-stream/docs/3.1.2/reference/html/spring-cloud-stream.html#_advanced_consumer_configuration you can add a ProducerMessageHandlerCustomizer @Bean to set arbitrary properties on the message handler.它似乎没有记录,但类似于侦听器容器定制器 https://docs.spring.io/spring-cloud-stream/docs/3.1.2/reference/html/spring-cloud-stream.html# _advanced_consumer_configuration你可以添加一个ProducerMessageHandlerCustomizer @Bean来设置消息处理程序的任意属性。

In newer versions of the handler, the timeout is always configured to be at least as much as ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG , to avoid false negatives (where the publication is successful after the handler times it out).在较新版本的处理程序中,超时始终配置为至少与ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG一样多,以避免误报(在处理程序超时后发布成功)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用Spring Cloud Stream应用启动器TCP处理消息 - How to handle message using Spring Cloud Stream app starter TCP 如何处理 Spring 云 stream kafka 流活页夹中的序列化错误? - How to handle Serialization error in Spring cloud stream kafka streams binder? Spring Cloud Stream - 注意并处理代理中的错误 - Spring Cloud Stream - notice and handle errors in broker 如何使用 JWT 令牌 Spring 云网关对下游 api 进行身份验证 - How to authenticate downstream api with JWT Token Spring Cloud Gateway 如何在 Spring 云网关中进行下游之前修改查询字符串参数 - How to modify query string parameter before making downstream in Spring cloud gateway 如何拦截Spring Cloud Stream消息? - How to intercept Spring Cloud Stream messages? 如何自动装配Spring Stream Cloud绑定 - How to autowire spring stream cloud bindings 如何记录 Spring Cloud Stream 功能? - How to log around Spring Cloud Stream functions? 如何为Spring-cloud-stream配置GlobalChannelInterceptor? - How to configure GlobalChannelInterceptor for spring-cloud-stream? 如何在 Spring Cloud Stream App 中反序列化 MessagePack - How to deserialize MessagePack in Spring Cloud Stream App
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM