簡體   English   中英

在 Kafka Consumer API 中實現 Deserializer 和 Serde 有什么區別?

[英]What is the difference between implementing Deserializer and Serde in Kafka Consumer API?

我嘗試在 GitHub ( https://github.com/onurtokat/kafka-clickstream-enrich ) 上模擬 Gwen (Chen) Shapira 的 kafka-clickstream-enrich kafka-stream 項目。 當我使用反序列化器使用消費者類消費主題時,我遇到了錯誤。 定制的 Serde 類具有序列化器和反序列化器。 但是,我試圖理解為什么自定義 serde 用於反序列化器,然后消費者 API 給出錯誤,因為它不是 org.apache.kafka.common.serialization.Deserializer 的實例

可以使用帶有 Serdes.Integer() Serializer 和 new ProfileSerde() Deserializer 的 KTable 來使用該主題,如下所示。

KTable<Integer, UserProfile> profiles = builder.table(Constants.USER_PROFILE_TOPIC,
                Consumed.with(Serdes.Integer(), new ProfileSerde()),
                Materialized.as("profile-store"));

定制的 Serde 被定義為;

static public final class ProfileSerde extends WrapperSerde<UserProfile> {
        public ProfileSerde() {
            super(new JsonSerializer<UserProfile>(), new JsonDeserializer<UserProfile>(UserProfile.class));
        }
    }

通用的 Serde 是定制的,如下所示;

package com.onurtokat.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 WrapperSerde<T> implements Serde<T> {

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

    public WrapperSerde(Serializer<T> serializer, Deserializer<T> deserializer) {
        this.serializer = serializer;
        this.deserializer = deserializer;
    }

    @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<T> serializer() {
        return serializer;
    }

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

我的消費者非常簡單,可以在下面看到;

package com.onurtokat.consumers;

import com.onurtokat.ClickstreamEnrichment;
import com.onurtokat.Constants;
import com.onurtokat.model.UserProfile;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.IntegerDeserializer;

import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;

public class ConsumeProfileData {

    public static void main(String[] args) {
        //prepare config
        Properties config = new Properties();
        config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class.getName());
        config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ClickstreamEnrichment.ProfileSerde.class);

        KafkaConsumer<Integer, UserProfile> consumerProfileTopic = new KafkaConsumer<>(config);
        consumerProfileTopic.subscribe(Arrays.asList(Constants.USER_PROFILE_TOPIC));
        while (true) {
            ConsumerRecords<Integer, UserProfile> records = consumerProfileTopic.poll(Duration.ofMillis(100));
            for (ConsumerRecord<Integer, UserProfile> record : records) {
                System.out.println(record.key() + " " + record.value());
            }
        }
    }
}

當我嘗試與我的消費者一起消費主題時的錯誤是;

log4j:WARN No appenders could be found for logger (org.apache.kafka.clients.consumer.ConsumerConfig).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" org.apache.kafka.common.KafkaException: Failed to construct kafka consumer
    at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:811)
    at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:659)
    at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:639)
    at com.onurtokat.consumers.ConsumeProfileData.main(ConsumeProfileData.java:25)
Caused by: org.apache.kafka.common.KafkaException: com.onurtokat.ClickstreamEnrichment$ProfileSerde is not an instance of org.apache.kafka.common.serialization.Deserializer
    at org.apache.kafka.common.config.AbstractConfig.getConfiguredInstance(AbstractConfig.java:304)
    at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:712)
    ... 3 more

區別在於:

  • SERDES可以通過卡夫卡的流API(又名卡夫卡流)使用。 Serde 是一對 (1)序列化器和 (2)序列化器的包裝器,用於相同的數據類型——請參閱接下來的兩個要點。 也就是說, Serde<T>有一個Serializer<T>和一個Deserializer<T> 您發布的第一個代碼片段(例如KTable )是 Kafka Streams 代碼片段,這就是它需要Serde的原因。 Kafka Streams 需要一個Serde因為它既生成消息(它需要一個Serializer )又讀取消息(它需要一個Deserializer )。
  • Kafka 的消費者 API(又名消費者客戶端)使用解串器讀取消息。 您的最后一個代碼片段(例如KafkaConsumer )正在使用消費者客戶端,因此需要一個Deserializer ,而不是Serde
  • Kafka 的生產者 API(又名生產者客戶端)使用序列化程序來編寫消息。

關於:

Caused by: org.apache.kafka.common.KafkaException: com.onurtokat.ClickstreamEnrichment$ProfileSerde is not an instance of org.apache.kafka.common.serialization.Deserializer
    at org.apache.kafka.common.config.AbstractConfig.getConfiguredInstance(AbstractConfig.java:304)
    at org.apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.java:712)
    ... 3 more

您的 Kafka 消費者客戶端代碼獲得了一個Serde ,它期望一個Deserializer

看來你誤解了:

可以使用帶有 Serdes.Integer() Serializer 和 new ProfileSerde() Deserializer 的 KTable 來使用該主題,如下所示。

你必須提供Consumed.with()和 KeySerde 和 ValueSerde。

關於異常:

很清楚 - 您必須設置Deserializer (而不是Serde )的實現

config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, //here);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM