Por que usar mensageria assíncrona
Veja como as filas desacoplam produtores e consumidores.
Por que usar mensageria assíncrona é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.
Por que usar mensagens assíncronas
Em uma solicitação síncrona, seu processo PHP fica bloqueado enquanto se comunica com gateways de e-mail, processadores de pagamentos ou serviços dependentes. Sob carga, isso vincula sua latência e disponibilidade a cada dependência chamada. As mensagens assíncronas rompem essa cadeia: o produtor coloca uma mensagem em uma fila e retorna imediatamente; os consumidores a processam mais tarde, no próprio ritmo.
Esta lição aborda o motivo — desacoplamento, armazenamento temporário e as concessões das garantias de entrega que você precisa avaliar antes de usar RabbitMQ ou Kafka.
Desacoplamento temporal e espacial
Uma fila desacopla produtores e consumidores em dois eixos:
- Espacial — nenhum dos lados precisa do endereço do outro; ambos conhecem apenas o intermediário.
- Temporal — o consumidor pode estar indisponível quando o produtor publica; a mensagem aguarda.
A versão síncrona abaixo vincula a solicitação web à disponibilidade e à velocidade do servidor de e-mail.
<?php
// Synchronous: the HTTP request blocks on SMTP
function registerUser(string $email): void {
saveUser($email);
// If SMTP is slow or down, the user waits or the request fails
sendWelcomeEmail($email); // 800ms blocking call
echo "Registered\n";
}
function saveUser(string $e): void { /* ... */ }
function sendWelcomeEmail(string $e): void { usleep(1); }
registerUser('dev@example.com');Publique e prossiga
A versão assíncrona persiste o usuário, publica uma mensagem UserRegistered e retorna. Um trabalhador separado envia o e-mail. Agora, a latência HTTP depende apenas de uma publicação rápida no intermediário local, não da ida e volta pelo SMTP.
<?php
function registerUser(string $email): void {
saveUser($email);
// Publish a lightweight event; worker handles email later
publish('user.registered', json_encode(['email' => $email]));
echo "Registered (email queued)\n";
}
function saveUser(string $e): void { /* ... */ }
function publish(string $routingKey, string $payload): void {
echo "-> queued $routingKey: $payload\n";
}
registerUser('dev@example.com');Nivelamento de carga (armazenamento temporário)
Os picos de tráfego são irregulares; a capacidade de processamento é fixa. Uma fila atua como um amortecedor: absorve um pico de 10.000 mensagens e permite que um conjunto de trabalhadores as processe a uma taxa sustentável. Sem uma fila, o pico sobrecarregaria diretamente o banco de dados ou a API dependente.
Isso é nivelamento de carga — você troca latência (as mensagens podem aguardar brevemente) por estabilidade (nada falha).
Garantias de entrega
Todo sistema de mensagens faz uma promessa de entrega. Saiba qual é a sua:
- No máximo uma vez — envie e esqueça; as mensagens podem ser perdidas, mas nunca são duplicadas.
- Pelo menos uma vez — são reenviadas até serem confirmadas; duplicatas são possíveis. Essa é a configuração padrão mais comum.
- Exatamente uma vez — sem perdas nem duplicatas; é caro e frequentemente uma ilusão parcial na camada da aplicação.
Como a maioria dos sistemas reais oferece pelo menos uma vez, seus consumidores precisam tolerar receber a mesma mensagem duas vezes.
Consumidores idempotentes
A solução para as duplicatas da entrega pelo menos uma vez é a idempotência: processar uma mensagem duas vezes produz o mesmo resultado que processá-la uma vez. A técnica usual é armazenar uma chave de deduplicação (o ID da mensagem) em um índice exclusivo.
<?php
function handle(array $msg, PDO $pdo): void {
$pdo->beginTransaction();
try {
// Unique constraint on message_id makes the insert the dedup gate
$stmt = $pdo->prepare(
'INSERT INTO processed_messages (id) VALUES (?)'
);
$stmt->execute([$msg['id']]);
} catch (PDOException $e) {
$pdo->rollBack();
echo "Duplicate {$msg['id']} skipped\n";
return; // already handled
}
chargeCustomer($msg['amount']);
$pdo->commit();
}
function chargeCustomer(int $a): void {}Confirmações e reentrega
Um consumidor sinaliza sucesso com uma confirmação. Se ele falhar antes de confirmar, o intermediário reentrega a mensagem a outro consumidor. É isso que faz a entrega pelo menos uma vez funcionar — mas significa que um ack deve ocorrer depois que o efeito colateral for confirmado, nunca antes.
Envie a confirmação cedo demais e uma falha perderá a mensagem. Envie-a tarde demais (e ocorra uma falha) e você terá uma duplicata — que sua camada de idempotência absorverá.
<?php
// Pseudocode of the consumer contract
function consumeLoop($channel): void {
while ($msg = $channel->get()) {
try {
processSideEffect($msg); // commit DB write first
$channel->ack($msg); // only then ack
} catch (\Throwable $e) {
$channel->nack($msg, requeue: true); // let it redeliver
}
}
}
function processSideEffect($m): void {}A ordenação não é gratuita
As filas não garantem ordenação global quando você escala horizontalmente os consumidores. Dois trabalhadores que retiram mensagens da mesma fila as processam em concorrência, portanto a mensagem B pode terminar antes da mensagem A.
Se a ordem for importante (por exemplo, alterações no saldo de uma conta), você precisará particionar por chave para que todas as mensagens relacionadas sejam encaminhadas em sequência a um único consumidor. O Kafka faz isso nativamente com partições; com o RabbitMQ, encaminhe usando uma função hash consistente para filas por chave.
Filas de mensagens mortas
Algumas mensagens nunca poderão ser processadas com sucesso — cargas inválidas ou referências a registros excluídos, por exemplo. Tentar processá-las indefinidamente trava a fila (uma mensagem venenosa). O padrão é uma fila de mensagens mortas (DLQ): após N tentativas malsucedidas, encaminhe a mensagem para outro local para inspeção, em vez de reenviá-la.
<?php
function consume(array $msg, $channel): void {
$attempts = ($msg['headers']['x-attempt'] ?? 0) + 1;
try {
process($msg);
$channel->ack($msg);
} catch (\Throwable $e) {
if ($attempts >= 5) {
$channel->deadLetter($msg); // park in DLQ
} else {
$channel->republish($msg, ['x-attempt' => $attempts]);
}
}
}
function process(array $m): void {}Quando NOT usar uma fila
As mensagens assíncronas acrescentam um custo operacional real: um intermediário para operar, consistência eventual para explicar à equipe de produto e depuração mais difícil entre limites de processos.
Escolha uma fila quando o trabalho for lento, sujeito a picos, passível de nova tentativa ou de envio e esquecimento. Mantenha-o síncrono quando o chamador realmente precisar do resultado agora (por exemplo, um preço oficial que o usuário precisa ver) — colocar em uma fila uma chamada que precisa de resposta apenas acrescenta latência e complexidade.
Fila versus registro
Dois formatos amplos de intermediário dão suporte a esses padrões, e o restante deste curso usa ambos:
- Uma fila de tarefas (RabbitMQ) exclui uma mensagem assim que ela é confirmada. Ela é excelente para distribuir trabalho a um conjunto de consumidores concorrentes, com roteamento por mensagem e tempos de expiração.
- Um registro de transações (Kafka) mantém as mensagens durante o período de retenção; cada consumidor acompanha seu próprio deslocamento e pode reproduzir o histórico, enquanto muitos grupos independentes de consumidores leem o mesmo fluxo.
Escolha a fila para distribuir trabalho e o registro para fluxos de eventos de alta vazão e reprodução.
<?php
$useCase = 'replay events for a new analytics service';
$broker = str_contains($useCase, 'replay') || str_contains($useCase, 'stream')
? 'Kafka (commit log)'
: 'RabbitMQ (task queue)';
echo $broker . "\n";Verificação rápida
Raciocinando sobre garantias de entrega.
Recapitulação
Agora você tem o modelo mental por trás das mensagens assíncronas:
- As filas fornecem desacoplamento espacial e temporal e atuam como um amortecedor para o nivelamento de carga.
- A maioria dos sistemas oferece pelo menos uma vez, portanto os consumidores precisam ser idempotentes.
- Envie a confirmação depois que o efeito colateral for confirmado; permita que as falhas provoquem uma reentrega.
- A ordenação exige particionamento por chave; mensagens venenosas exigem uma DLQ.
- Não coloque em uma fila o trabalho cuja resposta o chamador precisa receber de forma síncrona.
Em seguida, você colocará isso em prática com RabbitMQ no PHP.
Perguntas Frequentes
A aula “Por que usar mensageria assíncrona” é grátis?
Sim — o texto completo de “Por que usar mensageria assíncrona” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.
O que vou aprender em “Por que usar mensageria assíncrona”?
Veja como as filas desacoplam produtores e consumidores. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar PHP Academy?
Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Por que usar mensageria assíncrona”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de PHP Academy?
Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Por que usar mensageria assíncrona
- Trabalhando com RabbitMQ em PHP
- Apache Kafka com PHP
- Construindo fluxos de trabalho orientados a eventos