web-dev-qa-db-ja.com

kafkaでカスタムシリアライザーを作成するにはどうすればよいですか?

次のような利用可能なシリアライザーはほとんどありません。

org.Apache.kafka.common.serialization.StringSerializer
org.Apache.kafka.common.serialization.StringSerializer 

独自のカスタムシリアライザーを作成するにはどうすればよいですか?

7
Vimal Dhaduk

ここに、Kafkaメッセージ値に独自のシリアライザー/デシリアライザーを使用する例があります。Kafkaメッセージキーも同じです。

MyMessageのシリアル化されたバージョンをKafka valueとして送信し、コンシューマー側のMyMessageオブジェクトに再度逆シリアル化します。

プロデューサー側でMyMessageをシリアル化します。

Org.Apache.kafka.common.serialization.Serializerを実装するシリアライザークラスを作成する必要があります

serialize()メソッドが作業を行い、オブジェクトを受け取り、シリアル化されたバージョンをバイト配列として返します。

public class MyValueSerializer implements Serializer<MyMessage>
{
    private boolean isKey;

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

    @Override
    public byte[] serialize(String topic, MyMessage message)
    {
        if (message == null) {
            return null;
        }

        try {

            (serialize your MyMessage object into bytes)

            return bytes;

        } catch (IOException | RuntimeException e) {
            throw new SerializationException("Error serializing value", e);
        }
    }

    @Override
    public void close()
    {

    }
}

final IntegerSerializer keySerializer = new IntegerSerializer();
final MyValueSerializer myValueSerializer = new MyValueSerializer();
final KafkaProducer<Integer, MyMessage> producer = new KafkaProducer<>(props, keySerializer, myValueSerializer);

int messageNo = 1;
int kafkaKey = messageNo;
MyMessage kafkaValue = new MyMessage();
ProducerRecord producerRecord = new ProducerRecord<>(topic, kafkaKey, kafkaValue);
producer.send(producerRecord, new DemoCallBack(logTag, startTime, messageNo, strValue));

コンシューマ側でのMyMessageの逆シリアル化。

Org.Apache.kafka.common.serialization.Deserializerを実装するデシリアライザークラスを作成する必要があります

deserialize()メソッドが作業を行い、シリアル化された値をバイト配列として受け取り、オブジェクトを返します。

public class MyValueDeserializer implements Deserializer<MyMessage>
{
    private boolean isKey;

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

    @Override
    public MyMessage deserialize(String s, byte[] value)
    {
        if (value == null) {
            return null;
        }

        try {

            (deserialize value into your MyMessage object)

            MyMessage message = new MyMessage();
            return message;

        } catch (IOException | RuntimeException e) {
            throw new SerializationException("Error deserializing value", e);
        }
    }

    @Override
    public void close()
    {

    }
}

次に、次のように使用します。

final IntegerDeserializer keyDeserializer = new IntegerDeserializer();
final MyValueDeserializer myValueDeserializer = new MyValueDeserializer();
final KafkaConsumer<Integer, MyMessage> consumer = new KafkaConsumer<>(props, keyDeserializer, myValueDeserializer);

ConsumerRecords<Integer, MyMessage> records = consumer.poll(1000);
for (ConsumerRecord<Integer, MyMessage> record : records) {

    int kafkaKey = record.key();
    MyMessage kafkaValue = record.value();

    ...
}
14

言葉なし、コードのみ

  1. あなたがカフカに送られるいくつかのオブジェクト

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public class TestDto {
    
        private String name;
        private String version;
    
    }
    
  2. プロデューサーが使用するシリアライザーを作成します

    @Slf4j
    public class KafkaValueSerializer implements Serializer<TestDto> {
    
        private ObjectMapper objectMapper = new ObjectMapper();
    
        @Override
        public void configure(Map<String, ?> configs, boolean isKey) {
        }
    
        @Override
        public byte[] serialize(String topic, TestDto data) {
            try {
                return objectMapper.writeValueAsBytes(data);
            } catch (JsonProcessingException e) {
                log.error("Unable to serialize object {}", data, e);
                return null;
            }
        }
    
        @Override
        public void close() {
        }
    }
    
  3. クーザーの、消費者のためのデシリアライザーについて気にしないでください

    @Slf4j
    public class KafkaValueDeserializer implements Deserializer<TestDto> {
    
        private ObjectMapper objectMapper = new ObjectMapper();
    
        @Override
        public void configure(Map<String, ?> configs, boolean isKey) {
        }
    
        @Override
        public TestDto deserialize(String topic, byte[] data) {
            try {
                return objectMapper.readValue(new String(data, "UTF-8"), TestDto.class);
            } catch (Exception e) {
                log.error("Unable to deserialize message {}", data, e);
                return null;
            }
        }
    
        @Override
        public void close() {
        }
    }
    
  4. 最後に、シリアライザー/デシリアライザーをapplication.ymlに追加します

    spring:
        kafka:
          bootstrap-servers:  192.168.192.168:9092
          producer:
              value-serializer: com.package.service.kafka.KafkaValueSerializer
          consumer:
              group-id: groupId
              value-deserializer: com.package.service.kafka.KafkaValueDeserializer
    

それで全部です。設定ファイルやタンボイリンで踊る必要はありません:)

  1. 送信

    KafkaTemplate<String, TestDto> kafkaTemplate;
    
    TestDto test = new TestDto("test name", "test-version");
    kafkaTemplate.send(topic, testDto);
    
  2. 聴く

    @KafkaListener(topics = "${ktp-agent.kafka.request-topic}", groupId = "${spring.kafka.consumer.group-id}")
    public void listen(TestDto message) {
    
        log.info("Received message '{}' from Kafka.", message.toString());
    }
    
3
Vladimir