Kafka 实战 - Kafka Streams 自定义Serde

在Kafka Streams应用中,Serde(Serializer/Deserializer)负责消息的序列化与反序列化工作,确保数据在生产者、broker和消费者之间正确传输和解析。有时候,Kafka Streams提供的内置Serde可能无法满足特定数据类型的需求,此时需要自定义Serde。以下是一个自定义Serde的实战示例,假设我们有一个自定义的交易数据类Transaction

public class Transaction {
    private String accountId;
    private double amount;
    private long timestamp;

    // 构造函数、getter、setter与equals/hashCode/toString方法省略...
}

我们需要创建一个自定义的Serde,用于处理这种类型的数据。

TransactionSerde.java

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 TransactionSerde implements Serde<Transaction> {

    private final Serializer<Transaction> serializer;
    private final Deserializer<Transaction> deserializer;

    public TransactionSerde() {
        this.serializer = new TransactionSerializer();
        this.deserializer = new TransactionDeserializer();
    }

    @Override
    public void configure(Map<String, ?> configs, boolean isKey) {
        serializer.configure(configs, isKey);
        deserializer.configure(configs, isKey);
    }

    @Override
    public void close() {
        serializer.close();
        deserializer.close();
    }

    @Override
    public Serializer<Transaction> serializer() {
        return serializer;
    }

    @Override
    public Deserializer<Transaction> deserializer() {
        return deserializer;
    }

    // 自定义的序列化器
    public static class TransactionSerializer implements Serializer<Transaction> {
        @Override
        public byte[] serialize(String topic, Transaction data) {
            if (data == null) {
                return null;
            }

            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(data);
                return baos.toByteArray();
            } catch (IOException e) {
                throw new SerializationException("Error serializing Transaction to bytes", e);
            }
        }

        @Override
        public void close() {
            // 可以在这里添加关闭资源的操作,如关闭流等
        }
    }

    // 自定义的反序列化器
    public static class TransactionDeserializer implements Deserializer<Transaction> {
        @Override
        public Transaction deserialize(String topic, byte[] data) {
            if (data == null) {
                return null;
            }

            try {
                ByteArrayInputStream bais = new ByteArrayInputStream(data);
                ObjectInputStream ois = new ObjectInputStream(bais);
                return (Transaction) ois.readObject();
            } catch (IOException | ClassNotFoundException e) {
                throw new SerializationException("Error deserializing bytes to Transaction", e);
            }
        }

        @Override
        public void close() {
            // 可以在这里添加关闭资源的操作,如关闭流等
        }
    }
}

使用自定义Serde的Kafka Streams示例

import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.Printed;

import java.util.Properties;

public class TransactionProcessingDemo {

    public static void main(String[] args) {
        Properties streamsConfig = new Properties();
        streamsConfig.put(StreamsConfig.APPLICATION_ID_CONFIG, "transaction-processing");
        streamsConfig.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        streamsConfig.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
        streamsConfig.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, TransactionSerde.class);

        StreamsBuilder builder = new StreamsBuilder();

        // 使用自定义Serde的KStream
        KStream<String, Transaction> transactionStream = builder.stream("transactions", Consumed.with(Serdes.String(), new TransactionSerde()));

        // 打印交易数据到控制台
        transactionStream.print(Printed.toSysOut());

        KafkaStreams streams = new KafkaStreams(builder.build(), streamsConfig);
        streams.start();

        // 在程序退出前,优雅地关闭Kafka Streams应用
        Runtime.getRuntime().addShutdownHook(new Thread(streams::close));
    }
}

示例解析:

  1. 自定义Serde:创建TransactionSerde类,实现Serde<Transaction>接口。内部包含两个嵌套类:TransactionSerializerTransactionDeserializer,分别实现序列化和反序列化逻辑。这里使用了Java的ObjectOutputStreamObjectInputStream进行对象的序列化和反序列化。

  2. 配置自定义Serde:在Kafka Streams应用的配置中,设置DEFAULT_VALUE_SERDE_CLASS_CONFIG为自定义的TransactionSerde类。

  3. 使用自定义Serde的KStream:在创建KStream时,指定键的Serde为Serdes.String(),值的Serde为new TransactionSerde()。这样,Kafka Streams就会使用自定义的Serde处理Transaction类型的数据。

  4. 运行示例:创建Kafka Streams拓扑,打印交易数据到控制台,并启动应用。在程序退出前,注册一个shutdown hook以优雅地关闭Kafka Streams应用。

通过上述实战示例,我们展示了如何创建自定义的Serde类来处理自定义数据类型,并在Kafka Streams应用中正确配置和使用自定义Serde。实际应用中,可以根据需要调整序列化和反序列化逻辑,以适应不同的数据格式和传输需求。注意,序列化和反序列化过程中应处理好异常,确保数据的完整性和一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值