J'ai une classe simple pour consommer les messages d'un serveur kafka. La majorité des codes sont copiés à partir des commentaires de org.Apache.kafka.clients.consumer.KafkaConsumer.Java.
public class Demo {
public static void main(String[] args) {
Properties props = new Properties();
props.put("metadata.broker.list", "192.168.144.10:29092");
props.put("group.id", "test");
props.put("session.timeout.ms", "1000");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "10000");
KafkaConsumer<byte[], byte[]> consumer = new KafkaConsumer<byte[], byte[]>(props);
consumer.subscribe("voltdbexportAUDIT", "voltdbexportTEST");
boolean isRunning = true;
while (isRunning) {
Map<String, ConsumerRecords<byte[], byte[]>> records = consumer.poll(100);
process(records);
}
consumer.close();
}
private static Map<TopicPartition, Long> process(Map<String, ConsumerRecords<byte[], byte[]>> records) {
Map<TopicPartition, Long> processedOffsets = new HashMap<>();
for (Map.Entry<String, ConsumerRecords<byte[], byte[]>> recordMetadata : records.entrySet()) {
List<ConsumerRecord<byte[], byte[]>> recordsPerTopic = recordMetadata.getValue().records();
for (int i = 0; i < recordsPerTopic.size(); i++) {
ConsumerRecord<byte[], byte[]> record = recordsPerTopic.get(i);
// process record
try {
processedOffsets.put(record.topicAndPartition(), record.offset());
} catch (Exception e) {
e.printStackTrace();
}
}
}
return processedOffsets;
}
}
J'utilise 'org.Apache.kafka: kafka-clients: 0.8.2.0'. ça lève l'exception
Exception in thread "main" org.Apache.kafka.common.config.ConfigException: Missing required configuration "key.deserializer" which has no default value.
at org.Apache.kafka.common.config.ConfigDef.parse(ConfigDef.Java:124)
at org.Apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.Java:48)
at org.Apache.kafka.clients.consumer.ConsumerConfig.<init>(ConsumerConfig.Java:194)
at org.Apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.Java:430)
at org.Apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.Java:413)
at org.Apache.kafka.clients.consumer.KafkaConsumer.<init>(KafkaConsumer.Java:400)
at kafka.integration.Demo.main(Demo.Java:26)
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
at Java.lang.reflect.Method.invoke(Method.Java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.Java:140)
Comment dois-je configurer le key.deserializer?
Cela fonctionne hors de la boîte sans implémenter vos propres sérialiseurs
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "test");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("session.timeout.ms", "30000");
props.put("key.deserializer","org.Apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer","org.Apache.kafka.common.serialization.StringDeserializer");
props.put("partition.assignment.strategy", "range");
Vous devez définir les propriétés:
props.put("serializer.class","my.own.serializer.StringSupport");
props.put("key.serializer.class","my.own.serializer.LongSupport");
dans votre méthode principale afin de les transmettre au constructeur du producteur. Bien sûr, vous devez spécifier les bons encodeurs. La classe sérialiseur convertit le message en un tableau d'octets et la classe key.serializer transforme l'objet clé en un tableau d'octets. Généralement, vous devriez également leur permettre d'inverser le processus.
Vous avez affaire à un tableau d'octets pour le paramètre clé et valeur. Donc sérialiseur et désérialiseur Byte requis.
vous pouvez ajouter des propriétés,
Pour désérialiser
props.put("key.deserializer","org.Apache.kafka.common.serialization.ByteArrayDeserializer");
Pour sérialiser
props.put("value.deserializer","org.Apache.kafka.common.serialization.ByteArraySerializer");
Assurez-vous de passer la valeur de chaîne de la classe de désérialisation, plutôt que l'objet de classe (ce qui était mon erreur).
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
Serdes.String().deserializer().getClass().getName());
Lorsque vous oubliez la .getName()
vous obtiendrez la même exception qui dans ce cas est trompeuse.
Pour les clés, utilisez l'une des options suivantes
Clé de chaîne
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
clé JSON
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
Touche Avro
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, io.confluent.kafka.serializers.KafkaAvroDeserializer.class);
clé ByteArray
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);
De même, utilisez l'un des éléments suivants pour votre désérialiseur de valeur:
Valeur de chaîne
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
valeur JSON
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
Valeur Avro
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, io.confluent.kafka.serializers.KafkaAvroDeserializer.class);
Valeur ByteArray
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class);
Notez que pour les désérialiseurs Avro, vous aurez besoin des dépendances suivantes:
<dependency>
<groupId>io.confluent</groupId>
<artifactId>kafka-avro-serializer</artifactId>
<version>${confluent.version}</version>
</dependency>
<dependency>
<groupId>org.Apache.avro</groupId>
<artifactId>avro</artifactId>
<version>${avro.version}</version>
</dependency>