ArquiteturaIntermediário7 min de leitura5 seçõesanos 1990, Data aproximada

Fila × Pub/Sub

Dois 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.

Em 10 segundos

Fila e pub/sub são o mesmo cano com regras opostas de entrega. Fila é trabalho dividido: uma mensagem, um consumidor entre vários — some workers e a vazão sobe. Pub/sub é fato difundido: um evento, uma cópia para cada inscrito — some inscritos e mais gente fica sabendo. A pergunta que decide é uma só: isto deve ser feito uma vez (fila) ou conhecido por vários (pub/sub)?

Antes de ter nome

A distinção ecoa a diferença entre uma carta endereçada a um destinatário (fila) e um jornal que todos os assinantes recebem no mesmo dia (pub/sub).

  • #mensageria
  • #fila
  • #pub-sub
  • #eventos
  • #assincrono
Analogia

A senha do açougue × o alto-falante do mercado

No açougue, você tira uma senha e um único atendente — o que ficar livre — chama o seu número. É a fila: a tarefa vai para um atendente só, e contratar mais atendentes faz a fila andar mais rápido. Já o anúncio no alto-falante ('promoção no corredor 3') chega a todos os clientes de uma vez — é o pub/sub: um mesmo aviso, ouvido por todo mundo que estiver escutando. Trocar um pelo outro é ou mandar o alto-falante atender um cliente, ou tirar senha para uma promoção.

01Conceito

O que a mensagem representa

A escolha não é sobre a tecnologia, é sobre o significado da mensagem. Uma tarefa ('gere esta nota fiscal') deve ser feita uma vez: é fila, e vários workers competem por ela. Um fato ('o pedido foi pago') pode interessar a muitos: é pub/sub, e cada inscrito recebe a própria cópia.

O sintoma de ter escolhido errado é claro. Pub/sub onde devia ser fila: a mesma nota é gerada três vezes, uma por consumidor. Fila onde devia ser pub/sub: o faturamento é avisado do pagamento, mas o estoque e o e-mail nunca ficam sabendo.

Os dois modelos se combinam, e é aí que a mensageria fica poderosa. Um evento pedido-pago é publicado num tópico; entre os inscritos estão o serviço de faturamento, o de estoque e o de e-mail. Cada um recebe sua cópia (pub/sub) e, internamente, cada serviço pode ter uma fila de workers processando esses eventos em paralelo (fila). O fato é difundido uma vez; o trabalho que ele gera em cada consumidor é dividido entre muitos.

Vale ligar isso ao Observer: pub/sub é o Observer levado para além do processo. No Observer, o sujeito mantém a lista de ouvintes e os notifica por chamada de método, no mesmo processo e de forma síncrona. No pub/sub, o broker é o intermediário: o publicador não conhece os inscritos, a entrega é assíncrona e durável, e produtor e consumidor podem estar em máquinas, linguagens e tempos diferentes. É o mesmo desacoplamento 'quem avisa não conhece quem escuta', agora atravessando a rede.

02No mundo real

Como isso aparece na prática

O e-mail enviado três vezes

Cenário

Um time ligou três serviços a um tópico pub/sub de 'novo usuário', achando que balanceava carga. Cada novo cadastro disparava o e-mail de boas-vindas três vezes, uma por serviço inscrito.

Como o padrão entra

O envio de e-mail virou uma fila de trabalho com vários workers competindo pela mesma mensagem, enquanto o tópico pub/sub ficou só para os fatos que realmente interessavam a várias partes.

Trade-off: Passou a existir uma fila a mais para operar. Em troca, cada e-mail voltou a ser enviado exatamente uma vez, com a vazão escalando pelo número de workers.

O estoque que nunca soube do pagamento

Cenário

O pagamento era colocado numa fila lida pelo faturamento. Quando o estoque também precisou reagir ao pagamento, ele foi ligado à mesma fila — e passou a roubar metade das mensagens do faturamento.

Como o padrão entra

O pagamento virou um evento publicado num tópico; faturamento e estoque viraram inscritos independentes, cada um com sua própria cópia de cada evento.

Trade-off: Cada inscrito precisou ser idempotente, já que agora todos recebem tudo. Em troca, adicionar um quarto interessado ao fato passou a ser só mais uma inscrição, sem tocar em quem já existia.

03Cuidado

Onde isto dá errado

  1. Pub/Sub para dividir trabalho

    Ligar vários consumidores a um tópico não balanceia carga — replica. Cada inscrito recebe a mensagem inteira, então a tarefa é executada uma vez por consumidor. Para dividir trabalho, o modelo é fila com workers competindo.

  2. Fila para difundir um fato

    Colocar vários interessados na mesma fila faz eles competirem: cada mensagem vai para um só. Quem precisa que todos saibam do mesmo evento usa pub/sub, não uma fila compartilhada.

  3. Esquecer que pub/sub exige idempotência

    Como todo inscrito recebe cada evento, e a entrega costuma ser ao menos uma vez, cada consumidor precisa tolerar receber a mesma mensagem de novo sem duplicar o efeito.

04Implementação

Enviar para um × publicar para todos

// FILA (work queue): uma mensagem, UM consumidor a processa.
// Serve para DIVIDIR trabalho entre workers concorrentes.
await fila.enviar({ tipo: "gerar-nota", pedidoId: 42 });
// N workers competem; só um pega a mensagem. Somar workers = mais vazão.

// PUB/SUB (topico): um evento, TODOS os inscritos recebem uma cópia.
// Serve para NOTIFICAR várias partes independentes do mesmo fato.
await topico.publicar({ tipo: "pedido-pago", pedidoId: 42 });
// -> faturamento recebe, -> estoque recebe, -> e-mail recebe.
// Cada inscrito tem sua própria cópia e seu próprio ritmo.

// A pergunta que decide: o trabalho deve ser feito UMA vez
// (fila) ou o fato deve ser CONHECIDO por vários (pub/sub)?
// Errar isso ou duplica trabalho, ou perde quem precisava saber.
05Decisão

Quando usar × quando evitar

Use quando

3
  • Fila para distribuir tarefas entre workers e escalar vazão.
  • Pub/Sub para notificar várias partes do mesmo fato.
  • Os dois juntos: difundir o evento, dividir o trabalho em cada consumidor.

Evite quando

2
  • Pub/Sub quando a tarefa deve ser feita exatamente uma vez.
  • Fila quando várias partes precisam do mesmo fato.

Testar o que ficou

3 armadilhas de Fila × Pub/Sub 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.

  • SQS × SNS na AWSSQS é fila (uma mensagem, um consumidor a processa); SNS é pub/sub (um evento, todos os inscritos recebem) — a distinção virada produto.
  • RabbitMQ: queue × exchange fanoutA fila entrega a um worker do grupo; a exchange fanout replica para todas as filas inscritas — os dois modelos no mesmo broker.
  • consumer groups do KafkaDentro de um grupo, cada mensagem vai a um consumidor (fila); grupos diferentes recebem tudo (pub/sub) — os dois ao mesmo tempo.

O padrão em uma linha

Sem nome de domínio, sem cerimônia. Só a ideia.

// Fila: um consumidor. Pub/Sub: todos os inscritos.
await fila.send(job);      // trabalho
bus.publish("PedidoCriado", e); // fato

O que ele cobra

1 salto a mais entre a chamada e o efeito.

  • Escolher errado acopla demais (pub/sub onde queria dividir trabalho) ou perde entregas (fila onde queria broadcast)
  • Ambos exigem um broker a operar, monitorar e dimensionar, com sua própria falha e latência

Não vale se: produtor e consumidor vivem no mesmo processo e a chamada pode ser síncrona — aí um broker entre eles é infraestrutura sem propósito.

Onde isto aparece

Continue por aqui