web-dev-qa-db-fra.com

Comment lire les données en utilisant l'API Kafka Consumer dès le début?

Quelqu'un peut-il me dire comment lire les messages à l'aide de l'API Kafka Consumer dès le début, chaque fois que j'exécute le fichier jar Consumer.

27
Nits

Cela fonctionne avec le consommateur 0.9.x. En règle générale, lorsque vous créez un consommateur, vous devez lui attribuer un ID de groupe de consommateurs à l’aide de la propriété ConsumerConfig.GROUP_ID_CONFIG. Générez l'ID de groupe de consommateurs de manière aléatoire chaque fois que vous démarrez le consommateur en procédant de la manière suivante: properties.put(ConsumerConfig.GROUP_ID_CONFIG, UUID.randomUUID().toString()); (propriétés est une instance de Java.util.Properties que vous allez transmettre au constructeur new KafkaConsumer(properties)).

La génération aléatoire du client signifie que le nouveau groupe de consommateurs n’a aucun décalage associé à kafka. Nous devons donc ensuite définir une stratégie pour ce scénario. Comme l'indique la documentation de la propriété auto.offset.reset

Que faire s'il n'y a pas d'offset initial dans Kafka ou si l'offset actuel n'existe plus sur le serveur (par exemple, parce que ces données ont été supprimées):

  • plus tôt: réinitialise automatiquement le décalage au plus tôt
  • latest: réinitialise automatiquement le décalage sur le dernier décalage 
  • none: renvoie une exception au consommateur si aucun décalage précédent n'a été trouvé ou si le groupe du consommateur 
  • toute autre chose: jetez une exception au consommateur.

Ainsi, parmi les options répertoriées ci-dessus, nous devons choisir la règle earliest afin que le nouveau groupe de consommateurs commence à partir du début à chaque fois.

Votre code en Java ressemblera à ceci:

properties.put(ConsumerConfig.GROUP_ID_CONFIG, UUID.randomUUID().toString());
properties.put(ConsumerConfig.CLIENT_ID_CONFIG, "your_client_id");
properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
consumer = new KafkaConsumer(properties);

La seule chose que vous ayez à comprendre maintenant, c’est lorsque vous avez plusieurs consommateurs qui appartiennent au même groupe de consommateurs mais sont distribués. Comment générer un identifiant aléatoire et le répartir entre ces instances afin qu’ils appartiennent tous au même groupe de consommateurs. 

J'espère que ça aide!

33
Nautilus

Une option pour ce faire serait d'avoir un identifiant de groupe unique à chaque fois que vous démarrez, ce qui signifie que Kafka vous enverra les messages du sujet depuis le début. Faites quelque chose comme ceci lorsque vous définissez vos propriétés pour KafkaConsumer:

properties.put(ConsumerConfig.GROUP_ID_CONFIG, UUID.randomUUID().toString());

L'autre option consiste à utiliser consumer.seekToBeginning(consumer.assignment()), mais cela ne fonctionnera que si Kafka reçoit d'abord une pulsation de votre consommateur en le faisant appeler par la méthode poll. Alors, appelez poll(), faites ensuite une seekToBeginning(), puis appelez à nouveau poll() si vous voulez que tous les enregistrements soient pris en compte au début. C'est un petit hackey, mais cela semble être le moyen le plus fiable de le faire à partir de la version 0.9.

// At this point, there is no heartbeat from consumer so seekToBeinning() wont work
// So call poll()
consumer.poll(0);
// Now there is heartbeat and consumer is "alive"
consumer.seekToBeginning(consumer.assignment());
// Now consume
ConsumerRecords<String, String> records = consumer.poll(0);
12
ucsunil

en utilisant le groupe de consommateurs de haut niveau props.put("auto.offset.reset", "smallest"); au moment de la création de la ConsumerConfig 

3
user2720864

Une solution possible consiste à utiliser une implémentation de ConsumerRebalanceListener lors de l’abonnement à un ou plusieurs sujets. ConsumerRebalanceListener contient des méthodes de rappel lorsque de nouvelles partitions sont attribuées ou supprimées d'un consommateur. L'exemple de code suivant illustre cela:

public class SkillsConsumer {

private String topic;

private KafkaConsumer<String, String> consumer;

private static final int POLL_TIMEOUT = 5000;

public SkillsConsumer(String topic) {
    this.topic = topic;
    Properties properties = ConsumerUtil.getConsumerProperties();
    properties.put("group.id", "consumer-skills");
    this.consumer = new KafkaConsumer<>(properties);
    this.consumer.subscribe(Collections.singletonList(this.topic),
            new PartitionOffsetAssignerListener(this.consumer));
}

}

public class PartitionOffsetAssignerListener implements ConsumerRebalanceListener {

private KafkaConsumer consumer;

public PartitionOffsetAssignerListener(KafkaConsumer kafkaConsumer) {
    this.consumer = kafkaConsumer;
}

@Override
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {

}

@Override
public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
    //reading all partitions from the beginning
    for(TopicPartition partition : partitions)
        consumer.seekToBeginning(partition);
}

}

Maintenant, chaque fois que les partitions sont attribuées au consommateur, chaque partition sera lue depuis le début. 

2
skm

Si vous utilisez plus spécifiquement l’API de consommateur Java, org.Apache.kafka.clients.consumer.Consumer, vous pouvez essayer les méthodes seek *.

consumer.seekToBeginning(consumer.assignment())

Consumer.assignment () renvoie ici toutes les partitions assignées à un consommateur donné et seekToBeginning commencera à partir du premier décalage pour la collection de partitions donnée.

1
Saideep Sambaraju

Donc, pour moi, ce qui a fonctionné était une combinaison de ce qui a été suggéré ci-dessus. Le principal changement consistait à inclure

props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

et avoir un ID de groupe généré de manière aléatoire à chaque fois. Mais cela seul n'a pas fonctionné pour moi. Pour une raison quelconque, la première fois que j'ai interrogé le consommateur, il n’a jamais obtenu d’enregistrement. Je devais le pirater pour le faire fonctionner - 

consumer.poll(0); // without this the below statement never got any records
final ConsumerRecords<Long, String> consumerRecords = consumer.poll(Duration.ofMillis(100));

Je suis nouveau chez KAFKA et je ne sais pas du tout pourquoi, mais pour tous ceux qui essaient encore de faire fonctionner cela, espérons que cela aidera.

1
karthiks3000