Índice
1. Por que você precisa de um group.id com subscribe
- Conceito de consumo:
Kafka utiliza o conceito de grupos de consumidores para permitir o consumo paralelo de tópicos - cada mensagem será entregue uma vez em cada grupo de consumidores, não importa quantos consumidores estejam realmente no grupo. Portanto o parâmetro grupo é obrigatório, sem grupo o Kafka não saberá como tratar outros consumidores inscritos no mesmo tema. - Offset :
sempre que iniciamos um consumidor, ele se junta a um grupo de consumidores e então atribui partições para leitura com base no número de outros consumidores nesse grupo de consumidores. Para essas partições, ele verifica se o deslocamento de leitura da lista é conhecido e, se encontrado, inicia a leitura das mensagens a partir desse ponto. Se nenhum deslocamento for encontrado, o parâmetro auto.offset.reset controla se a leitura deve ser iniciada a partir da mensagem mais antiga ou mais recente na partição.
2. Precisamos enviar compensações manualmente usando commitSync?
-
Preciso confirmar compensações manualmente?
Se as compensações precisam ser confirmadas depende do valor selecionado como parâmetro enable.auto.commit. Por padrão, isso é definido como verdadeiro, o que significa que o consumidor confirmará automaticamente suas compensações periodicamente (auto.commit.interval.ms determina com que frequência). Se for definido como falso, os próprios deslocamentos precisarão ser confirmados. Esse comportamento padrão é provavelmente também a razão pela qual muitos acham que o kafka sempre começa a consumir a partir do mais recente, já que o deslocamento é confirmado automaticamente, ele usará esse deslocamento. -
Existe uma maneira de reproduzir a mensagem desde o início?
Se quiser começar a ler sempre do início, você pode chamar seekToBeginning, que se chamado sem argumentos será redefinido para a primeira mensagem em todas as partições inscritas ou apenas nas partições que você passar. -
seekToBeginning
busca o primeiro deslocamento de cada partição fornecida. poll(long) A função avalia lentamente, procurando o primeiro deslocamento em todas as partições apenas ao chamar ou position(TopicPartition). Se nenhuma partição for fornecida, encontre o primeiro deslocamento de todas as partições atualmente alocadas.public class MyListener implements ConsumerSeekAware { ... @Override public void onPartitionsAssigned(Map<TopicPartition, Long> assignments, ConsumerSeekCallback callback) { callback.seekToBeginning(assignments.keySet()); } }
-
Existe uma maneira de reproduzir as mensagens começando do final?
Sim, você pode usar seekToEnd() para encontrar todas as partições alocadas até o fim. Ou use seekToTimestamp(long time) - procura todas as partições alocadas para o deslocamento indicado por este carimbo de data/hora.public class MyListener extends AbstractConsumerSeekAware { @KafkaListener(...) void listn(...) { ... } } public class SomeOtherBean { MyListener listener; ... void someMethod() { this.listener.seekToTimestamp(System.currentTimeMillis - 60_000); } }
3. O que devo fazer se quiser enviar a compensação manualmente?
-
1. Desative a confirmação automática
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
-
Método de confirmação
Para confirmação manual, KafkaConsumers fornece dois métodos, commitSync() e commitAsync(). commitSync() é uma chamada de bloqueio que retorna depois que o deslocamento é confirmado com sucesso e commitAsync() retorna imediatamente. Se quiser saber se o commit foi bem-sucedido, você pode fornecer um parâmetro de método para o manipulador de retorno de chamada ( OffsetCommitCallback ). Observe que em ambas as chamadas de commit, o consumidor confirma o deslocamento da última chamada poll().
Por exemplo: suponha que um tópico particionado tenha um consumidor e a última chamada para poll() retorne mensagens nos deslocamentos 4, 5 e 6. Ao confirmar, o deslocamento 6 será confirmado, pois é o último deslocamento rastreado pelo cliente consumidor.
Além disso, commitSync() e commitAsync() permitem mais controle sobre quais compensações queremos confirmar: o consumidor Map<TopicPartition, OffsetAndMetadata> só confirmará as compensações especificadas se você usar a sobrecarga correspondente que permite especificar o deslocamento (isto é , o mapa pode conter qualquer subconjunto das partições alocadas e o deslocamento especificado pode ser qualquer valor). -
Confirmação síncrona:
bloqueia o thread até que a confirmação seja bem-sucedida ou um erro irrecuperável seja encontrado (nesse caso, ele é devolvido ao chamador)while (true) { ConsumerRecords<String, String> records = consumer.poll(100); for (ConsumerRecord<String, String> record : records) { System.out.printf("offset = %d, key = %s, value = %s", record.offset(), record.key(), record.value()); consumer.commitSync(); } }
Para cada iteração no loop for, o código passa para a próxima iteração somente depois que consumer.commitSync() retornar com êxito ou for interrompido pelo lançamento de uma exceção.
-
Envio assíncrono:
é um método sem bloqueio. Chamá-lo não bloqueará o thread. Em vez disso, continuará processando as instruções a seguir, independentemente de eventual sucesso ou falha.while (true) { ConsumerRecords<String, String> records = consumer.poll(100); for (ConsumerRecord<String, String> record : records) { System.out.printf("offset = %d, key = %s, value = %s", record.offset(), record.key(), record.value()); consumer.commitAsync(callback); } }
Para cada iteração no loop for, o código passa para a próxima iteração, independentemente do que acontece com consumer.commitAsync() eventualmente. E o resultado enviado será processado pela função de retorno de chamada definida.
-
Compensações: Latência versus Consistência de Dados
1. Se você precisar garantir a consistência dos dados, escolha commitSync(), pois isso garantirá que você saberá se o commit de deslocamento foi bem-sucedido ou falhou antes de executar quaisquer operações adicionais. Mas como é síncrono e bloqueador, você gastará mais tempo aguardando a conclusão do commit, o que causará alta latência.
2. Se você aceita alguma inconsistência de dados e deseja ter baixa latência, escolha commitAsync() porque não aguardará a conclusão. Em vez disso, ele apenas emitirá uma solicitação de confirmação e posteriormente processará a resposta (sucesso ou falha) do Kafka enquanto o código continua em execução.