Spring 使用Kafka消息总线时AbstractAggregatingMessageGroupProcessor的NullPointerException
很确定这是SpringXD中的一个bug 在单节点模式下运行Spring XD 1.3.0.RELEASE。除了我使用Kafka而不是本地传输之外,所有配置都是默认的。相关XD配置:Spring 使用Kafka消息总线时AbstractAggregatingMessageGroupProcessor的NullPointerException,spring,apache-kafka,spring-xd,Spring,Apache Kafka,Spring Xd,很确定这是SpringXD中的一个bug 在单节点模式下运行Spring XD 1.3.0.RELEASE。除了我使用Kafka而不是本地传输之外,所有配置都是默认的。相关XD配置: spring: profiles: singlenode xd: transport: kafka messagebus: kafka: brokers: localhost:9092 zkAddress:
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
使用聚合器创建流(此聚合器直接来自参考文档):
然后发送3个帖子:
xd:> http post --data Hello
xd:> http post --data World
xd:> http post --data !
结果是stacktrace:
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\u messageKey
。此标头的值为null
,因此抛出NPE
进一步看,Kafka似乎有意从制作人处设置为null。一种可能的解决方法是,通过在
$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问题进行评论
干杯,
马吕斯这是Spring XD中的一个bug。有关详细信息,请参阅
根据马吕斯的建议,以下是一个合适的解决方法: 编辑
$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>
您可能需要向我们证明指定的变量不应为null。我还尝试使用
XD.messagebus.kafka.mode=raw
启动XD,并在每个模块上指定--outputType=application/octet stream
,但这导致了相同的错误。看起来这是KafkaMessageDrivenChannelAdapter中的错误无条件地将messageKey填充到映射。请再就这件事向卡夫卡提起诉讼。明天我会给你一些解决方法。@ArtemBilan我打开了有点讽刺意味的一点,这不起作用,因为SI通过将标题的值设置为null来删除标题。实际上,更准确地说,SI只在标题不为null时删除标题。看看我在中链接的行,你会看到。啊,我明白了-很抱歉,过滤器最终没有工作,但至少很高兴让你走上了正确的轨道。从长远来看,最好的做法可能是,一旦发布了带有修复程序的版本,就更新SpringXD的Spring集成版本。
<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>
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