As filas paralelas do parque
O brinquedo tem cinco filas paralelas para dar conta da multidão. Dentro de cada fila, a ordem é sagrada: quem chegou antes entra antes. Mas entre filas não há ordem nenhuma — a fila 3 pode andar mais rápido que a 1. Se um grupo de amigos precisa entrar junto e na ordem certa, todos têm que escolher a mesma fila. A chave de partição é essa escolha de fila: ela agrupa quem precisa de ordem, e deixa o resto se espalhar para o parque inteiro andar mais rápido.
A chave decide ordem e paralelismo ao mesmo tempo
A chave resolve dois problemas de uma vez, e por isso é difícil: ela define o que fica em ordem (mensagens da mesma chave) e quanto o sistema paraleliza (quantas chaves distintas espalham a carga). Uma chave boa acerta os dois; uma ruim sacrifica um pelo outro.
Os extremos mostram o trade-off. Uma chave única para tudo dá ordem total — e concentra o fluxo inteiro numa partição, matando o paralelismo. Uma chave aleatória dá paralelismo máximo — e ordem nenhuma. A chave certa é a unidade de negócio que precisa de ordem: o id do pedido, da conta, do agregado.
É literalmente o problema da shard key aplicado a um log de mensagens, e herda as mesmas armadilhas. A pior é a partição quente (hot partition): uma chave que concentra tráfego — particionar por pais num app dominado por um país, ou por tipo quando um tipo é 99% do volume — joga a carga numa partição só, e o consumidor dela vira o gargalo enquanto os outros ficam ociosos. A chave precisa ao mesmo tempo garantir a ordem certa e distribuir de forma uniforme.
Há um efeito colateral operacional pouco lembrado: mudar o número de partições de um tópico costuma mudar o mapeamento chave→partição (quando é por hash do total de partições). Mensagens de uma mesma chave que antes iam para a partição 2 passam a ir para a 5, e a ordem entre as 'antigas' e as 'novas' se perde na transição. Por isso o número de partições é uma decisão de capacidade que se planeja com folga desde o começo — reparticionar um tópico vivo é tão delicado quanto rebalancear shards.
Como isso aparece na prática
O 'pedido enviado' processado antes do 'pedido pago'
Cenário
Eventos de pedido eram distribuídos sem chave, espalhados por partições para paralelizar. Ocasionalmente, o evento 'enviado' era processado antes do 'pago', deixando pedidos como enviados sem pagamento confirmado.
Como o padrão entra
As mensagens passaram a ser particionadas pela chave pedido.id: todos os eventos de um mesmo pedido caem na mesma partição e são processados na ordem em que ocorreram.
Trade-off: O paralelismo passou a ser limitado pelo número de pedidos ativos por partição, não por mensagem. Na prática, sobra paralelismo de sobra — há muito mais pedidos que partições —, e a ordem por pedido ficou garantida.
A partição quente do cliente gigante
Cenário
Um sistema multi-inquilino particionava eventos por tenant_id. Um cliente enorme gerava mais eventos que todos os outros somados, e a partição dele vivia atrasada enquanto as demais estavam ociosas.
Como o padrão entra
A chave desse tenant passou a incorporar um sufixo (tenant + faixa de entidade), espalhando o gigante por várias partições, com a ordem mantida no nível de entidade em vez de tenant.
Trade-off: A ordem deixou de ser garantida no nível do tenant inteiro, passando a valer por entidade. Foi um ajuste aceitável, porque a ordem que o negócio exigia era por entidade, não pelo tenant como um todo.
Onde isto dá errado
Esperar ordem global entre partições
A ordem só existe dentro de uma partição. Contar com a sequência entre mensagens de partições diferentes é contar com algo que o sistema nunca prometeu — e que quebra assim que o consumo paraleliza.
Chave que concentra em partição quente
Particionar por um campo de baixa cardinalidade ou dominado por um valor joga a carga numa partição só. Como no sharding, a chave precisa distribuir uniformemente, não só agrupar o que precisa de ordem.
Reparticionar um tópico vivo sem pensar na ordem
Mudar o número de partições remapeia chaves para partições novas e rompe a ordem entre mensagens antigas e novas de uma mesma chave. É uma migração delicada, não um ajuste de configuração qualquer.
A chave que agrupa e ordena
// Um topico e dividido em PARTICOES para escalar. A ordem das
// mensagens so e garantida DENTRO de uma particao — nunca entre elas.
// A chave de particao decide em qual particao cada mensagem cai.
await topico.publicar({
chave: pedido.id, // <- todas as mensagens deste pedido
valor: { tipo: "pago" }, // caem na MESMA particao, em ordem
});
// Mesma chave -> mesma particao -> ordem preservada entre elas.
// Chaves diferentes -> particoes diferentes -> podem correr em paralelo.
// A escolha da chave e um trade-off:
// chave = pedido.id -> ordem por pedido, bom paralelismo
// chave = "global" -> ordem TOTAL, mas 1 particao = zero paralelismo
// chave = usuario.id -> ordem por usuario; cuidado com o usuario gigante
// que vira uma particao quente (hot partition).Quando usar × quando evitar
Use quando
3- Quando algumas mensagens têm ordem obrigatória entre si, mas não com todas.
- Ao escalar o consumo de um tópico sem perder a ordem por entidade.
- Quando há uma unidade natural de ordenação que também distribui bem.
Evite quando
2- Quando a ordem entre mensagens é irrelevante.
- Quando a única chave possível concentra tudo numa partição.
Testar o que ficou
3 armadilhas de Ordenação e chave de partição viram perguntas, com o nome do padrão escondido, misturadas com padrões parecidos.
Onde isto aparece de verdade
Você já usa isto, talvez sem saber o nome.
partition key do KafkaA chave decide a partição da mensagem, e a ordem só é garantida dentro de uma partição — mesma chave, mesma ordem.MessageGroupId do SQS FIFOAgrupa mensagens que precisam ser processadas em ordem, deixando grupos diferentes correrem em paralelo.sessions do Azure Service BusAs sessões garantem ordem por chave de sessão, permitindo que chaves diferentes sejam consumidas em paralelo.
O padrão em uma linha
Sem nome de domínio, sem cerimônia. Só a ideia.
// Mesma chave → mesma partição → ordem local.
await producer.send({ key: pedidoId, value: evento });O que ele cobra
1 salto a mais entre a chamada e o efeito.
- A ordem só vale dentro de uma partição, então a escolha da chave decide o que pode e o que não pode ser ordenado
- Uma chave concentrada cria uma partição quente que vira gargalo, exatamente como uma shard key ruim
Não vale se: a ordem entre as mensagens é irrelevante para o processamento — sem exigência de sequência, particionar por chave só adiciona uma decisão a errar.
Onde isto aparece
Continue por aqui
- ShardingQuando os dados não cabem mais numa máquina — nem em disco, nem em escrita —, a saída é reparti-los: cada shard guarda um pedaço, escolhido por uma chave. Escala escrita e volume de forma horizontal, ao preço alto de perder as junções fáceis, as transações entre shards e a chance de errar a chave e nunca mais conseguir corrigir barato.
- Fila × Pub/SubDois modelos de mensageria que parecem iguais e resolvem problemas opostos. A fila divide trabalho: uma mensagem é processada por um único consumidor entre vários. O pub/sub difunde um fato: um evento chega a todos os inscritos, cada um com sua cópia. Escolher errado ou duplica trabalho que devia ser único, ou deixa de avisar quem precisava saber.
- Garantias de entregaAt-most-once perde, at-least-once duplica, e exactly-once não existe entre sistemas distintos. Entender qual das três você tem — e por que a terceira é vendida sem ser verdade — é o que decide se o cliente vai ser cobrado duas vezes.