Diferença entre idempotência e exatamente uma vez no Kafka Stream

8

Eu estava analisando o que entendi que podemos conseguir com uma única transação, permitindo idempotence=true

idempotência: o produtor Idempotent ativa exatamente uma vez um produtor em um único tópico. Basicamente, cada envio de mensagem tem garantias mais fortes e não será duplicado caso ocorra um erro

Então, se já temos idempotência, por que precisamos de outra propriedade exatamente uma vez no Kafka Stream? O que exatamente diferente entre idempotência e exatamente uma vez

Por que a propriedade exatamente uma vez não está disponível no Kafka Producer normal?

Sandeep
fonte
2
Esta publicação no blog também é uma boa fonte para obter mais informações: medium.com/@andy.bryant/…
Matthias J. Sax

Respostas:

6

No ambiente distribuído, a falha é um cenário muito comum que pode ocorrer a qualquer momento. No ambiente Kafka, o broker pode travar, falha na rede, falha no processamento, falha ao publicar mensagens ou falha no consumo de mensagens etc. Esse cenário diferente introduziu diferentes tipos de perda e duplicação de dados.

Cenários de falha

A (falha na confirmação ): o produtor publicou a mensagem com êxito com nova tentativa> 1, mas não pôde receber confirmação devido a falha. Nesse caso, o Producer tentará novamente a mesma mensagem pode apresentar duplicado.

insira a descrição da imagem aqui

B (processo do produtor falhou em mensagens em lote): produtor que enviou um lote de mensagens com falha, com pouco sucesso publicado. Nesse caso, e assim que o produtor reiniciar, republicará novamente todas as mensagens do lote que introduzirão duplicado no Kafka. insira a descrição da imagem aqui

C (Falha ao ignorar e esquecer) O produtor publicou a mensagem com nova tentativa = 0 (acionar e esquecer). Em caso de falha publicada, não será informado e enviará a próxima mensagem, isso fará com que a mensagem seja perdida. insira a descrição da imagem aqui

D (Falha no consumidor na mensagem em lote) Um consumidor recebe um lote de mensagens da Kafka e confirma manualmente seu deslocamento (enable.auto.commit = false). Se o consumidor falhar antes de se comprometer com Kafka, na próxima vez que o consumidor consumir os mesmos registros novamente, os quais serão reproduzidos em duplicado no lado do consumidor.

insira a descrição da imagem aqui

Semântica exatamente uma vez

Nesse caso, mesmo se um produtor tentar reenviar uma mensagem, isso fará com que a mensagem seja publicada e consumida pelo consumidor exatamente uma vez.

Para obter a semântica Exatamente uma vez em Kafka, ele usa abaixo de 3 propriedades

  1. enable.idempotence = true (endereço a, b & c)
  2. MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5 (o produtor sempre terá uma solicitação a bordo por conexão)
  3. isolamento.level = read_committed (endereço d)

Habilitar Idempotent (enable.idempotence = true)

A entrega idempotente permite que o produtor grave uma mensagem no Kafka exatamente uma vez em uma partição específica de um tópico durante a vida útil de um único produtor, sem perda de dados e pedido por partição.

"Observe que ativar a idempotência exige que MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION seja menor ou igual a 5, RETRIES_CONFIG seja maior que 0 e ACKS_CONFIG seja 'todos'. Se esses valores não forem explicitamente definidos pelo usuário, serão escolhidos valores adequados. Se valores incompatíveis forem escolhidos. definido, uma ConfigException será lançada "

Para alcançar a idempotência, o Kafka usa uma identificação exclusiva, que é chamada de identificação do produto ou PID e número de sequência ao produzir mensagens. O produtor continua incrementando o número de sequência em cada mensagem publicada, que mapeia com PID exclusivo. O corretor sempre compara o número de sequência atual com o anterior e rejeita se o novo não for +1 maior que o anterior, o que evita a duplicação e, ao mesmo tempo, se mais do que o maior for perdido nas mensagens insira a descrição da imagem aqui

No cenário de falha, o broker comparará o número de sequência com o anterior e, se a sequência não tiver aumentado, +1 rejeitará a mensagem. insira a descrição da imagem aqui

Transação (isolamento.nível)

As transações nos permitem atualizar dados atomicamente em várias partições de tópicos. Todos os registros incluídos em uma transação serão salvos com sucesso, ou nenhum deles. Ele permite comprometer as compensações do consumidor na mesma transação, juntamente com os dados que você processou, permitindo, assim, a semântica de ponta a ponta exatamente uma vez. .

O Producer não espera para gravar a mensagem no kafka, onde o Producer usa beginTransaction, commitTransaction e abortTransaction (em caso de falha) O Consumidor usa isolation.level read_committed ou read_uncommitted

  • read_committed: o consumidor sempre lerá apenas dados confirmados.
  • read_uncommitted: leia todas as mensagens na ordem de compensação sem aguardar que as transações sejam confirmadas

Se um consumidor com isolated.level = read_committed alcançar uma mensagem de controle para uma transação que não foi concluída, ele não entregará mais mensagens dessa partição até que o produtor confirme ou anule a transação ou ocorra um tempo limite de transação. O tempo limite da transação é determinado pelo produtor usando a configuração transaction.timeout.ms (padrão 1 minuto).

Exatamente uma vez no produtor e consumidor

Em condições normais, onde temos produtores e consumidores separados. O produtor precisa idempotente e ao mesmo tempo gerenciar transações, para que o consumidor possa usar o isolamento.level para ler apenas read_committed para tornar todo o processo como operação atômica. Isso garante que o produtor sempre sincronize com o sistema de origem. Mesmo a interrupção ou transação do produtor interrompida, sempre será consistente e publique a mensagem ou lote de mensagens como unidade uma vez.

O mesmo consumidor receberá uma mensagem ou lote de mensagens como unidade uma vez.

No Produtor Semântico Exatamente Uma Vez, juntamente com o Consumidor, aparecerá como operação atômica que operará como uma unidade. Publique e seja consumido uma vez ou abortado.

Exatamente uma vez no Kafka Stream

O Kafka Stream consome mensagens do tópico A, processa e publica mensagem no Tópico B e, uma vez publicado, use commit (confirmação geralmente executada sob cobertura) para liberar todos os dados do armazenamento de estado no disco.

Exatamente uma vez no Kafka Stream é o padrão de leitura-processo-gravação que garante que essas operações sejam tratadas como operações atômicas. Como o Kafka Stream atende ao produtor, ao consumidor e às transações, o Kafka Stream vem com um processamento especial de parâmetros.

O Kafka Streams atualiza atomicamente as compensações do consumidor, as lojas locais do estado, os tópicos do log de alterações da loja do estado e a produção para exibir os tópicos todos juntos. Se qualquer uma dessas etapas falhar, todas as alterações serão revertidas.

processing.guarantee: exatamente_uma vez que forneça automaticamente os parâmetros abaixo que você não precisa definir explicitamente

  1. isolamento.level = read_committed
  2. enable.idempotence = true
  3. MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5
sun007
fonte
12

O fluxo Kafka oferece a semântica exatamente uma vez do ponto de vista de ponta a ponta (consome de um tópico, processa essa mensagem e depois produz para outro tópico). No entanto, você mencionou apenas o atributo idempotente do produtor . Essa é apenas uma pequena parte da imagem completa.

Deixe-me refazer a pergunta:

Por que precisamos da semântica de entrega exatamente uma vez no lado do consumidor, enquanto já garantimos a semântica de entrega exatamente uma vez no lado do produtor?

Resposta: Como a semântica de entrega exatamente uma vez não está apenas na etapa de produção, mas no fluxo total do processamento. Para alcançar a entrega exata uma vez semanticamente, existem algumas condições que devem ser satisfeitas com a produção e o consumo.

Este é o cenário genérico: O processo A produz mensagens para o tópico T. Ao mesmo tempo, o processo B tenta consumir mensagens do tópico T. Queremos garantir que o processo B nunca processe uma mensagem duas vezes.

Parte do produtor: devemos garantir que os produtores nunca produzam uma mensagem duas vezes. Podemos usar o Kafka Idempotent Producer

Parte do consumidor: Aqui está o fluxo de trabalho básico para o consumidor:

  • Etapa 1: o consumidor obtém a mensagem M com êxito do tópico do Kafka.
  • Etapa 2: o consumidor tenta executar o trabalho e o trabalho retorna com sucesso.
  • Etapa 3: o consumidor confirma o deslocamento da mensagem para os corretores Kafka.

Os passos acima são apenas um caminho feliz. Existem muitas questões que surgem na realidade.

  • Cenário 1: O trabalho na etapa 2 é executado com êxito, mas o consumidor falha. Desde essa circunstância inesperada, o consumidor ainda não confirmou o deslocamento da mensagem. Quando o consumidor reiniciar, a mensagem será consumida duas vezes.
  • Cenário 2: Enquanto o consumidor confirma o deslocamento na etapa 3, ele falha devido a falhas de hardware (por exemplo: CPU, violação de memória, ...) Ao reiniciar, o consumidor não tem como saber se o erro foi confirmado com êxito ou não.

Como existem muitos problemas, a execução da tarefa e o deslocamento da confirmação devem ser atômicos para garantir a semântica de entrega exatamente uma vez no lado do consumidor. Isso não significa que não podemos, mas é preciso muito esforço para garantir a semântica de entrega exata. O Kafka Stream sustenta o trabalho dos engenheiros.

Observou que: o Kafka Stream oferece "processamento de fluxo exatamente uma vez". Refere-se ao consumo de um tópico, materialização do estado intermediário em um tópico Kafka e produção para um. Se nosso aplicativo depende de outros serviços externos (banco de dados, serviços ...), devemos garantir que nossas dependências externas possam garantir exatamente uma vez nesses casos.

TL, DR: exatamente uma vez para o fluxo total, é necessária a cooperação entre produtores e consumidores.

Referências:

hqt
fonte
Eu não chamaria isso de entrega , porque a entrega geralmente implica a frequência com que uma mensagem é lida / enviada, e exatamente uma vez em Kafka obviamente se retira internamente por causa da falha. A entrega exata uma vez (ou seja, com que frequência uma mensagem é realmente enviada pela rede) não é possível (cf. en.wikipedia.org/wiki/Byzantine_fault e en.wikipedia.org/wiki/Two_Generals%27_Problem )
Matthias J. Sax
Sim. Conforme mencionado na resposta, é verdade que o Kafka Stream não oferece entrega exatamente uma vez no prazo geral. Sobre o Problema Geral Dois, não podemos ter geral exatamente uma vez no sistema distribuído, mas é possível quando perdemos algumas condições ou adicionamos mais algumas condições ao sistema. por exemplo: tempo limite. No entanto, esta é a história diferente.
Hqt 18/11/19
Bem, eu não usaria o termo delivery , mas ficaria com a semântica .
Matthias J. Sax