You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kafka Streams中Double类型反序列化异常问题求助

解决Kafka Streams中Double类型反序列化异常问题

问题根源

报错Size of data received by Deserializer is not 8的核心原因是:

  • Kafka的DoubleDeserializer要求输入必须是固定8字节的二进制Double值(Java中Double类型的原生二进制表示)。
  • 你通过kafka-console-producer发送的是字符串形式的数字(如Test:12.34),这些内容被默认序列化为UTF-8字节数组,长度不等于8,因此触发反序列化失败。

即使你指定了value.serializer=org.apache.kafka.common.serialization.DoubleSerializer,console producer也无法将输入的字符串转换为二进制Double——因为DoubleSerializer仅接受Java Double对象作为输入,而控制台输入的是文本字符串,无法直接被该序列化器处理。


解决方案

方案一:自定义Serde处理字符串与Double的转换

如果需要继续使用kafka-console-producer发送文本格式的数据,可以自定义Serde,实现字符串到Double的解析与反向转换:

1. 实现自定义Serde

import org.apache.kafka.common.serialization.Deserializer;
import org.apache.kafka.common.serialization.Serde;
import org.apache.kafka.common.serialization.Serializer;
import java.util.Map;

public class DoubleFromStringSerde implements Serde<Double> {
    @Override
    public void configure(Map<String, ?> configs, boolean isKey) {}

    @Override
    public void close() {}

    @Override
    public Serializer<Double> serializer() {
        // 将Double转为字符串字节数组发送
        return (topic, data) -> data == null ? null : data.toString().getBytes();
    }

    @Override
    public Deserializer<Double> deserializer() {
        // 将字符串字节数组解析为Double
        return (topic, data) -> {
            if (data == null) return null;
            try {
                return Double.parseDouble(new String(data));
            } catch (NumberFormatException e) {
                throw new RuntimeException("Invalid Double string format", e);
            }
        };
    }
}

2. 修改Kafka Streams代码

将原代码中的Serdes.Double()替换为自定义Serde:

public static void main(String[] args) { 
    Properties properties = new Properties(); 
    properties.put(StreamsConfig.APPLICATION_ID_CONFIG, "test-app");    
    properties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
    
    StreamsBuilder builder = new StreamsBuilder();

    // 使用自定义Serde消费和生产
    KStream<String, Double> inputTopic = builder.stream("a-topic",   
        Consumed.with(Serdes.String(), new DoubleFromStringSerde()));
    inputTopic.print(Printed.toSysOut());
                
    inputTopic.to("b-topic", Produced.with(Serdes.String(), new DoubleFromStringSerde()));
    
    Topology topology = builder.build();
    KafkaStreams kafkaStreams = new KafkaStreams(topology, properties);
    kafkaStreams.start();
    Runtime.getRuntime().addShutdownHook(new Thread(() -> kafkaStreams.close()));
} 

方案二:使用Java生产者发送原生二进制Double

如果希望使用Kafka原生的DoubleSerializer/DoubleDeserializer,需要编写专门的Java生产者程序,直接发送Double类型的value:

Java生产者示例

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.DoubleSerializer;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Properties;

public class DoubleProducer {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", StringSerializer.class.getName());
        props.put("value.serializer", DoubleSerializer.class.getName());

        try (Producer<String, Double> producer = new KafkaProducer<>(props)) {
            producer.send(new ProducerRecord<>("a-topic", "Test", 12.34));
            producer.send(new ProducerRecord<>("a-topic", "Test2", 123.454));
            producer.send(new ProducerRecord<>("a-topic", "Test3", 12345.321));
            System.out.println("Messages sent successfully");
        }
    }
}

这种情况下,你的原Kafka Streams代码无需修改——生产者发送的是8字节的二进制Double,完全符合DoubleDeserializer的要求。


内容的提问来源于stack exchange,提问作者IronMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:38:13