Java Kafka streams错误:序列化异常:LongDeserializer接收的数据大小不是8
我正在尝试卡夫卡流。编写一个简单的应用程序,其中我正在计算重复消息 信息:Java Kafka streams错误:序列化异常:LongDeserializer接收的数据大小不是8,java,apache-kafka,apache-kafka-streams,Java,Apache Kafka,Apache Kafka Streams,我正在尝试卡夫卡流。编写一个简单的应用程序,其中我正在计算重复消息 信息: 2019-02-27-11:16:56 :: session:prod-111656 :: Msg => Hello World: 2491 2019-02-27-11:16:56 :: session:prod-111656 :: Msg => Hello World: 2492 等等 我正在尝试按会话:prod xxxx拆分此类邮件。把它当作钥匙。和session:prod xxxx+Hello Wor
2019-02-27-11:16:56 :: session:prod-111656 :: Msg => Hello World: 2491
2019-02-27-11:16:56 :: session:prod-111656 :: Msg => Hello World: 2492
等等
我正在尝试按会话:prod xxxx
拆分此类邮件。把它当作钥匙。和session:prod xxxx+Hello World:xxxx
将其用作值。然后按键分组,查看在每个会话中复制了哪些消息
代码如下:
KStream<String, String> textLines = builder.stream("RegularProducer");
KTable<String, Long> ktable = textLines.map(
(String key, String value) -> {
try {
String[] parts = value.split("::");
String sessionId = parts[1];
String message = ((parts[2]).split("=>"))[1];
message = sessionId+":"+message;
return new KeyValue<String,String>(sessionId.trim().toLowerCase(), message.trim().toLowerCase());
} catch (Exception e) {
return new KeyValue<String,String>("Invalid-Message".trim().toLowerCase(), "Invalid Message".trim().toLowerCase());
}
})
.groupBy((key,value) -> value)
.count().filter(
(String key, Long value) -> {
return value > 1;
}
);
ktable.toStream().to("RegularProducerDuplicates",
Produced.with(Serdes.String(), Serdes.Long()));
Topology topology = builder.build();
topology.describe();
KafkaStreams streams = new KafkaStreams(topology, props);
streams.start();
有谁能帮我这里出了什么问题吗?您的Kafka Streams应用程序运行正常 该错误位于
kafka控制台使用者中(kafka.tools.ConsoleConsumer
是实现脚本逻辑的类)
在反序列化过程中,它不能正确处理null
。当它获取null
作为消息的值或键时,它将设置默认值(表示null
字符串的字节数组)。如果您检查源代码,您可以找到以下函数
def write(反序列化器:选项[deserializer[\u]],sourceBytes:Array[Byte]){
val nonNullBytes=选项(sourceBytes).getOrElse(“null”.getBytes(StandardCharsets.UTF_8))
val convertedBytes=deserializer.map(u.deserialize(null,nonNullBytes).toString。
getBytes(StandardCharsets.UTF_8)).getOrElse(非空字节)
output.write(转换字节)
}
如何查看当它获取空的sourceBytes(sourceBytes==null
)进行反序列化时,它会为此设置默认值:
val nonNullBytes=Option(sourceBytes).getOrElse(“null”.getBytes(StandardCharsets.UTF_8))
在您的例子中,它是“null”.getBytes(StandardCharsets.UTF_8)
。然后,尝试使用org.apache.kafka.common.serialization.LongDeserializer
(您的值反序列化器)进行反序列化LongDeserializer
从一开始就检查字节数组的大小。现在是4(表示为null
)并引发异常
例如,如果您使用StringDeserializer,它将不会正确地对其进行反序列化,但至少不会引发异常,因为它不会检查字节数组的长度
长话短说:ConsoleConsumer的格式化程序,负责打印,为漂亮的打印设置了一些默认值,这是某些反序列化程序(LongDeserializer、IntegerDeserializer)无法处理的
关于为什么应用程序为某些键生成null
值:
KTable:filter
与KStream::filter
具有不同的语义。根据javadoc for KTable:
对于每个被删除的记录(即,不满足给定的
谓词)转发墓碑记录
对于您的过滤器
,当计数时,我遇到了同样的问题,发现如果我将过滤器
移动到流
之后,将不会生成空值(逻辑删除)。用于值的反序列化程序可能不用于字符串,并且会持续很长时间。
在cli中创建使用者时,请指定它。前-
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 \
--topic name \
--from-beginning \
--formatter kafka.tools.DefaultMessageFormatter \
--property print.key=true \
--property print.value=true \
--skip-message-on-error \
--property key.deserializer=org.apache.kafka.common.serialization.StringDeserializer \
--property value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
这里检查最后两行,在创建消费者时,注意您的(键、值)类型
在我的例子中,这两个都是字符串,如果值是长类型的,则使用最后一行作为:
--property value.deserializer=org.apache.kafka.common.serialization.LongDeserializer您正在对其进行反序列化,就好像该值是一个long。好像不是。你能告诉我在哪里吗?我对streams非常陌生,还不熟悉这种编程风格。(字符串键,长值)-->似乎值不是长的(正如反序列化程序所告诉的,它不是8字节长的值)。最肯定的是,这是一根弦。p、 s我对流也不太了解,但似乎是典型的kafka issueHmmm,因为在count()的前一步中,返回的值是类型t和Long。根据文件。真想知道这里出了什么问题。@Shades88,你能不能把用于阅读的整个命令(kafka控制台使用者)添加到这个问题上?不,即使我从一开始就没有,也会发生这种情况。对于没有计数=1或不重复的每条进线,此错误为thrown@Shades88,我更新了我的答案,解释了发生了什么。很好的解释。在这种情况下,我想分组,计数,然后过滤。因此,我将无法使用KStream::filter。那么我怎样才能避免墓碑记录呢?同样,通过这个过滤函数,我指定Kafka Streams,只给我KTable中那些值大于1的记录。我刚刚运行了一个标准Java消费程序,您是对的。有许多记录的值为null。那么过滤函数的作用是什么?@Shades88,当您将KTable
转换为KStream
时,您可以过滤掉逻辑删除代码:KTable.toStream.filter((键,值)->value!=null)
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 \
--topic name \
--from-beginning \
--formatter kafka.tools.DefaultMessageFormatter \
--property print.key=true \
--property print.value=true \
--skip-message-on-error \
--property key.deserializer=org.apache.kafka.common.serialization.StringDeserializer \
--property value.deserializer=org.apache.kafka.common.serialization.StringDeserializer