Por que o kafka precisa do group.id de subscribe? Precisamos confirmar compensações manualmente usando commitSync?

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.

Guess you like

Origin blog.csdn.net/qq_35241329/article/details/132289438