TCP, UDP e IP
As camadas de transporte abaixo do HTTP, e a troca entre entrega garantida e baixa latência.
Raramente um backend escolhe entre TCP e UDP: as bibliotecas escolhem por ele. As decisões que ficam com o desenvolvedor são outras: como reaproveitar conexões, quanto tempo esperar por elas, como mantê-las vivas e, quando houver um protocolo próprio, como delimitar as mensagens.
Quando cada transporte faz sentido
| Situação | Transporte | Por quê |
|---|---|---|
| APIs, banco de dados, filas, cache | TCP | Precisam de tudo, em ordem |
| Arquivos e transferências grandes | TCP | Entrega garantida, com controle de congestionamento |
| Consultas de DNS | UDP, com TCP para respostas grandes | Uma pergunta curta; repetir é mais barato que abrir conexão |
| Voz, vídeo, jogos em tempo real | UDP, ou WebRTC sobre UDP | Dado atrasado não serve; melhor perder do que esperar |
| Métricas enviadas em grande volume | UDP (como no StatsD) | Perder uma amostra é aceitável; não travar a aplicação é essencial |
| Web para usuários finais | HTTP/3 sobre QUIC, sobre UDP | Conexões mais rápidas e sem bloqueio por perda, tratado na borda |
Reaproveitar conexões
Abrir uma conexão TCP custa uma ida e volta; com TLS, duas ou três. Reaproveitar elimina esse custo de todos os pedidos depois do primeiro.
| Onde | Como reaproveitar |
|---|---|
| Cliente HTTP | Uma instância compartilhada do cliente, com keep-alive ligado |
| Banco de dados | Pool de conexões, criado uma vez na inicialização |
| Redis e filas | Um cliente por processo, compartilhado |
| Entre serviços com muito tráfego | HTTP/2 ou gRPC, que multiplexam vários pedidos numa conexão |
Conexões reaproveitadas trazem dois cuidados:
- Conexões ociosas morrem em silêncio. Balanceadores, firewalls e NATs fecham conexões paradas há alguns minutos sem avisar as pontas. O próximo pedido numa conexão dessas falha. Bons pools validam ou descartam conexões ociosas antigas.
- Conexões muito antigas ficam presas ao destino antigo. Uma conexão aberta continua falando com o endereço resolvido quando foi criada, mesmo que o DNS mude. O tópico de DNS mostra como limitar a idade das conexões.
Tempos limite
O TCP espera muito por padrão. Uma tentativa de conexão a um endereço que não responde pode levar mais de um minuto até desistir, e uma conexão aberta pode ficar esperando dados para sempre.
| Tempo limite | O que limita | Valor de partida |
|---|---|---|
| Conexão | Quanto esperar o handshake completar | 1 a 5 segundos dentro da mesma rede |
| Leitura | Quanto esperar por dados numa conexão aberta | Conforme o tempo esperado da operação |
| Total do pedido | O pedido inteiro, do início ao fim | O que o usuário ou o serviço chamador tolera |
| Ociosidade | Quanto uma conexão parada fica no pool | Menor que o limite do balanceador ou firewall no caminho |
Sem tempo limite de conexão, um serviço que caiu sem fechar as conexões faz cada chamada esperar o tempo do sistema operacional, e as threads ou conexões do pool se esgotam esperando.
Manter a conexão viva
O keepalive do TCP envia pequenos pacotes numa conexão ociosa para descobrir se a outra ponta ainda existe, e para que os equipamentos no caminho não a considerem abandonada.
| Configuração | O que faz | Padrão típico no Linux |
|---|---|---|
| Tempo ocioso antes do primeiro teste | Quanto esperar sem tráfego | 2 horas |
| Intervalo entre testes | Espaço entre as tentativas | 75 segundos |
| Número de testes | Quantas falhas até fechar | 9 |
O padrão de duas horas é longo demais para quase todo ambiente de nuvem, onde balanceadores costumam fechar conexões ociosas em minutos. Drivers de banco, clientes HTTP e bibliotecas de fila costumam permitir ligar o keepalive com tempos menores, ou têm o seu próprio mecanismo de verificação.
Protocolos próprios sobre TCP
Antes de criar um protocolo próprio sobre TCP, confira se HTTP, gRPC ou WebSocket resolvem: eles já tratam delimitação de mensagens, tempos limite, compressão e ferramentas de depuração. Se for mesmo necessário:
| Decisão | Opções |
|---|---|
| Delimitação | Tamanho antes dos dados (mais robusto, aceita qualquer conteúdo) ou delimitador (mais simples, exige escapar o delimitador) |
| Tamanho máximo | Sempre limitar: um tamanho anunciado de 4 GB não pode virar uma alocação de 4 GB |
| Leitura | Acumular bytes até ter uma mensagem completa, nunca tratar uma leitura como uma mensagem |
| Tempo limite | De leitura e de ociosidade, para que clientes lentos ou mortos não prendam o servidor |
Resumo da decisão
- Transporte: TCP para quase tudo no backend; UDP para tempo real, DNS e telemetria; HTTP/3 na borda.
- Conexões: reaproveitar sempre, com pool e cliente compartilhado.
- Tempos limite: de conexão, de leitura e total, em todo cliente.
- Conexões ociosas: validar ou descartar antes que o caminho as feche.
- Protocolo próprio: só se HTTP, gRPC ou WebSocket não servirem, com delimitação, tamanho máximo e tempos limite.
O próximo nível mostra um servidor TCP que lê mensagens delimitadas do jeito certo nas cinco linguagens, e ferramentas para ver as conexões de perto.
Prompts para aprofundar
Ao abrir no ChatGPT ou no Claude, o prompt é enviado ao serviço escolhido pela URL e também fica copiado na sua área de transferência.
TCP, UDP ou QUIC para o meu caso
Quero entender quando faz sentido usar cada transporte. Compare TCP, UDP e QUIC: garantias, custo de conexão, comportamento com perda de pacotes, controle de fluxo e de congestionamento, e suporte em proxies e firewalls. Depois me apresente oito situações, uma por vez, e pergunte qual transporte eu usaria e por quê: 1. Uma API REST entre microsserviços. 2. Chamadas de voz num aplicativo. 3. Envio de métricas da aplicação em grande volume. 4. Transferência de arquivos grandes. 5. Um jogo multijogador em tempo real. 6. Consultas de DNS. 7. Um site acessado por celular em redes instáveis. 8. Replicação entre dois bancos de dados. Corrija cada resposta e explique o que daria errado com a alternativa.
Configurar conexões e tempos limite
Quero configurar corretamente as conexões de rede da minha aplicação: reaproveitamento, tempos limite e keepalive. Pergunte qual linguagem eu uso, quais clientes de rede a aplicação tem (HTTP, banco, Redis, filas) e onde ela roda (nuvem, Kubernetes, atrás de qual balanceador). Para cada cliente, explique: 1. Como garantir o reaproveitamento de conexões. 2. Quais tempos limite configurar (conexão, leitura, total) e valores de partida. 3. O que acontece com conexões ociosas no meu ambiente e como evitar falhas por conexões fechadas em silêncio. 4. Se vale ligar o keepalive do TCP e com quais tempos. Termine com uma tabela de configuração para cada cliente, com os valores recomendados e o motivo de cada um.
Criar ou não um protocolo próprio
Estou pensando em criar um protocolo próprio sobre TCP para comunicação entre dois sistemas. Quero avaliar se vale a pena. Pergunte o que os sistemas trocam, em que volume e com quais requisitos de latência. Depois: 1. Avalie se HTTP, gRPC ou WebSocket resolveriam, e o que cada um já oferece pronto. 2. Se um protocolo próprio for mesmo necessário, ajude a desenhá-lo: delimitação das mensagens, tamanho máximo, versão do protocolo, tratamento de erros, tempos limite e encerramento. 3. Liste os ataques e falhas que um protocolo próprio precisa tratar, como tamanho anunciado gigante, envio lento e conexões abertas em excesso. 4. Diga como testar o protocolo, inclusive com latência e perda simuladas.