Share Groups ("Queues for Kafka"), definidos no KIP-932 (Kafka Improvement Proposal 932), são um modelo de consumo em que vários consumidores compartilham as mesmas partições de um tópico, com acknowledgement por registro, reentrega automática e contagem de entregas. Eles existem para resolver um problema antigo do consumer group, que prende um consumidor a cada partição e obriga a dimensionar as partições pelo pico de consumo.
Este estudo é um aprofundamento no uso do recurso. Explica o que ele é e como funciona por dentro (atribuição sem dono de partição, componentes do broker, ciclo de poll(), estados de um registro e janela in-flight), o que muda em relação aos consumer groups e o que a adoção exige da aplicação e da operação: destino idempotente, tratamento de erro por registro, dimensionamento de locks, métricas novas e regras de autoscaling. Também calcula os limites que o protocolo impõe, relata o custo adicional nos brokers e termina com os casos de uso em que o modelo se encaixa e aqueles em que o consumer group continua sendo a escolha certa.
O texto segue o KIP-932 e o código-fonte do Apache Kafka 4.0 a 4.2 e vale para qualquer distribuição que implemente o protocolo. Onde cita um serviço gerenciado, usa o Amazon MSK (Amazon Managed Streaming for Apache Kafka) como referência, com suas métricas, seus limites e sua disponibilidade em setembro de 2026. As Partes 1 a 3 apresentam o modelo, as Partes 4 a 8 tratam do que a adoção exige e a Parte 9 fecha com os casos de uso e um roteiro de decisão; Fontes e Glossário ficam ao final.
Resumo
O que um time precisa saber antes de avaliar Share Groups. A figura mostra a diferença essencial entre os dois modelos de consumo; os cartões resumem cada tema e apontam para a parte com o detalhe.
Figura 1. O mesmo tópico de quatro partições consumido por um consumer group (esquerda) e por um share group (direita); cada cor é uma partição. Animação contínua.
- Consumer group: cada partição pertence a um único membro e os registros chegam na ordem do log; C5 e C6 não recebem nada, porque o paralelismo máximo é o número de partições.
- Share group: os registros de todas as partições passam pela janela in-flight das share-partitions e são entregues a qualquer consumidor do grupo, misturando partições e sem ordem entre consumidores.
- Em ambos, o broker decide a entrega; no share group ele também mantém um lock por registro até o acknowledgement.
O que é. Um share group permite que mais consumidores do que partições leiam o mesmo tópico. O broker entrega registros a qualquer membro do grupo, mantém um lock por registro enquanto ele está em processamento, conta as entregas e reentrega o que não for confirmado. Registros são confirmados com ACCEPT, devolvidos com RELEASE ou descartados com REJECT. Consumer groups continuam existindo e não mudam; share groups são um segundo modelo, escolhido por grupo. Detalhe na Parte 3
Diferença para consumer groups. No consumer group cada partição pertence a um único membro, a posição de leitura é um offset commitado e a ordem por partição é preservada. No share group a partição é compartilhada, a posição é uma janela de registros com estado individual, não há ordem entre consumidores e não há rebalance de partições quando membros entram ou saem. Detalhe na Parte 2
Maturidade. No Apache Kafka: early access na versão 4.0 (março de 2025), preview na 4.1 (setembro de 2025) e pronto para produção na 4.2 (fevereiro de 2026; a 4.2.1 corrige um deadlock crítico). No Amazon MSK, em setembro de 2026, o recurso está disponível como preview no Kafka 4.1.x em brokers Standard; o Kafka 4.2 está disponível em Express brokers, nos quais o KIP-932 ainda não é suportado.
Clientes. O recurso exige um protocolo novo e a classe KafkaShareConsumer. Hoje, isso significa cliente Java 4.1 ou superior e Spring for Apache Kafka 4.0 ou superior. Kafka Connect e Kafka Streams consomem com KafkaConsumer e não participam de share groups; para sink connectors existe uma proposta em discussão (KIP-1302). Detalhe na Parte 4
Limites. Cada share-partition entrega no máximo group.share.partition.max.record.locks registros ainda não confirmados (2 000 por default a partir do Kafka 4.1; 200 no 4.0). Esse número, dividido pelo tempo médio que um registro passa entregue, dá o teto de vazão do grupo. O lock dura 30 s por default; após 5 entregas o registro é arquivado, sem dead-letter queue (DLQ) nativa. Até 200 membros por grupo por default, configurável até 1 000. Detalhe na Parte 5
Garantias. At-least-once: o mesmo registro pode ser processado mais de uma vez, então a escrita no destino precisa ser idempotente. Não há transações nem exactly-once; não há ordem garantida entre lotes ou entre consumidores. Em modo explícito a aplicação decide registro a registro; em modo implícito o lote inteiro é confirmado de uma vez. Detalhe na Parte 8
Quando o modelo se aplica
Filas de trabalho em que cada registro é independente, o tempo de processamento varia, o número de consumidores precisa crescer além das partições e o tratamento de erro é por registro. Não se aplica quando a ordem por chave importa, quando exactly-once é exigido ou quando o consumidor é um framework que só fala consumer groups. Casos de uso e alternativas na Parte 9.
Consumer groups: o modelo e seus limites
O consumer group atribui cada partição a um único membro. O paralelismo máximo é o número de partições, e cada entrada ou saída de membro redistribui partições (rebalance). Antes de trocar o modelo de consumo, vale conhecer o que o próprio consumer group oferece para reduzir o custo desses rebalances e aproveitar o paralelismo existente.
Figura 2a. Consumer group com assignor eager (range, round_robin).
Figura 2b. Consumer group com cooperative_sticky ou KIP-848.
Figura 2c. Share group.
Figura 2. Um terceiro consumidor entrando em um grupo com quatro partições, nos três modelos. Ciclo de 12 segundos; a barra inferior indica a fase.
- Fase 1, grupo estável: C1 e C2 dividem as quatro partições (consumer groups) ou recebem registros de qualquer partição (share group).
- Fase 2, C3 entra: com assignor eager todas as partições são revogadas e os três consumidores param até a nova atribuição; com
cooperative_stickyou KIP-848 só a partição que muda de dono (P3) para; no share group nada é revogado e C3 recebe registros no primeiropoll(). - Fase 3, novo estado: nos consumer groups C3 fica com P3 e o paralelismo continua limitado a quatro; no share group os três consumidores compartilham as quatro partições.
| Ajuste | Configuração do cliente Java (default) | Efeito |
|---|---|---|
| Rebalance cooperativo |
partition.assignment.strategy = CooperativeStickyAssignor (RangeAssignor) |
Só as partições movidas pausam; disponível desde o Kafka 2.4 e funciona em brokers 3.x. |
| Static membership (KIP-345) |
group.instance.id (não definido) |
Reinício de uma instância dentro de session.timeout.ms não dispara rebalance. |
| Tamanho do lote |
max.poll.records (500), max.poll.interval.ms (300 000) |
Um lote que demora mais que o intervalo para ser processado expulsa o membro do grupo e provoca rebalances "espontâneos" em pico. |
| Membros do grupo | Instâncias × threads de consumo | Dimensionar até o número de partições; acima disso os membros excedentes ficam ociosos. Este é o limite estrutural que os Share Groups removem. |
| Garantia de entrega |
enable.auto.commit (true, 5 s) |
Com auto-commit o offset pode ser confirmado antes de o registro chegar ao destino (at-most-once em falha do processo); commit após o processamento restaura at-least-once. |
| Novo protocolo (KIP-848) |
group.protocol = consumer (classic) |
Atribuição feita no broker, sem barreira global; só com brokers 4.0+ e incompatível com partition.assignment.strategy, heartbeat.interval.ms e session.timeout.ms do lado do cliente. |
Fonte: documentação de configuração do consumidor Apache Kafka; KIP-345, KIP-429 e KIP-848.
Como funcionam os Share Groups (KIP-932)
O próprio KIP registra a motivação. Times fazem "over-partition" só para ter paralelismo de consumo suficiente nos picos, porque o consumer group prende um consumidor a cada partição. Share Groups quebram esse acoplamento. Tudo nesta seção segue o texto do KIP-932 e o código-fonte das versões 4.0.0, 4.1.0 e 4.2.0.
Em seis passos, que as subseções seguintes detalham:
- O assignor do servidor dá trabalho a todos os membros do grupo, sem dono de partição (Figura 3).
- Três componentes do broker dividem o trabalho: Group Coordinator, Share-Partition Leader e Share Coordinator (Figura 4).
- Cada
poll()adquire registros, inicia um lock por registro e carrega os acknowledgements do lote anterior (Figura 5). - Cada registro passa pelos estados Available, Acquired, Acknowledged ou Archived (Figura 6).
- Só a janela in-flight tem estado no broker; o backlog fora dela não tem lock (Figura 7 e simulador).
- A aplicação escolhe confirmar por lote ou por registro, e nos dois modos o lock de aquisição decide o que acontece quando o processamento demora (Figuras 8 a 12). As configurações de broker e de grupo fecham a parte.
Passo 1: atribuição sem dono de partição
No consumer group o assignor divide as partições entre os membros e cada partição tem um único dono. No share group o assignor do servidor (SimpleAssignor) atribui partições a todos os membros, inclusive a mesma partição a vários deles; o que cada membro recebe é decidido registro a registro, no fetch, e não na atribuição. É isso que permite mais consumidores do que partições e dispensa a redistribuição de partições quando membros entram ou saem.
Figura 3. Atribuição nos dois modelos. KIP-932: "the number of consumers in a share group can exceed the number of partitions in a topic".
Passo 2: os componentes no broker
Três componentes dividem o trabalho. O Group Coordinator cuida de membership e atribuição, como nos consumer groups do KIP-848. O Share-Partition Leader, no broker líder de cada partição, decide quais registros entregar a cada fetch, mantém em memória o estado da janela in-flight e controla os locks. O Share Coordinator persiste esse estado em um tópico interno (__share_group_state), para que uma troca de líder não perca acknowledgements nem delivery counts.
Figura 4. Componentes definidos pelo KIP-932. O Group Coordinator cuida de membership e atribuição, como nos consumer groups do KIP-848, e pede ao Share Coordinator que inicialize ou apague o estado das share-partitions (chamadas do protocolo, ou RPCs, InitializeShareGroupState e DeleteShareGroupState, omitidas na figura). O Share-Partition Leader, no broker líder da partição, decide quais registros entregar e mantém o estado in-flight em memória. O Share Coordinator persiste esse estado em um tópico próprio, criado no primeiro uso; o KIP justifica o tópico separado porque __consumer_offsets "já é um gargalo conhecido para alguns usuários".
Passo 3: o ciclo de um poll()
Cada poll() do consumidor vira um ShareFetch para o Share-Partition Leader. O líder escolhe registros Available a partir do início da janela, marca-os Acquired, incrementa o delivery count de cada um, inicia o lock de aquisição (30 s por default) e responde. No modo implícito, o mesmo poll() carrega os acknowledgements do lote anterior, que o líder persiste no Share Coordinator antes de responder. O tempo entre a entrega e a confirmação é o W usado nas fórmulas da Parte 5.
Figura 5. Ciclo em modo implícito (share.acknowledgement.mode=implicit, default). Cada poll() confirma o lote anterior e adquire o próximo em uma única RPC (remote procedure call); a Figura 8 compara com o modo explícito. O tempo em Acquired (W) inclui fetch, processamento e o próximo poll, e é o denominador da fórmula de capacidade da Parte 5. O Share-Partition Leader espera a persistência antes de responder.
Passo 4: os estados de um registro
Um registro entra na janela como Available, passa a Acquired quando é entregue e termina Acknowledged (ACCEPT) ou Archived (REJECT, ou limite de entregas atingido). RELEASE e a expiração do lock o devolvem a Available com o delivery count preservado; RENEW (Kafka 4.2) estende o lock sem mudar de estado. A Figura 6 resume as transições e é o vocabulário usado pelas animações do passo 6.
Figura 6. Estados de um registro dentro de uma share-partition. RENEW (KIP-1222, Kafka 4.2) estende o lock de um registro Acquired sem mudar de estado. O delivery count é aproximado (o KIP diz que ele "cannot be relied upon to be precise in all situations"). Ele serve para interromper a reentrega de poison messages, e não deve ser usado como contador exato.
Passo 5: a janela in-flight de uma share-partition
O Share-Partition Leader só mantém estado para os registros entre o SPSO (share-partition start offset) e o SPEO (share-partition end offset); a distância entre eles é limitada por group.share.partition.max.record.locks. Registros fora da janela, mesmo um backlog de milhões, não têm lock nem estado. A Figura 7 reproduz o exemplo do KIP; o simulador, no modo interativo, permite adquirir, confirmar, liberar e rejeitar registros e ver a janela se mover.
Figura 7. Exemplo do KIP-932. O registro 3 foi adquirido duas vezes e voltou a Available; o 5 foi confirmado; o 6 foi rejeitado; 2 e 4 estão em processamento. Registros fora da janela, inclusive um backlog de milhões, não têm lock nem estado no broker.
Nesta posição a versão HTML tem um painel interativo (simulador da janela in-flight ou calculadora de capacidade).
Passo 6: modo de acknowledgement, por lote ou por registro
O consumidor escolhe em share.acknowledgement.mode a granularidade com que informa ao broker o resultado do processamento. A escolha define se a aplicação consegue tratar cada evento da fila separadamente ou só o lote como um todo.
Figura 8. Os dois modos de acknowledgement definidos no KIP-932. No modo implícito o único resultado possível é ACCEPT, aplicado a todo o lote do último poll(); a única forma de não confirmar é liberar o lote inteiro. No modo explícito cada registro recebe ACCEPT, RELEASE ou REJECT (e RENEW a partir do Kafka 4.2), o que permite controlar o estado de cada evento da fila.
Figura 9. Modo implícito, fase a fase (ciclo de 12 segundos).
-
poll()adquire seis registros; o broker os marca Acquired e inicia o lock de cada um. - O consumidor processa o lote; o registro 103 falha, mas não existe
acknowledge()neste modo para sinalizar isso. - O próximo
poll()(oucommitSync()/commitAsync()) envia um único ACCEPT para o lote inteiro. - Os seis viram Acknowledged, inclusive o 103, que não será reentregue.
Figura 10. Modo explícito, fase a fase (ciclo de 12 segundos).
-
poll()adquire seis registros, como no modo implícito. - A aplicação chama
acknowledge(registro, tipo)para cada um: ACCEPT nos processados, REJECT no 103 (erro permanente), RELEASE no 104 (erro transitório). -
commitSync()envia os seis resultados; no broker, ACCEPT vira Acknowledged, REJECT vira Archived e RELEASE volta a Available com o delivery count preservado. - O 104 é reentregue a qualquer consumidor do grupo com delivery count 2; após o limite de entregas (5) seria arquivado.
Figura 11. Modo implícito quando o lote não é confirmado (ciclo de 12 segundos).
-
poll()adquire seis registros. - Cinco são processados com sucesso e o 103 falha; a única alternativa a confirmar o lote inteiro é não confirmar nada.
- A aplicação fecha o consumidor (
close()) ou o lock de 30 s expira: o broker devolve os seis a Available e incrementa o delivery count de todos. - Os seis são reentregues, inclusive os cinco já processados, que serão processados de novo; por isso o modo implícito exige destino idempotente e o tratamento de erro por registro pede o modo explícito.
Nos dois modos, cada registro entregue carrega um lock de aquisição, de 30 s por default. Se o processamento demora mais do que isso, o broker devolve o registro a Available e outro consumidor pode recebê-lo enquanto o primeiro ainda trabalha nele; o Kafka 4.2 acrescenta o RENEW (KIP-1222), que estende o lock sem mudar o estado do registro. A Figura 12 mostra as duas situações, com o tempo comprimido.
Figura 12. O lock de aquisição em ação, com tempo comprimido (30 s reais correspondem a 4 s de animação).
- Faixa superior: o registro 107 é entregue ao consumidor A, cujo processamento leva 45 s, mais do que o lock de 30 s.
- O lock expira com A ainda trabalhando: o broker devolve o 107 a Available (delivery count 1) e o reentrega ao consumidor B (delivery count 2).
- A termina, grava no destino e tem o ACCEPT recusado, porque o lock já não é dele; B grava e confirma. O destino recebeu a mesma escrita duas vezes.
- Faixa inferior, Kafka 4.2: A renova o lock com RENEW (KIP-1222) antes de expirar e confirma no prazo; uma entrega, uma gravação. O lock deve ser maior que o percentil 99 do tempo de processamento de um lote, e o destino, idempotente.
| Aspecto | implicit (default) | explicit |
|---|---|---|
| Granularidade | O lote inteiro devolvido pelo último poll()
|
Cada registro, individualmente |
| Resultados possíveis | Só ACCEPT (implícito); acknowledge() não pode ser chamado |
ACCEPT, RELEASE, REJECT; RENEW no Kafka 4.2 |
| Como confirma | Próximo poll() (assíncrono, sem exceção em caso de falha), commitSync() ou commitAsync()
|
acknowledge(record, tipo) para todos os registros do lote e depois poll(), commitSync() ou commitAsync(); poll() com registros pendentes lança IllegalStateException
|
| Falha de desserialização | Nos dois modos o cliente libera o registro e lança exceção com partição e offset; no explícito, acknowledge(topic, partition, offset, tipo) permite rejeitá-lo sem o ConsumerRecord
|
|
| Resultado do commit |
commitSync() devolve um mapa por partição; poll() não informa |
Idem; com commitAsync() ou poll() o resultado só chega pelo AcknowledgementCommitCallback
|
| Indicado para | Processamento do lote tudo ou nada, com destino idempotente | Controle de estado por evento: DLQ por registro, poison messages, rastreabilidade de cada registro |
Fonte: KIP-932, seções "Consumer configuration" e "Acknowledging records", e Javadoc de KafkaShareConsumer (acknowledge, commitSync, commitAsync, setAcknowledgementCommitCallback).
Configurações disponíveis
| Configuração de broker | Kafka 4.0.0 | Kafka 4.1.0 e 4.2.0 | Faixa | Função |
|---|---|---|---|---|
group.share.partition.max.record.locks |
200 | 2 000 | 100 a 10 000 | Teto de registros in-flight por share-partition |
group.share.record.lock.duration.ms |
30 000 | 30 000 | 1 000 a 3 600 000 | Duração do lock; por grupo via share.record.lock.duration.ms, entre os limites group.share.min/max.record.lock.duration.ms (15 000 e 60 000) |
group.share.delivery.count.limit |
5 | 5 | 2 a 10 | Entregas antes de arquivar |
group.share.max.size |
200 | 200 | 1 a 1 000 | Membros por share group |
group.share.max.share.sessions |
não existia | 2 000 | ≥ group.share.max.size
|
Share sessions por broker (uma por consumidor conectado); no 4.0 havia group.share.max.groups = 10, removida no 4.1 |
share.coordinator.state.topic.* |
50 partições, replication factor 3, min.insync.replicas 2, snapshot a cada 500 updates | — | Tópico interno de estado | |
| Habilitação |
unstable.api.versions.enable e group.coordinator.rebalance.protocols com share
|
kafka-features.sh upgrade --feature share.version=1 |
— | 4.0 early access; 4.1 preview desligado por default; 4.2 pronto para produção |
Configurações por grupo (dinâmicas): share.auto.offset.reset (latest por default), share.isolation.level, share.record.lock.duration.ms, share.session.timeout.ms, share.heartbeat.interval.ms; o KIP-1240 (Kafka 4.3) acrescenta outras. No consumidor deixam de existir enable.auto.commit, auto.offset.reset, isolation.level, partition.assignment.strategy, group.instance.id, session.timeout.ms e heartbeat.interval.ms; entra share.acknowledgement.mode (implicit ou explicit). Acknowledgements: ACCEPT (Acknowledged), RELEASE (volta a Available, delivery count preservado), REJECT (Archived, sem nova entrega) e, desde o 4.2, RENEW (estende o lock).
Fonte: ShareGroupConfig.java e GroupCoordinatorConfig.java nas tags 4.0.0, 4.1.0 e 4.2.0 do apache/kafka; tabela "Broker configuration" do KIP-932.
Compatibilidade dos clientes
Um cliente só participa de um share group se implementar as RPCs ShareGroupHeartbeat, ShareFetch e ShareAcknowledge. O KIP rejeitou tornar o KafkaConsumer comutável por configuração justamente para não quebrar frameworks como o Kafka Connect.
| Cliente | Share Groups | Evidência |
|---|---|---|
Java kafka-clients 4.1+ (KafkaShareConsumer) |
sim | Classe definida pelo KIP-932; RPCs v1 estabilizadas no 4.1. |
| Spring for Apache Kafka 4.0+ | sim | Documentação "Kafka Queues (Share Consumer)"; produção com Spring Kafka 4.1 sobre Kafka 4.2. |
| Kafka Connect (sinks) | em proposta | Hoje consome com consumer groups. O KIP-1302 (em discussão desde abril de 2026, KAFKA-20367) propõe um WorkerShareSinkTask que usa KafkaShareConsumer por opção (consumer.override.group.protocol=share), sem mudar a API dos connectors; só para sinks, at-least-once, com exactly-once dependente do KIP-1289. |
| Kafka Streams | não | Consome com consumer groups (protocolo do KIP-1071); sem proposta para share groups. |
| librdkafka, Python, Go e outros | verificar | Não verificados aqui; cada cliente precisa implementar o protocolo. |
Para uma prova de conceito, o caminho disponível é um consumidor Java próprio (ou Spring Kafka) com KafkaShareConsumer. Colocar um intermediário entre o share consumer e um framework que só fala consumer groups acrescenta um salto e enfraquece o acknowledgement fim a fim. O critério objetivo de compatibilidade é o suporte às RPCs do KIP-932.
Limites: partições, registros in-flight e teto de vazão
O broker só guarda estado dos registros que estão entregues a algum consumidor e ainda não confirmados (a janela in-flight); o backlog que espera no log não ocupa memória nem lock. Como essa janela tem um tamanho máximo fixo por share-partition, e cada registro passa um tempo médio dentro dela, o número de registros que o grupo consegue processar por segundo também tem um máximo, calculado nesta parte. Os exemplos numéricos usam um tópico hipotético de 64 partições (e de 128, para comparação), o default de 2 000 locks por share-partition e vazões da ordem de milhares de registros por segundo.
Partições em um share group
-
O número de partições define quantos registros podem estar entregues aos consumidores ao mesmo tempo. Cada share-partition entrega no máximo
group.share.partition.max.record.locksregistros (2 000 por default) que ainda não foram confirmados; o máximo do tópico é a soma. No exemplo de 64 partições: 64 × 2 000 = 128 000 registros em processamento simultâneo; com 128 partições, 128 × 2 000 = 256 000. Registros além disso ficam no log aguardando, sem lock, até que confirmações abram espaço na janela. Menos partições reduzem esse máximo e concentram o estado em menos Share-Partition Leaders. -
Partições continuam sendo a unidade de paralelismo dos produtores e da replicação. Share Groups mudam o lado do consumo; a vazão de escrita por partição, a distribuição de líderes entre brokers e a referência de partições por broker das boas práticas do MSK (1 000 por broker
kafka.m5.largeoukafka.m7g.large, 1 500 para updates) valem como antes. -
Kafka não reduz partições de um tópico existente. Reduzir um tópico de 128 para 64 partições, por exemplo, exige criar um tópico novo, reapontar todos os produtores e drenar o antigo. Para o dimensionamento de partições, a regra prática usual,
partições = max(T ÷ p, T ÷ c), em queTé a vazão alvo,pa vazão de um produtor por partição eca de um consumidor por partição, continua aplicável ao lado do produtor, enquanto o lado do consumidor passa a ser limitado pelo teto de registros in-flight descrito a seguir.
Figura 13. KIP-932: "The share-partition leader limits the distance between the SPSO and the SPEO. The upper bound is controlled by the broker configuration group.share.partition.max.record.locks." Um backlog de milhões de registros não implica milhões de locks.
| Tema | Detalhe |
|---|---|
| Valor efetivo do teto no MSK | O MSK 4.1.x roda Kafka 4.1: default 2 000 (faixa 100 a 10 000). O valor 200 pertence ao Kafka 4.0. A lista pública de configurações customizáveis do MSK ainda não inclui essa propriedade, então o planejamento usa o default 2 000; o que será ajustável na liberação para produção será definido pelo serviço. |
| Quando o teto pesa | Com 2 000 locks, as 64 share-partitions do exemplo permitem 128 000 registros Acquired ao mesmo tempo, o que a 5 000 registros/s equivale a cerca de 26 s de processamento em andamento. Com 200 locks (Kafka 4.0) seriam 12 800 registros, menos de 3 s no mesmo ritmo, e 40 consumidores lendo 500 registros por poll (20 000) já excederiam o teto, com parte dos polls voltando vazia. O teto pesa quando o tempo de processamento por registro é longo ou quando muitos consumidores pedem lotes grandes ao mesmo tempo. Regra prática medida em benchmark independente (Vanlightly, mai-2026, Kafka 4.2): max.poll.records um pouco abaixo de max.record.locks ÷ consumidores por partição, para que os polls não voltem vazios. |
| Memória e heap | Por share-partition: SPSO/SPEO, lotes com estado e delivery count, locks ativos; dezenas de bytes por entrada, poucos MB mesmo com 256 000 registros in-flight. Mais uma share session por consumidor conectado (teto 2 000 por broker). Acompanhar HeapMemoryAfterGC (alarme em 60%). |
| Share Coordinator em backlog | Uma escrita por lote de acknowledgement, em vez de uma por registro. A 5 000 registros/s em lotes de 500, cerca de 10 escritas/s, com replication factor 3 e batching adaptativo (KIP-1224). O tamanho do backlog altera o tempo de drenagem; a taxa de escritas depende apenas da vazão de acknowledgements. Métricas: write-rate, write-latency, thread-idle-ratio, num-partitions em share-coordinator-metrics. |
| Como dimensionar o teto |
locks por share-partition ≥ (vazão alvo ÷ share-partitions) × W, onde W é o tempo médio, em segundos, que um registro passa entregue a um consumidor sem estar confirmado: da resposta do fetch que o entregou até o próximo poll() ou commit que o confirma, incluindo o processamento e a escrita no destino. No exemplo, com 5 000 registros/s, 64 share-partitions e W = 2 s: ≈ 157 registros por share-partition; o default 2 000 tem folga de mais de 12 vezes. O teto só pesa quando W cresce (destino lento) ou a vazão alvo sobe uma ordem de grandeza. |
Teto de vazão pela lei de Little
Em regime estável, registros Acquired = vazão × W. Logo vazão máxima = share-partitions × locks ÷ W, onde W é o tempo médio que um registro passa em Acquired (fetch, processamento e o próximo poll). Workers só ajudam até esse teto; a vazão alcançável é o menor entre workers × registros por poll ÷ W e o teto.
Figura 14. A lei de Little na janela in-flight: a mesma janela de oito registros com W = 2 s e com W = 4 s. As faixas correm em tempo real, na proporção indicada.
- Um registro entra na janela quando é adquirido, permanece W segundos (fetch, processamento e confirmação) e sai quando é confirmado.
- Em regime estável a janela está sempre cheia; novos fetches voltam vazios até uma confirmação abrir espaço.
- A vazão máxima é o tamanho da janela dividido por W: oito registros com W = 2 s dão quatro registros por segundo; com W = 4 s, dois. Mais consumidores não alteram esse teto.
| Share-partitions × locks | In-flight máximo | Teto com W = 0,5 s | W = 2 s | W = 5 s |
|---|---|---|---|---|
| 64 × 200 (Kafka 4.0) | 12 800 | 25 600 registros/s | 6 400 registros/s | 2 560 registros/s |
| 64 × 2 000 (Kafka 4.1+) | 128 000 | 256 000 registros/s | 64 000 registros/s | 25 600 registros/s |
| 128 × 200 | 25 600 | 51 200 registros/s | 12 800 registros/s | 5 120 registros/s |
| 128 × 2 000 | 256 000 | 512 000 registros/s | 128 000 registros/s | 51 200 registros/s |
No exemplo de 64 partições com 2 000 locks, o teto só passa a limitar acima de cerca de 256 workers a 500 registros por poll, ou com W de dezenas de segundos. Antes disso o limite tende a ser a vazão por worker, que depende do processamento e do destino. O botão "Mostrar painéis interativos" abre uma calculadora com esses parâmetros.
Share Groups deslocam o limite imposto pelas partições, mas não o eliminam. No consumer group o teto de paralelismo é um consumidor por partição. No share group o teto passa a ser de registros em processamento por partição (group.share.partition.max.record.locks), e a vazão máxima decorre dele: share-partitions × locks ÷ W. Como o número de locks é uma configuração do broker e W depende do processamento e do destino, o número de partições continua determinando o teto. Acrescentar consumidores aumenta a vazão só até esse ponto; a partir dele, os polls voltam vazios e só três coisas o elevam: mais partições, mais locks por partição ou um W menor.
Nesta posição a versão HTML tem um painel interativo (simulador da janela in-flight ou calculadora de capacidade).
A relação usada acima é a lei de Little, demonstrada por John D. C. Little em 1961 para sistemas de filas em regime estacionário, sem hipótese sobre a distribuição das chegadas ou dos tempos de serviço. No artigo original, L é o número médio de unidades no sistema, λ a taxa média de chegada e W o tempo médio que uma unidade passa no sistema, e o resultado é enunciado assim: "It is shown that, if the three means are finite and the corresponding stochastic processes strictly stationary, and, if the arrival process is metrically transitive with nonzero mean, then L = λW". Na janela in-flight de uma share-partition, L são os registros Acquired, λ a vazão de registros e W o tempo em Acquired.
Fonte: Little, J. D. C. "A Proof for the Queuing Formula: L = λW". Operations Research, vol. 9, n. 3 (maio–junho de 1961), p. 383–387, doi:10.1287/opre.9.3.383. Retrospectiva do autor: "Little's Law as Viewed on Its 50th Anniversary", Operations Research, vol. 59, n. 3 (2011), p. 536–549, doi:10.1287/opre.1110.0940.
Impacto de habilitar Share Groups nos brokers
O que um share group acrescenta ao trabalho do broker, a que esse acréscimo é proporcional e como observá-lo. Nada aqui depende do tipo ou da família de instância.
| Recurso do broker | O que os Share Groups acrescentam | Proporcional a | Métrica |
|---|---|---|---|
| CPU | Aquisição (varredura da janela, locks), acknowledgements, purgatory de ShareFetch, escritas do coordinator | registros/s de fetch e ack, não ao backlog |
CpuUser + CpuSystem, RequestHandlerAvgIdlePercent
|
| Heap | Estado in-flight por share-partition; cache de share sessions | share-partitions × locks; consumidores |
HeapMemoryAfterGC < 60% |
| Disco e replicação | Tópico __share_group_state (50 partições, replication factor 3) com poda periódica |
Lotes de acknowledgement |
KafkaDataLogsDiskUsed, write-rate do coordinator |
| Rede | Mesmos bytes por entrega; redeliveries repetem bytes | RELEASE e locks expirados |
BytesOutPerSec, acknowledgements por tipo (KIP-1103) |
A medição pública encontrada sobre o custo desse estado adicional é a série de benchmarks de Jack Vanlightly (maio de 2026, Kafka 4.2, ferramenta Dimster, clusters de três brokers com TLS), que compara consumer groups e share groups com a mesma carga e topologia. As conclusões do autor, apresentadas como educativas e não como números canônicos: share groups consumiram consistentemente mais CPU nos brokers, pela contabilidade de estado por registro; a latência fim a fim no percentil 99 ficou um pouco mais alta e mais irregular em clusters folgados; a vazão máxima sustentável ficou na mesma faixa dos consumer groups, chegando a superá-la em um dos cenários. O tamanho do acréscimo de CPU não foi quantificado em percentual no texto.
Em termos de dimensionamento, o estado adicional cresce com o número de registros in-flight e com os acknowledgements por segundo, e o backlog fora da janela não influi nele; a confirmação para um ambiente específico vem de CpuUser + CpuSystem, HeapMemoryAfterGC e das métricas do Share Coordinator medidos em uma prova de conceito com a carga real.
Autoscaling e métricas
Uma das razões para adotar Share Groups é variar o número de consumidores com a carga sem esbarrar no número de partições. Esta parte compara o comportamento do autoscaling nos dois modelos e depois trata dos sinais e das regras de escala.
No consumer group, cada instância adicionada só ajuda enquanto houver partição sem dono, e toda entrada ou saída de membro provoca um rebalance que pausa o consumo total ou parcialmente (Parte 2). No share group, uma instância nova começa a receber registros no primeiro poll(), sem redistribuição, e a saída de uma instância devolve à fila apenas os registros que ela tinha adquirido e ainda não confirmara (Parte 3). O limite de instâncias úteis deixa de ser o número de partições e passa a ser o teto de registros in-flight da Parte 5 e a capacidade do destino.
| Aspecto | Consumer group | Share group |
|---|---|---|
| Instâncias úteis | Até o número de partições; as demais ficam ociosas | Até group.share.max.size (200 por default, configurável até 1 000), enquanto o teto de vazão da Parte 5 não for atingido |
| Adicionar uma instância | Rebalance: partições trocam de dono, com pausa total (assignor eager) ou parcial (cooperativo ou KIP-848) | Sem redistribuição: a instância recebe registros no primeiro poll() e as demais continuam consumindo |
| Remover uma instância | Rebalance; registros lidos e ainda não confirmados por offset são reprocessados por quem herda a partição | Sem rebalance; registros adquiridos e não confirmados voltam a Available com delivery count + 1 e são reentregues a outras instâncias |
| Sinal de lag | Log end offset − offset confirmado, por partição; no MSK, SumOffsetLag e EstimatedMaxTimeLag
|
Log end offset − SPSO, por share-partition, exposto pelo broker a partir do Kafka 4.2 (KIP-1226); no 4.1, via Admin API |
| Quando mais instâncias não ajudam | Ao atingir o número de partições | Ao atingir o teto in-flight (share-partitions × locks ÷ W) ou a capacidade do destino |
| Cuidados na redução | Cooldown maior que o tempo de rebalance; confirmar offsets antes de sair | Confirmar o último lote (commitSync()) antes de close(); destino idempotente, porque os registros in-flight da instância removida serão reentregues |
| Ferramentas | O scaler Kafka do KEDA (Kubernetes Event-driven Autoscaling) lê offsets de consumer groups | Verificar o suporte a share groups do scaler na versão em uso, ou expor o lag via Prometheus (Open Monitoring do MSK) para um scaler genérico |
As regras a seguir valem para os dois modelos. O que muda é o custo de cada ação de escala, menor no share group porque não há rebalance, e o teto a partir do qual novas instâncias deixam de aumentar a vazão.
Regras de escala
O tempo estimado de drenagem (ETD, estimated time to drain) responde à pergunta "em quanto tempo o backlog zera se as taxas atuais se mantiverem". Ele é calculado como backlog dividido pela diferença entre a taxa de consumo e a taxa de produção. Para consumer groups, o MSK publica essa estimativa nas métricas EstimatedMaxTimeLag e EstimatedTimeLag, disponíveis no nível DEFAULT (sem custo adicional) para o agregado por grupo e tópico; para share groups, o ponto de partida é o lag por share-partition da tabela abaixo.
O ETD funciona bem como objetivo, por exemplo "drenar em até 20 minutos", mas não como a métrica que dispara o autoscaling diretamente, por três motivos. Quando consumo e produção se aproximam, o denominador tende a zero e a estimativa salta para valores enormes. As taxas medidas em intervalos curtos oscilam com o batching dos produtores e dos consumidores. E cada ação de escala altera a própria taxa de consumo, o que realimenta a métrica e pode provocar ciclos de sobe e desce. Por isso a recomendação é usar o ETD como meta e disparar a escala pelo lag suavizado, com as regras a seguir.
- Escalar para fora quando
SumOffsetLag(MSK, DEFAULT) ourecords-lag-max, em consumer groups, ou o lag por share-partition (log end offset − SPSO), em share groups, suavizados em 1 a 5 min, passarem de um limiar por réplica por N minutos; ou quandoEstimatedMaxTimeLagexceder o objetivo (por exemplo, 20 minutos) por N minutos. - Escalar para dentro só com lag próximo de zero por M > N minutos, com tempo de espera entre ações (cooldown) maior que o tempo de rebalance (menor com
cooperative_stickye static membership). - Teto de réplicas. Em consumer groups, partições ÷ threads de consumo por instância, limite que o scaler Kafka do KEDA já aplica por default. Em share groups, o menor entre
group.share.max.sizee o número de workers que atinge o teto de vazão da Parte 5 (a calculadora daquela parte mostra esse número). - Bloquear a escala para fora quando a latência de escrita no destino estiver alta, porque nesse estado mais consumidores só transferem a fila do Kafka para o destino.
Métricas para Share Groups
| Métrica pedida para Share Groups | Onde obter | Fonte |
|---|---|---|
| Backlog depth (lag) | Lag por share-partition = log end offset − SPSO, persistido e exposto a partir do Kafka 4.2; kafka-share-groups.sh --describe --offsets. No 4.1, calcular via Admin API. |
KIP-1226, KIP-932 |
| Acquisition rate | Cliente: records-consumed-rate (consumer-share-fetch-manager-metrics); broker: grupo share-group-metrics
|
KIP-932, KIP-1103 |
| Acknowledgement rate | Cliente: acknowledgements-send-rate, acknowledgements-error-rate; broker: acknowledgements por tipo |
KIP-932, KIP-1103 |
| Redelivery rate | Sem métrica direta: contar ConsumerRecord.deliveryCount() ≥ 2 no consumidor e RELEASE no broker |
KIP-932 |
| In-flight records | Sem métrica direta no KIP-932; aproximar por acquired − acknowledged ou pelas métricas do Share-Partition Leader | KIP-1103 |
| Saúde |
share-coordinator-metrics (write-rate, write-latency, thread-idle-ratio); consumer-share-metrics (poll-idle-ratio-avg, time-between-poll-avg, fetch-latency-avg) |
KIP-932 |
Garantias de processamento
O KIP-932 define a entrega como at-least-once. O que o broker faz e o que fica com a aplicação:
| Tema | O que o Share Group faz | O que a aplicação precisa fazer |
|---|---|---|
| Idempotência | Nada: pode entregar o mesmo registro mais de uma vez (lock expirado, RELEASE, falha entre processar e confirmar) | Escrita idempotente no destino: id derivado de chave estável (id do evento ou tópico + partição + offset), upsert em vez de insert |
| Redelivery | RELEASE ou expiração do lock devolvem o registro a Available, para qualquer consumidor do grupo | Distinguir erro transitório (RELEASE) de permanente (REJECT); registrar deliveryCount |
| Acquisition lock timeout | 30 s por default; por grupo entre 15 e 60 s (limites default); RENEW no 4.2 | Lock maior que o percentil 99 do tempo de processamento de um lote, incluindo a escrita no destino; lotes menores reduzem o risco |
| Delivery count | Incrementa por aquisição; no limite (5) o registro vai para Archived; contador aproximado | Tratar como proteção contra poison messages e expor a distribuição como métrica |
| Poison messages | Falha de deserialização: o consumidor libera o registro e a exceção traz partição e offset; checksum (CRC) inválido: lote rejeitado automaticamente | Capturar RecordDeserializationException e decidir REJECT com envio à DLQ |
| Dead-letter queue | Não existe (listada em "Future Work"); no limite de entregas o registro é arquivado silenciosamente | DLQ na aplicação, em tópico próprio (padrão abaixo) |
| Exactly-once | Não suportado: acknowledgements não participam de transações | Se exigido, permanecer em consumer groups |
| Ordenação | Offsets crescentes dentro de um lote; entre lotes e consumidores não há garantia (o exemplo do KIP: registros 100 a 109 são reentregues depois de 110 a 119 quando o primeiro consumidor cai) | Logs com timestamp no evento toleram; ordem por chave exige consumer groups |
O efeito de um lock que expira no meio do processamento, e o RENEW que evita a reentrega no Kafka 4.2, estão na Figura 12 (Parte 3). O fluxo a seguir mostra onde entram ACCEPT, RELEASE e REJECT quando um registro falha.
Figura 15. Tratamento de erro com share.acknowledgement.mode=explicit. Se o último RELEASE permitido falhar, o broker arquiva o registro sem avisar; a aplicação deve ler deliveryCount() e, na última tentativa, gravar na DLQ e rejeitar. A produção na DLQ deve acontecer antes do commitSync() que envia os acknowledgements.
Para comparação, em um consumer group com auto-commit (enable.auto.commit=true) o offset pode ser confirmado antes de o registro chegar ao destino; em uma falha do processo isso equivale a at-most-once, e o commit feito só após o processamento restaura o at-least-once. Em Share Groups o acknowledgement só acontece quando a aplicação decide.
Casos de uso e limites de aplicação
Share Groups resolvem um problema específico, desacoplar o número de consumidores do número de partições com tratamento por registro. Fora dele, o consumer group continua sendo o modelo adequado.
Figura 16. Roteiro de decisão em duas etapas. As restrições do protocolo levam ao consumer group com qualquer "sim"; os cinco motivos reproduzem a tabela de casos de uso abaixo e qualquer um deles justifica o share group, desde que as condições da faixa inferior sejam atendidas. Sem motivo, o consumer group com os ajustes da Parte 2 é o caminho de menor risco.
| Caso de uso | Por que Share Groups se aplicam | O que observar |
|---|---|---|
| Fila de tarefas com tempo de processamento variável | Registros lentos não bloqueiam a partição: outros consumidores seguem adquirindo os registros seguintes; o lock protege o que está em andamento. | Lock maior que o percentil 99 do tempo de processamento; RENEW (Kafka 4.2) para tarefas longas. |
| Processamento com muitos workers efêmeros | Entrada e saída de membros não redistribui partições; não há rebalance nem pausa coletiva. | Membros por grupo limitados por group.share.max.size, 200 por default e até 1 000 por configuração; teto de vazão da Parte 5. |
| Tratamento de erro por registro | ACCEPT, RELEASE e REJECT por registro em modo explícito; delivery count separa erro transitório de poison message. | DLQ na aplicação: gravar antes de rejeitar; arquivamento no limite de entregas é silencioso. |
| Consumo cooperativo de um mesmo tópico por instâncias sem afinidade | Nenhuma instância é dona de partição; a carga se distribui pela taxa de poll de cada uma. | Idempotência no destino: o mesmo registro pode ser entregue mais de uma vez. |
| Picos de backlog com destino folgado | O número de consumidores pode crescer além das partições sem criar tópico novo. | Só ajuda se o limite for o paralelismo; se o destino ou o processamento por registro é o gargalo, mais consumidores não mudam a vazão. |
| Quando não se aplica | Motivo | Alternativa |
|---|---|---|
| Ordem por chave | Registros da mesma partição são processados por consumidores diferentes e podem ser reentregues fora de ordem. | Consumer group; ordem por partição preservada. |
| Exactly-once | Acknowledgements não participam de transações (listado em "Future Work" do KIP). | Consumer group com transações (read_committed, produtor transacional). |
| Kafka Connect e Kafka Streams | Consomem com KafkaConsumer; o KIP não tornou o consumidor comutável por configuração. Para sinks do Connect, o KIP-1302 está em discussão. |
Consumer group, ou um consumidor Java próprio na frente do destino. |
| Fetch-from-follower, static membership, assignor no cliente | Não existem em share groups. | Consumer group. |
| Ambientes Amazon MSK em setembro de 2026 | O recurso está disponível como preview no Kafka 4.1.x em brokers Standard. | Avaliar em cluster de testes; consumer groups em produção enquanto o preview vigorar. |
| Retenção curta por tamanho | Registros não entregues podem ser apagados pela retenção antes de consumidos; o share group não segura o log. | Dimensionar retenção pelo pior tempo de drenagem. |
Fontes
| Fonte | Usada para |
|---|---|
| KIP-932: Queues for Kafka (wiki do Apache Kafka, 26-jan-2026) | Conceitos, estados, componentes, RPCs, configurações, métricas, plano early access / preview / disponibilidade geral (GA), "Future Work", alternativas rejeitadas, exemplo de janela in-flight |
| ShareGroupConfig.java 4.0.0, 4.1.0, 4.2.0; GroupCoordinatorConfig.java | Defaults e faixas (200 → 2 000 locks, 30 s, 5 entregas, 200 membros, 2 000 sessions) |
| Apache Kafka: Upgrading to 4.2; 4.2.0 Release Announcement; 4.0.0 Release Announcement | Status do KIP-932 por versão (inclusive a correção da 4.2.1), share.version=1, KIP-1222/1224/1226 |
| Índice de KIPs (KIP-345, 429, 517, 848, 1103, 1206, 1222, 1224, 1226, 1240) | Static membership, rebalance cooperativo, poll-idle-ratio, novo protocolo, métricas e evoluções de share groups |
| MSK: Supported Apache Kafka versions; anúncios 4.1 e 4.2 (Express) | Disponibilidade citada na Parte 1: "Queues as a preview feature" no 4.1.x em brokers Standard, Kafka 4.2 em Express brokers e "KIP-932 not yet supported on MSK Express brokers" |
| MSK: Best practices for Standard brokers; Custom MSK configurations; Metrics details | Partições por broker, CPU < 60%, heap < 60%; propriedades customizáveis; métricas de lag e fetch |
| MSK: Migrate from ZooKeeper to KRaft; anúncio (26-ago-2026) | Migração in-place mencionada no glossário (pré-requisito: cluster em 3.9.x) |
| Terceiros: Confluent, Apache Kafka 4.3 release | KIP-1240 (Kafka 4.3) |
| Jack Vanlightly: Benchmarking Apache Kafka Consumer Groups vs Share Groups (overhead test) e Part 1: Tuning max.poll.records (mai-2026, Kafka 4.2) | Única medição independente encontrada do impacto nos brokers (CPU, latência, vazão) e regra prática de max.poll.records |
| John D. C. Little: A Proof for the Queuing Formula: L = λW (Operations Research 9(3), 1961) e Little's Law as Viewed on Its 50th Anniversary (Operations Research 59(3), 2011) | Base da fórmula de teto de vazão da Parte 5 (registros Acquired = vazão × W) |
| KIP-1302: Support Share Groups (Queue Semantics) in Kafka Connect Sink Connectors (em discussão; atualizado em 8-abr-2026) | Proposta de share groups em sink connectors do Kafka Connect: escopo, configurações e dependência do KIP-1289 para exactly-once |
Glossário
| Termo | Significado neste guia |
|---|---|
| Consumer group / share group | No consumer group cada partição é lida por um único membro (paralelismo limitado a partições, ordem garantida). No share group (KIP-932) vários membros leem as mesmas partições, com acknowledgement por registro e contagem de entregas. |
| Share-partition | Uma partição vista por um share group; cada grupo tem a sua para a mesma partição do tópico. |
| SPSO / SPEO / in-flight | Início e fim da janela de registros em consumo (share-partition start/end offset). Só os registros entre eles têm estado no broker; o teto é group.share.partition.max.record.locks. |
| Acquisition lock / delivery count | Reserva temporária de um registro para um consumidor (30 s por default). Contagem de aquisições; no limite (5) o registro é arquivado. |
| ACCEPT / RELEASE / REJECT / RENEW | Sucesso; liberar para nova tentativa; descartar em definitivo; estender o lock (Kafka 4.2). |
| Group Coordinator / Share-Partition Leader / Share Coordinator | Membership e atribuição; entrega e estado in-flight no broker líder da partição; persistência do estado em __share_group_state. |
| KRaft / ZooKeeper | KRaft (Kafka Raft) é o modo de metadados que substitui o ZooKeeper. Modos de metadados do cluster; Kafka 4.x só existe em KRaft; o MSK migra in-place a partir de 3.9.x. |
| Rebalance eager / cooperativo / KIP-848 | Todos param; só as partições movidas param (cooperative_sticky); atribuição no broker sem barreira global (Kafka 4.0). |
| Static membership | Identidade fixa do membro (group.instance.id) que evita rebalance em reinícios curtos; não existe em share groups. |
| Lag / ETD / lei de Little | Registros não consumidos; tempo estimado de drenagem = backlog ÷ (consumo − produção); itens no sistema = vazão × tempo médio no sistema. |
| DLQ / poison message | Destino para registros não processáveis; registro que falha repetidamente. Share groups não têm DLQ nativa. |
| At-least-once / exactly-once | Cada registro processado ao menos uma vez (duplicatas possíveis) ou exatamente uma vez (exige transações). Share groups são at-least-once. |
| Standard / Express brokers; Graviton3 (m7g) | Tipos de broker do MSK (Express inclui armazenamento e oferece Kafka 4.2; o KIP-932 ainda não é suportado neles). Família ARM dos brokers kafka.m7g.*. |
| Early access / preview / GA (general availability) | Estágios de maturidade no Apache Kafka: experimentação; testes sem produção; pronto para produção. |


















Top comments (0)