Apresentando a comunicação síncrona e assíncrona
Aula 1 — Comunicação síncrona e assíncrona
Como os serviços se comunicam entre si? Esta é uma decisão muito importante de arquitetura. Frequentemente tomamos essa decisão no automático, sem considerar as consequências. Parece simples: um serviço precisa chamar outro, então faz a chamada. Mas como essa chamada é feita? E o que acontece se o serviço estiver indisponível ou demorar demais para responder? É isso que vamos entender ao longo deste percurso sobre comunicações.
Definindo comunicação síncrona e assíncrona
Quando um serviço precisa de informações de outro serviço ou processo, há duas opções fundamentais, e essa decisão vai muito além do que parece à primeira vista. A primeira é a comunicação síncrona: esperar a resposta. O serviço A chama o serviço B e bloqueia o fluxo de execução até que o outro serviço responda. É simples e direto: fazemos a pergunta e esperamos a resposta.
A segunda opção é enviar e continuar; é o que chamamos de comunicações assíncronas. O serviço envia uma mensagem a um intermediador, uma API (Interface de Programação de Aplicações), um broker (intermediador), um barramento de eventos e segue seu fluxo. A resposta chegará em algum momento — ou pode nem chegar —, e o sistema precisa saber lidar com isso. Essa parece uma escolha apenas técnica, mas não é só isso. Essa decisão determina três aspectos que estão no coração de qualquer arquitetura: desempenho, acoplamento e resiliência.
- Desempenho: se o sistema se bloqueia ou flui.
- Acoplamento: se um serviço depende de outro estar ativo.
- Resiliência: o que acontece quando algo falha.
Definir corretamente o tipo de comunicação é extremamente importante. Definir mal é problemático. Criar uma comunicação síncrona onde deveria ser assíncrona pode impedir a escalabilidade; uma falha em cadeia pode derrubar tudo. O inverso também é verdadeiro: fazer uma comunicação assíncrona onde deveria ser síncrona adiciona complexidade desnecessária e pode comprometer a consistência de que o negócio tanto precisa.
Detalhando a comunicação síncrona
Vamos detalhar a comunicação síncrona. É a que a maioria de nós aprendeu primeiro: o serviço A chama o serviço B e fica esperando a resposta. Exemplos clássicos incluem chamadas HTTP, uso de RPC, GraphQL ou SOAP. Entre as vantagens, temos implementação simples, resposta imediata, facilidade de depuração e uma trilha de rastreamento linear. Entre as desvantagens, há o acoplamento temporal: se o serviço B estiver fora do ar, o serviço A não funciona corretamente. Podemos ter falhas em cascata: uma lentidão no serviço B ocasiona lentidão no serviço A e, com mais serviços encadeados, ocorre uma cascata de falhas. Também há aumento de latência: cada microsserviço pode ter uma latência pequena, mas a soma de todas pode resultar em uma latência muito elevada.
Não estamos afirmando que a comunicação síncrona seja ruim; ela tem seu lugar, mas exige que compreendamos seus custos. Um exemplo é a consulta de saldo bancário. Pensemos: ao abrir o aplicativo do banco e clicar em “ver saldos”, o aplicativo chama um serviço (uma API), esse serviço consulta a base de dados, e observamos o carregamento sabendo que algo está acontecendo enquanto esperamos a resposta. Esse é o processo: ficamos bloqueados, e o aplicativo não faz mais nada até obter a resposta. Isso faz sentido, pois precisamos do número naquele momento; precisamos conhecer o saldo naquele instante. Não há como mostrar um saldo provável ou uma resposta que chegará depois; precisamos fazer a solicitação, receber a resposta e aguardar até que o saldo esteja disponível na tela.
Explorando a comunicação assíncrona
Agora, sobre comunicações assíncronas: aqui o serviço A envia uma mensagem; pode enviá-la ao serviço B ou a um intermediador/barramento de eventos, como Apache Kafka, RabbitMQ, Amazon SQS ou Azure Service Bus, e segue em frente. O serviço B consome essa mensagem no seu próprio ritmo. A grande vantagem é o desacoplamento real: A e B não precisam estar ativos ao mesmo tempo; se o serviço B cair, as mensagens ficam no barramento de eventos aguardando. Outras vantagens incluem alta resiliência e escalabilidade horizontal: podemos adicionar mais consumidores para ler essas mensagens.
Tudo, porém, tem seu preço. A comunicação assíncrona traz maior complexidade, pois introduz componentes adicionais, como um broker (intermediador), consumidores e filas. Também exige a implementação de padrões de novas tentativas e de backoff (recuo), além de uma boa observabilidade.
Há outro custo: a consistência eventual; os dados ficarão temporariamente desatualizados, portanto, nossa arquitetura e nosso processo de negócio devem permitir isso; além disso, depurar torna-se mais difícil.
Um exemplo assíncrono: um pedido no iFood. Quando fazemos um pedido, aparece a tela “pedido confirmado” e pronto; o aplicativo já mostra a confirmação, mas talvez o restaurante ainda não tenha aceitado, a pessoa entregadora ainda não tenha sido notificada e o sistema de pagamentos ainda esteja processando em segundo plano. Tudo isso ocorre de forma assíncrona, em paralelo, enquanto muitas vezes já fechamos o aplicativo e vamos fazer outras coisas. Imagine se o iFood esperasse a confirmação do restaurante para exibir a tela de confirmação em uma sexta-feira à noite; como o restaurante está cheio, essa resposta pode levar 30 segundos, 1 minuto, e ficaríamos apenas olhando a tela. O sistema não escalaria nesse formato.
Equilibrando escolhas técnicas e de negócio
Esses exemplos são importantes porque mostram que uma escolha técnica dependerá muito da decisão de negócio. Precisamos fazer um equilíbrio entre comunicações síncronas e assíncronas:
- Latência: na comunicação síncrona, geralmente pode ser mais rápida para uma chamada isolada; na assíncrona, pode haver variação.
- Acoplamento: a síncrona cria dependência entre emissor e receptor; a assíncrona desacopla por meio de um broker (intermediador).
- Escalabilidade: a assíncrona tende a ter vantagem, pois consumidores independentes são mais fáceis de escalar.
- Complexidade: a síncrona é mais simples de entender; a assíncrona exige um nível de maturidade tanto no desenvolvimento quanto na arquitetura.
- Tolerância a falhas: a assíncrona leva vantagem porque a mensagem permanece persistida no broker (intermediador), facilitando a nova tentativa; não é todo o processo que vai falhar.
- Rastreabilidade: a síncrona é mais fácil de rastrear; a assíncrona exige ferramentas de observabilidade, como trilhas de rastreamento, para entendermos a trajetória entre serviços.
Regra prática: usar a comunicação síncrona quando precisamos de resposta agora, imediatamente; e usar a assíncrona quando podemos processar depois e quando precisamos escalar. Em teoria é simples; na prática, veremos nuances entre esses dois processos.
Consolidando quando usar cada uma
Quando usar cada uma? Vamos consolidar com exemplos do mundo real.
Usar a comunicação síncrona quando a resposta imediata for requisito do negócio. Autenticação: a pessoa usuária faz login e precisa saber agora se entrou ou não; não vamos usar a comunicação assíncrona para autenticação. Lembremos o exemplo da consulta de saldo: a pessoa cliente quer ver quanto tem na conta; quando o processo precisar de resposta imediata, seguimos para um cenário, para uma arquitetura síncrona.
Usar a comunicação assíncrona quando o volume for alto e imprevisível. Na gestão de logs (registros), por exemplo, são milhares de eventos por segundo: ninguém vai esperar a resposta de um registro de log. No processamento de pedidos em e-commerce (comércio eletrônico), confirmamos à pessoa cliente que recebemos o pedido e, em seguida, processamos em segundo plano outros passos, como redução de estoque, sistema de pagamentos, envio de comunicações para a área de logística e para a área de entrega, criação de pipelines (fluxos) de dados, processamento por lotes, transformações e enriquecimentos. Nesses cenários, optamos por uma arquitetura orientada a comunicações assíncronas. Percebamos: nos casos síncronos, o negócio precisa da resposta para continuar; nos assíncronos, o negócio pode continuar sem essas respostas.
Expondo custos ocultos
Quais são os custos ocultos?
Custos ocultos da comunicação síncrona: uma chamada lenta bloqueia todo o serviço, por exemplo, um timeout (tempo de espera excedido). Em caso de falha, todos tentam ao mesmo tempo, e precisamos adotar alguns padrões para evitar um caos total. Quando há bloqueio ou ausência de resposta, precisamos tratar a comunicação com um padrão de nova tentativa e um padrão de circuit breaker (disjuntor de circuito). Uma falha pode se propagar por toda a cadeia; é comum vermos isso acontecer, e é difícil de tratar.
Custos ocultos da comunicação assíncrona: os dados podem ficar temporariamente desatualizados (consistência eventual). Mensagens podem falhar e se acumular; por exemplo, podemos enviar mensagens para uma fila com prazo. Garantir a ordem correta dos eventos é muito difícil; se precisarmos de processamento em ordem, esses casos ficam mais complexos. Rastrear para onde um evento foi, depurar e traçar essas chamadas também se torna mais trabalhoso.
Não existe almoço grátis: cada escolha tem seu custo. Uma boa pessoa arquiteta não é a que escolhe “a melhor” opção em abstrato, mas a que considera claramente o custo do que está escolhendo e, consequentemente, entrega valor para o negócio.