Duas Direções de Tráfego, Uma Caixa
Bem-vindo
A maioria dos diagramas de arquitetura mostra o tráfego indo em uma direção: cliente no topo, servidor na parte inferior, seta apontando para baixo. A realidade tem tráfego indo em ambas as direções.
Ingresso: clientes externos alcançam seus serviços por meio deste caminho. Um proxy reverso na borda da sua rede termina o TLS, roteia as solicitações e aplica a política de acesso.
Egresso: seus serviços alcançam serviços externos por meio deste caminho. Chamando a API de um processador de pagamentos, buscando um destino de webhook, enviando uma solicitação a um parceiro. Frequentemente através de um proxy de encaminhamento ou de um gateway NAT com uma lista de permissões.
Muitas arquiteturas começam com uma única caixa que processa ambos os fluxos. Funciona, até o dia em que não funciona. O modo de falha é sutil, surge apenas após a existência de serviços internos suficientes, & ensina uma importante lição sobre separação de responsabilidades.
Ao final desta lição, você entenderá:
- Por que ingress & egress representam padrões de tráfego fundamentalmente diferentes, com eixos de escala diferentes & modos de falha diferentes
- Hairpin NAT & por que um proxy que tenta se conectar a si mesmo falha
- O bifurcação arquitetural: uma caixa se torna duas, & o que cada uma delas passa a possuir exclusivamente
- Ganhos de isolamento de segurança: cada lado pode restringir o acesso apenas aos seus pares realmente permitidos
- Como identificar quando seu design de caixa única cruzou o limiar em que a separação se torna necessária
Por Que as Direções Exigem Ferramentas Diferentes
Duas Cargas de Trabalho Diferentes em Uma Fronteira de Rede
Características do tráfego de entrada (ingress):
- Iniciado por partes externas (a internet em geral)
- O volume escala com sua base de usuários
- Terminação de TLS, roteamento de solicitações, limitação de taxa por origem
- Preocupações com defesa em profundidade: DDoS, abuso, raspagem de dados
- O IP público precisa aceitar conexões de qualquer pessoa
Características do tráfego de saída (egress):
- Iniciado pelos seus próprios serviços (um conjunto conhecido e pequeno de clientes)
- O volume escala com os seus padrões de chamadas entre serviços e para APIs externas
- Lista de permissão de IPs de origem nos endpoints remotos (você tem um único IP de saída fixo que os parceiros confiam)
- Preocupações com defesa em profundidade: exfiltração de dados, serviços internos comprometidos fazendo chamadas para fora
- Deve rejeitar conexões de qualquer pessoa que não seja dos seus próprios serviços
A assimetria fundamental: o tráfego de entrada (ingress) aceita tráfego do mundo; o tráfego de saída (egress) aceita tráfego apenas dos seus próprios serviços. Colocá-los na mesma máquina significa que essa máquina deve ser simultaneamente acessível pelo mundo (para o tráfego de entrada) e acessível apenas pelos seus serviços (para o tráfego de saída). As regras de firewall que satisfazem uma funcionam contra a outra.
O caminho de crescimento: um projeto minúsculo pode ocultar ambos atrás de um único IP e uma única ferramenta, porque o volume é pequeno e a lista de permissão de IPs de parceiros é curta. À medida que o projeto cresce, o atrito entre os dois papéis aumenta, e um dia um modo de falha específico (hairpin NAT) força a separação.
O Bug Que Força a Separação
Uma História de Interrupção Sanitizada
Imagine um verdadeiro ponto de bifurcação arquitetural que ocorre em frotas de produção. Os nomes abaixo foram alterados; a estrutura é idêntica ao que as equipes enfrentam no mundo real.
Uma organização opera um único servidor proxy em 203.0.113.5. Ele lida com tráfego de entrada (porta 443 para usuários) e de saída (porta 1080 SOCKS5 para serviços internos fazendo chamadas externas). Os serviços internos estão em sub-redes privadas e roteiam todo o tráfego de saída através desse proxy SOCKS5 em 203.0.113.5:1080.
Um dos serviços hospedados atrás do mesmo 203.0.113.5 é api.example.com. O DNS público resolve api.example.com para 203.0.113.5.
Agora, um serviço interno diferente precisa chamar api.example.com. Seu caminho de saída:
1. O serviço interno resolve api.example.com → 203.0.113.5
2. O serviço interno envia a solicitação através do proxy de saída SOCKS5 em 203.0.113.5:1080
3. O proxy tenta abrir uma conexão de si mesmo para 203.0.113.5:443
4. Conexão recusada. O pacote teria que sair e reentrar no mesmo NAT, o que a maioria das pilhas de rede rejeita. O proxy não pode se conectar a si mesmo através do seu próprio IP público.
Este é o hairpin NAT: um pacote que sai de um NAT e precisa reentrar no mesmo NAT para alcançar seu destino. Sem suporte especial para hairpin na camada de roteamento, o pacote é descartado.
Por que isso surge tardiamente
No início da vida do projeto, todos os serviços internos se comunicavam com outros serviços internos por nome de host privado (internal-api.local) ou não faziam chamadas de volta para os serviços públicos da própria organização. O caminho de hairpin simplesmente não existia.
Então, um novo recurso exigiu que o serviço A chamasse api.example.com (um nome de host público). O caminho de hairpin foi ativado. Conexão recusada. Interrupção.
A correção tratou o sintoma (forçar o resolver a fornecer o IP privado de api.example.com em vez do público). A causa raiz: uma única máquina estava fazendo muitos trabalhos.
O Bifurcação Arquitetural
Uma Caixa Vira Duas
A solução limpa: separar o proxy em duas máquinas.
Servidor de entrada (IP público 203.0.113.5):
- Caddy / proxy reverso nas portas 80, 443
- Registros DNS públicos apontam para aqui
- Hospeda api.example.com, app.example.com, etc.
Servidor de saída (IP público diferente 203.0.113.99):
- SOCKS5 / proxy de encaminhamento na porta 1080
- O firewall restringe as conexões de entrada apenas aos IPs da subrede interna
- Os serviços internos roteiam todo o tráfego de saída através deste endereço
O que isso proporciona:
1. Hairpin resolvido. Um serviço interno que chama api.example.com roteia a saída via 203.0.113.99 (egress), que então se conecta normalmente a 203.0.113.5 (ingress, um IP diferente). O loop de NAT desaparece porque os dois IPs estão em máquinas diferentes.
2. Isolamento de segurança. O firewall do servidor de egress pode ser bloqueado para um pequeno conjunto de IPs internos. O firewall do servidor de ingress permanece aberto para o mundo. Dois conjuntos de regras separados, cada um expressando um papel de forma limpa.
3. Escala independente. A largura de banda de ingress escala com os usuários; a largura de banda de egress escala com a atividade dos serviços internos. Atualize um sem tocar no outro.
4. Isolamento de falhas. Uma configuração incorreta de egress não quebra mais o site público. Um DDoS contra o site público não esgota mais a largura de banda de egress.
5. Modelo mental mais claro. Cada máquina tem uma função. Os engenheiros raciocinam sobre preocupações de ingress sem pensar em egress, e vice-versa.
Dois Eixos, Duas Decisões de Dimensionamento
Escalonamento Independente
Antes da separação, o crescimento em qualquer direção sobrecarregava a mesma máquina. Após a separação, cada direção possui seu próprio provisionamento.
Dimensionamento de Ingresso: escala com o número de usuários. As decisões de capacidade ficam na camada voltada para o público (mais réplicas de proxy reverso, VMs maiores, CDN na frente). O orçamento de largura de banda é calculado com base no tráfego de usuários no pico.
Dimensionamento de Egresso: escala com o volume de chamadas de serviços internos para APIs externas. Frequentemente dominado pela entrega de webhooks, chamadas a processadores de pagamento ou buscas de dados de terceiros. O orçamento de largura de banda é calculado com base nos padrões de chamadas internas.
Isolamento de falhas: um DDoS contra o ingresso público não consome mais a largura de banda de egresso (aquelas chamadas ao processador de pagamento continuam passando). Uma falha no proxy de egresso não derruba mais o site público (os usuários continuam acessando o site; apenas as chamadas de saída internas falham).
SLOs Diferentes: a disponibilidade do ingresso é importante para os usuários (interrupção visível do site); a disponibilidade do egresso é importante para os operadores (falhas em segundo plano que podem levar mais tempo para serem detectadas). Cada lado pode ter seu próprio SLO.
Múltiplos Servidores de Egresso
Uma vez que o papel de egresso seja uma máquina própria, o próximo movimento óbvio é executar várias máquinas de egresso atrás de um balanceador de carga para HA. Cada novo serviço interno aponta para o nome do host de egresso (que se resolve para o pool balanceado) em vez de um único IP.
A mesma lição do restante dos sistemas distribuídos: uma vez que uma camada se torna sem estado e tem seu próprio papel, ela se multiplica de forma barata.
Uma Nova Integração de Parceiro
Sua organização executa a separação de entrada/saída (ingress/egress) conforme projetado. O servidor de saída (egress) tem um IP público fixo (203.0.113.99) que você já permitiu (allowlist) para três APIs de parceiros existentes (um processador de pagamentos, um gateway de SMS e um provedor de e-mail).
Uma equipe de produto deseja adicionar uma quarta integração: um sistema de entrega de webhooks que faz chamadas de retorno para endpoints de clientes em todo o mundo. Previsão de volume: 10.000 chamadas por minuto, com picos de até 30.000.
Projete uma Fronteira de Rede para um Serviço em Crescimento
Síntese
Você aprendeu por que ingresso e egresso exigem ferramentas diferentes, a falha de hairpin NAT que força a separação em frotas reais, e como o escalonamento independente, o isolamento de segurança e o isolamento de falhas se acumulam uma vez que a separação é implementada.
Aplique os quatro.
Uma empresa de SaaS de médio porte opera três subdomínios de produto (app, api, admin) para seus usuários, além de quatro integrações de saída (Stripe, Twilio, SendGrid, um sistema de webhooks de cliente). Atualmente, tudo fica atrás de uma única máquina proxy em um IP público. Eles começaram a receber relatórios de falhas intermitentes de hairpin quando serviços internos tentam chamar api.example.com. Eles querem projetar uma correção permanente.
Para Onde Este Curso Vai a Seguir
Para Onde Este Curso Vai a Seguir
Você acabou de ver um dos refactors de separação de responsabilidades mais limpos em sistemas distribuídos: uma caixa se torna duas, cada uma com um papel claro, e o sistema herda benefícios de escalabilidade, segurança e isolamento de falhas ao longo do caminho.
A próxima lição (cs_distsys_failure_modes_and_blast_radius) estende o raciocínio sobre isolamento de falhas. Você lerá um postmortem sanitizado de DNS-SERVFAIL, identificará o padrão de falha em cascata e escreverá itens de ação sem culpa que visam sistemas em vez de pessoas.
Lição complementar: geometry_of_ingress_egress_separation reformula a separação como um grafo bipartido e explora vértices de corte, partições de rede e o que a teoria dos grafos nos diz sobre um limite de rede.
Muito bem. Sigamos em frente.