【问题标题】:NullPointerException from AbstractAggregatingMessageGroupProcessor when using Kafka Message Bus使用 Kafka 消息总线时来自 AbstractAggregatingMessageGroupProcessor 的 NullPointerException
【发布时间】:2016-03-16 20:09:15
【问题描述】:

很确定这是 Spring XD 中的一个错误。

在 SingleNode 模式下运行 Spring XD 1.3.0.RELEASE。除了我使用 Kafka 而不是本地传输之外,所有配置都是默认配置。相关 XD 配置:

spring:
  profiles: singlenode
xd:
  transport: kafka
  messagebus:
    kafka:
      brokers:                                 localhost:9092
      zkAddress:                               localhost:2181
      mode:                                    embeddedHeaders
      offsetManagement:                        kafkaTopic
      socketBufferSize:                        2097152
      offsetStoreTopic:                        SpringXdOffsets
      offsetStoreSegmentSize:                  25000000
      offsetStoreRetentionTime:                60000
      offsetStoreRequiredAcks:                 1
      offsetStoreMaxFetchSize:                 1048576
      offsetStoreBatchBytes:                   16384
      offsetStoreBatchTime:                    1000
      offsetUpdateTimeWindow:                  10000
      offsetUpdateCount:                       0
      offsetUpdateShutdownTimeout:             2000
      default:
        batchSize:                 16384
        batchTimeout:              0
        replicationFactor:         1
        concurrency:               1
        requiredAcks:              1
        compressionCodec:          none
        queueSize:                 8192 # must be a power of 2
        maxWait:                   100
        fetchSize:                 1048576
        minPartitionCount:         1
        durableSubscription:       false

使用聚合器创建流(直接来自参考文档):

stream create --name aggregates --definition "http | aggregator --count=3 --aggregation=T(org.springframework.util.StringUtils).collectionToDelimitedString(#this.![payload],' ') | log" --deploy

然后发送 3 个 POST:

xd:> http post --data Hello
xd:> http post --data World
xd:> http post --data !

结果是这个堆栈跟踪:

2015-12-10T17:07:11-0800 1.3.0.RELEASE ERROR pool-13-thread-1 listener.LoggingErrorHandler - Error while processing: KafkaMessage [Message(magic = 0, attributes = 0, crc = 344940496, key = null, payload = java.nio.HeapByteBuffer[pos=0 lim=81 cap=81]), KafkaMessageMetadata [offset=2, nextOffset=3, Partition[topic='aggregates.0', id=0]]
org.springframework.messaging.MessageHandlingException: error occurred in message handler [org.springframework.integration.config.AggregatorFactoryBean#0]; nested exception is java.lang.NullPointerException
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:139) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:147) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:120) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:442) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:392) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) ~[spring-messaging-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) ~[spring-messaging-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) ~[spring-messaging-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:231) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:154) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:102) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:105) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:69) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.channel.FixedSubscriberChannel.send(FixedSubscriberChannel.java:63) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) ~[spring-messaging-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) ~[spring-messaging-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) ~[spring-messaging-4.2.2.RELEASE.jar:4.2.2.RELEASE]
    at org.springframework.integration.endpoint.MessageProducerSupport.sendMessage(MessageProducerSupport.java:105) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter.access$300(KafkaMessageDrivenChannelAdapter.java:43) ~[spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter$AutoAcknowledgingChannelForwardingMessageListener.doOnMessage(KafkaMessageDrivenChannelAdapter.java:171) ~[spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.listener.AbstractDecodingMessageListener.onMessage(AbstractDecodingMessageListener.java:50) ~[spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.listener.QueueingMessageListenerInvoker$KafkaMessageDispatchingSubscriber.onNext(QueueingMessageListenerInvoker.java:221) [spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at org.springframework.integration.kafka.listener.QueueingMessageListenerInvoker$KafkaMessageDispatchingSubscriber.onNext(QueueingMessageListenerInvoker.java:209) [spring-integration-kafka-1.3.0.RELEASE.jar:na]
    at reactor.core.processor.util.RingBufferSubscriberUtils.route(RingBufferSubscriberUtils.java:67) [reactor-core-2.0.5.RELEASE.jar:na]
    at reactor.core.processor.RingBufferProcessor$BatchSignalProcessor.run(RingBufferProcessor.java:789) [reactor-core-2.0.5.RELEASE.jar:na]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_66]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_66]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_66]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_66]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_66]
Caused by: java.lang.NullPointerException: null
    at org.springframework.integration.aggregator.AbstractAggregatingMessageGroupProcessor.aggregateHeaders(AbstractAggregatingMessageGroupProcessor.java:115) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.aggregator.AbstractAggregatingMessageGroupProcessor.processMessageGroup(AbstractAggregatingMessageGroupProcessor.java:79) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.completeGroup(AbstractCorrelatingMessageHandler.java:648) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler.handleMessageInternal(AbstractCorrelatingMessageHandler.java:405) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) ~[spring-integration-core-4.2.2.RELEASE.jar:na]
    ... 32 common frames omitted

这是 Spring XD 错误吗?有解决办法吗?


更多细节。

导致 NPE 的标头是 kafka_messageKey。此标头的值为null,因此AbstractAggregatingMessageGroupProcessor:115 会抛出NPE。

进一步查看KafkaMessageBus,Kafka messageKey 似乎被 Producer 有意设置为 null。

【问题讨论】:

  • 您可能需要向我们证明指定的变量不应为空。
  • 我还尝试使用 xd.messagebus.kafka.mode=raw 启动 XD 并在每个模块上指定 --outputType=application/octet-stream 但这会导致相同的错误。
  • 当它无条件地将 messageKey 填充到 Map 时,看起来是 KafkaMessageDrivenChannelAdapter 中的错误。请针对 spring-integration-Kafka 提出 Jira。明天我会回复你一些解决方法。
  • @ArtemBilan 我打开了INTEXT-210

标签: spring apache-kafka spring-xd


【解决方案1】:

这是 Spring XD 中的一个错误。详情请见INT-3908


在 Marius 的 suggestion 之后,以下是一个合适的解决方法:

编辑$XD_HOME/modules/processor/aggregator/config/aggregator.xml 以包括:

<channel id="aggregatorInput"/>

<header-enricher input-channel="input" output-channel="aggregatorInput" default-overwrite="true">
    <header name="kafka_messageKey" value="."/>
</header-enricher>

<aggregator input-channel="aggregatorInput" output-channel="output"
    correlation-strategy-expression="${correlation}"
    release-strategy-expression="${release}" expression="${aggregation}"
    send-partial-result-on-expiry="true" expire-groups-upon-completion="true"
    message-store="messageStore">
</aggregator>

注意:使用 header-filter 将不起作用,因为 SI 用于 removing a header 的机制只能使用 remove the header if it is not already null


或者,如果您不想直接编辑模块 XML,您可以使用 Module Composition 在标准聚合器模块之前包含一个 Header Enricher。

module compose --name kafa-aggregator --definition "header-enricher --headers={\"kafka_messageKey\":\"'.'\"} --overwrite=true | aggregator --count=3 --aggregation=T(org.springframework.util.StringUtils).collectionToDelimitedString(#this.![payload],' ')"

stream create --name aggregates --definition "http | kafa-aggregator | log" --deploy

【讨论】:

  • 啊,我明白了 - 很抱歉过滤器最终没有工作,但至少很高兴让你走上了正确的道路。从长远来看,最好的做法可能是更新 Spring XD 的 Spring Integration 版本,一旦有修复的版本发布。
【解决方案2】:

一种可能的解决方法是向聚合器模块添加一个标题过滤器,方法是在$XD_HOME/modules/processor/aggregator/config/aggregator.xml 的开头插入一个标题过滤器,并按如下方式更改其开头:

<channel id="input" />

<channel id="aggregatorInput"/>

<int:header-filter input-channel="inputChannel"
    output-channel="aggregatorInput" header-names="kafka_messageKey"/>

<aggregator input-channel="aggregatorInput" output-channel="output"
            correlation-strategy-expression="${correlation}"
            release-strategy-expression="${release}" expression="${aggregation}"
            send-partial-result-on-expiry="true" expire-groups-upon-completion="true"
            message-store="messageStore">
    </aggregator>

... rest of the module definition remains unchanged ... 

至于如何在日志运行中解决这个问题,我将评论 JIRA 问题。

干杯, 马吕斯

【讨论】:

  • 有点讽刺的是,这不起作用,因为 SI 通过将标头的值设置为 null 来删除标头。
  • 实际上,更准确地说,SI 仅在标头尚未为空时才将其删除。看看我在my answer 中链接的行,你会看到。
猜你喜欢
  • 2019-12-04
  • 2020-02-22
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 2021-02-16
  • 2018-03-19
  • 2020-12-11
  • 2019-06-07
相关资源
最近更新 更多