Quando os consumidores ficam atrasados em relação aos produtores, as mensagens se acumulam e a latência de processamento aumenta significativamente. Offsets mal configurados podem fazer com que mensagens sejam ignoradas ou reprocessadas silenciosamente. Este guia apresenta padrões comprovados para criar aplicações consumidoras confiáveis e de alto throughput no ApsaraMQ for Kafka, abordando grupos de consumidores, gerenciamento de offsets, tratamento de falhas e ajuste de desempenho.
Como funciona o consumo de mensagens
Um consumidor do ApsaraMQ for Kafka repete um ciclo de três etapas:
Poll — Obtém um lote de mensagens do broker.
Processamento — Executa sua lógica de negócios nas mensagens obtidas.
Novo poll — Busca o próximo lote após a conclusão do processamento.
Mantenha o tempo de processamento curto para preservar um intervalo de poll estável. Atrasos prolongados no processamento disparam rebalanceamentos ou causam acúmulo de mensagens.
Grupos de consumidores e balanceamento de carga
Um grupo de consumidores é um conjunto de instâncias de consumidor que compartilham o mesmo group.id. O ApsaraMQ for Kafka distribui as partições dos tópicos assinados uniformemente entre os consumidores de um grupo, garantindo que cada mensagem seja entregue a exatamente um consumidor.
Exemplo: O Grupo A assina o Tópico A. Três consumidores — C1, C2 e C3 — fazem parte do grupo. Cada mensagem recebida é direcionada a C1, C2 ou C3, equilibrando a carga de consumo entre os três.
O ApsaraMQ for Kafka aciona um rebalanceamento quando os consumidores são:
Iniciados pela primeira vez
Reiniciados
Adicionados ou removidos do grupo
Evite rebalanceamentos frequentes
Os rebalanceamentos pausam o consumo enquanto as partições são reatribuídas. Rebalanceamentos frequentes prejudicam o throughput e aumentam a latência de processamento, ocorrendo geralmente quando os heartbeats dos consumidores expiram.
Para evitar esse problema, ajuste os parâmetros relevantes ou aumente a taxa de consumo. Para obter etapas detalhadas de solução de problemas, consulte Why do rebalances frequently occur on my consumer client?
Configuração de partições
A quantidade de partições determina quantos consumidores podem processar mensagens em paralelo. Cada partição é atribuída a exatamente um consumidor dentro de um grupo; portanto, se houver mais consumidores do que partições, os excedentes permanecerão ociosos.
Quantidade recomendada de partições
No console do ApsaraMQ for Kafka, a quantidade padrão de partições é 12, valor adequado para a maioria das cargas de trabalho. Ao dimensionar o ambiente, siga estas diretrizes:
|
Quantidade de partições |
Impacto |
|
Menor que 12 |
Pode reduzir o desempenho de produção e consumo de mensagens |
|
12 – 100 |
Faixa recomendada para a maioria das cargas de trabalho |
|
Maior que 100 |
Pode causar rebalanceamentos frequentes de consumidores |
Não é possível reduzir a quantidade de partições após um aumento. Incremente as partições gradualmente, evitando saltos grandes de uma só vez.
Padrões de assinatura
O ApsaraMQ for Kafka oferece suporte a dois padrões de assinatura.
Um grupo assina vários tópicos
Um único grupo de consumidores pode assinar múltiplos tópicos. As mensagens de todos os tópicos assinados são distribuídas uniformemente entre os consumidores do grupo.
String topicStr = kafkaProperties.getProperty("topic");
String[] topics = topicStr.split(",");
for (String topic: topics) {
subscribedTopics.add(topic.trim());
}
consumer.subscribe(subscribedTopics);
Vários grupos assinam um único tópico
Diversos grupos de consumidores podem assinar o mesmo tópico de forma independente. Cada grupo recebe todas as mensagens e opera sem interferir nos demais.
Esse padrão é ideal quando diferentes aplicações precisam processar o mesmo fluxo de dados independentemente — por exemplo, um grupo dedicado a análises em tempo real e outro para arquivamento de dados.
Mantenha um grupo por aplicação
Utilize um grupo de consumidores exclusivo para cada aplicação. Caso uma única aplicação precise executar lógicas de consumo distintas, crie arquivos de configuração separados (por exemplo, kafka1.properties e kafka2.properties) com valores de group.id diferentes.
Alinhe as assinaturas dentro do grupo
Todos os consumidores de um mesmo grupo devem assinar o mesmo conjunto de tópicos. Assinaturas divergentes dificultam a solução de problemas e podem provocar comportamentos inesperados de rebalanceamento.
Gerenciamento de offsets de consumidor
Cada partição rastreia um offset máximo, que representa o total de mensagens recebidas. Cada consumidor mantém um offset de consumidor, indicando quantas mensagens já processou naquela partição. A diferença entre esses dois valores corresponde ao acúmulo de mensagens (backlog não consumido).
Commit automático versus manual
O ApsaraMQ for Kafka disponibiliza dois parâmetros para realizar o commit de offsets de consumidor:
|
Parâmetro |
Padrão |
Descrição |
|
|
|
Ativa o commit automático de offsets |
|
|
|
Intervalo entre commits automáticos |
Com o commit automático ativado, o cliente verifica o tempo decorrido desde o último commit antes de cada poll. Se esse tempo ultrapassar o valor definido em auto.commit.interval.ms, ele efetua o commit do offset atual.
Ao utilizar commit automático, garanta que todas as mensagens do poll anterior tenham sido totalmente processadas antes do próximo poll. Se o consumidor gravar em um armazenamento externo e essa gravação falhar, o commit automático ainda poderá avançar o offset, fazendo com que essas mensagens sejam ignoradas permanentemente em vez de serem tentadas novamente. Compreenda essa contrapartida antes de depender do comportamento padrão.
Realizar commit manual de offsets
Para fazer o commit manual de offsets, defina enable.auto.commit como false e chame a função commit(offsets) após processar cada lote.
Comportamento de redefinição de offset
Os offsets de consumidor são redefinidos em duas situações:
Não existe offset com commit registrado — por exemplo, quando um consumidor se conecta a um broker pela primeira vez.
O offset com commit é inválido — por exemplo, o offset máximo de uma partição é 10, mas o consumidor tenta ler a partir do offset 11.
Controle o comportamento de redefinição em clientes Java por meio do parâmetro auto.offset.reset:
|
Valor |
Comportamento |
|
|
Inicia a partir da mensagem mais recente. Use esta opção como padrão |
|
|
Inicia a partir da mensagem disponível mais antiga |
|
|
Lança uma exceção em vez de redefinir |
Prefira latest em vez de earliest para evitar o reprocessamento de todo o histórico do tópico quando ocorrer um offset inválido. Se você fizer commits manuais de offsets com a função commit(offsets), a opção none é uma escolha segura, pois seus offsets deverão estar sempre válidos.
Tratamento de mensagens grandes
Quando mensagens individuais excedem os tamanhos usuais, ajuste os seguintes parâmetros para controlar o comportamento de busca:
|
Parâmetro |
Orientação |
|
|
Quantidade máxima de registros por poll. Defina como |
|
|
Volume máximo de dados por solicitação de fetch. Configure um valor ligeiramente superior ao tamanho esperado da mensagem |
|
|
Volume máximo de dados por partição em cada fetch. Configure um valor ligeiramente superior ao tamanho esperado da mensagem |
Com essas configurações, o consumidor busca mensagens grandes individualmente, evitando pressão sobre a memória causada por lotes excessivamente grandes.
Tratamento de duplicação de mensagens
O ApsaraMQ for Kafka utiliza semântica de entrega at-least-once: cada mensagem é entregue pelo menos uma vez para evitar perda de dados, mas duplicações podem ocorrer durante erros de rede ou reinicializações de clientes.
Implemente consumo idempotente
Se sua aplicação for sensível a duplicatas — como transações financeiras ou processamento de pedidos — implemente a deduplicação no nível da aplicação:
Associe uma chave única a cada mensagem durante a produção (por exemplo, um ID de transação).
Antes de processar uma mensagem consumida, verifique se a chave já foi processada anteriormente.
Ignore mensagens cujas chaves já tenham sido processadas.
Caso sua aplicação tolere duplicatas ocasionais (por exemplo, agregação de métricas ou ingestão de logs), ignore esta etapa.
Tratamento de falhas de consumo
As mensagens dentro de uma partição são consumidas sequencialmente. Quando o processamento falha — devido a dados malformados ou indisponibilidade de um service downstream, por exemplo — adote uma das estratégias abaixo:
|
Estratégia |
Contrapartida |
|
Tentativa local |
Tenta reprocessar a mensagem com falha até obter sucesso. Simples de implementar, mas bloqueia a thread do consumidor e causa acúmulo de mensagens naquela partição |
|
Tópico de dead-letter |
Envia mensagens com falha para um tópico dedicado para inspeção posterior. O consumo continua sem bloqueios, mas exige um processo separado para investigar e reprocessar as falhas |
Para a maioria das cargas de trabalho em produção, a abordagem de dead-letter evita o travamento do pipeline de consumo.
Redução da latência de consumo
O ApsaraMQ for Kafka utiliza um modelo baseado em pull: os consumidores buscam mensagens do broker em cada ciclo de poll. Enquanto os consumidores acompanham o ritmo dos produtores, a latência permanece baixa. Um pico de latência geralmente indica acúmulo de mensagens.
Causas comuns de acúmulo
|
Causa |
Solução |
|
Taxa de consumo inferior à taxa de produção |
Adicione consumidores ou aumente o throughput de processamento |
|
Thread do consumidor bloqueada por chamada remota lenta |
Configure timeouts em chamadas externas para liberar a thread após um tempo de espera limitado |
Aumento do throughput de consumo
Adicione mais consumidores. Inicie instâncias adicionais de consumidores (uma thread por consumidor) ou implante mais processos de consumo. A quantidade de consumidores ativos não pode exceder o número de partições; os excedentes ficarão ociosos.
Utilize um pool de threads para processamento. Desacople o polling do processamento para paralelizar o trabalho:
Defina um pool de threads com uma quantidade fixa de threads de trabalho.
Faça o poll de um lote de mensagens.
Envie cada mensagem para o pool de threads para processamento concorrente.
Após a conclusão de todas as tarefas do lote, faça o poll do próximo lote.
Esse padrão mantém o loop de poll responsivo enquanto distribui o trabalho de processamento entre várias threads.
Filtragem de mensagens
O ApsaraMQ for Kafka não oferece filtragem nativa de mensagens. Implemente a filtragem no nível da aplicação utilizando uma das abordagens a seguir:
|
Abordagem |
Quando usar |
|
Tópicos separados |
Poucas categorias distintas de mensagens |
|
Filtragem no lado do cliente |
Muitas categorias ou lógica de filtragem que muda frequentemente |
Combine ambas as abordagens quando seu caso de uso exigir: direcione categorias amplas para tópicos diferentes e aplique filtros refinados no lado do consumidor.
Transmissão de mensagens (broadcast)
O ApsaraMQ for Kafka não suporta nativamente a transmissão de mensagens em broadcast. Para entregar cada mensagem a múltiplos consumidores independentes, crie um grupo de consumidores separado para cada consumidor que precise receber todas as mensagens. Cada grupo consome de forma independente o fluxo completo de mensagens do tópico.