Downloads grandes versus a VPN: escolha o caminho na requisição
Um roteador não consegue medir o tamanho de uma resposta antes de ela chegar. Direcionar por tarefa exige um ponto de decisão na aplicação, ou uma política de fila que mantenha o caminho existente.
«Mande os downloads grandes por fora da VPN e mantenha as respostas pequenas nela» soa como política de roteamento, e não é. Um roteador decide com as informações disponíveis naquele instante: endereços, portas, protocolo, marcas de firewall, um fluxo identificado. O tamanho final de uma resposta não está nesse conjunto, porque ela ainda não chegou, e quando o roteador pudesse medir os bytes já os está transportando. Se você quer direcionar por tarefa, a decisão precisa migrar para um ponto que conheça a tarefa, e a lista de verificação abaixo mostra se o seu projeto tem esse ponto.
Por que um roteador não consegue medir uma resposta
No momento em que um pacote precisa de uma rota, o roteador viu no máximo os primeiros pacotes de um fluxo. Ele pode dizer quem fala com quem, por qual protocolo, com qual marca e quantos bytes passaram até agora. Os bytes até agora descrevem o passado. O tamanho da resposta é uma propriedade de uma resposta que ainda não foi gerada, e em respostas fragmentadas ou em streaming pode nunca ser conhecido de antemão.
Até os metadados do próprio protocolo são mais fracos do que parecem. O HTTP permite respostas cuja extensão não é anunciada antes do corpo, e uma única ação do usuário pode produzir muitas requisições cujo custo combinado não se parece com nenhum valor de cabeçalho. Tratar um cabeçalho como o tamanho de uma tarefa é um erro de modelagem antes de ser um erro de roteamento.
Verificação 1: existe um ponto de decisão que possa escolher um caminho?
Nomeie o componente que fará a escolha, e depois nomeie o que ele sabe no momento da escolha. Um atualizador que baixa de um conjunto documentado de hosts conhece seu propósito antes de a transferência começar. Um serviço de download que consulta metadados e então abre a requisição conhece a tarefa antes de a conexão existir. Um proxy cooperativo pode aplicar política no nível da requisição ou armazenar a resposta em cache sem fingir ser um roteador.
Se a resposta for «o gateway», a lista já falhou. Um gateway pode classificar fluxos conhecidos por destino, marca ou segmento de cliente e enviá-los por um caminho definido desde o primeiro pacote, o que muitas vezes basta para um atualizador aprovado e nunca basta para um tamanho de resposta desconhecido.
Verificação 2: o que os metadados realmente dizem?
O direcionamento ciente da aplicação é tão bom quanto os campos que lê. As regras de tamanho de resposta em a semântica do HTTP permitem casos em que o tamanho não está disponível no início, e as codificações de conteúdo tornam a contagem de bytes transferidos diferente do tamanho da representação de qualquer forma. Por isso uma política que troca de caminho quando um cabeçalho cruza um limite se comportará de forma inconsistente, e sobretudo justamente nas transferências grandes que deveria capturar.
O que os metadados da aplicação podem sustentar é uma decisão sobre uma tarefa: este fluxo de trabalho é uma sincronização massiva, este é interativo, este é uma atualização de software de uma origem conhecida. Isso é uma política escrita em termos de intenção, e é estável o bastante para ser testada. «Esta resposta será maior que quarenta megabytes» não é esse tipo de política.
Verificação 3: o fluxo já existe?
O roteamento pode mudar para um fluxo sem mudar a identidade da conexão, e essa distinção merece ser mantida clara. Uma conexão TCP é identificada pelos endereços e portas de suas pontas, e os pacotes podem seguir outro caminho se a tabela de roteamento mudar por baixo. O que não pode mudar de forma invisível é o estado de tradução de endereços de rede: mover o tráfego para outra saída normalmente muda a tupla de origem pública, e a ponta remota verá um par diferente sem estado correspondente.
conntrack -L -p tcp --dport 443 | head -5
ip route get 203.0.113.10
ss -tn state established dst 203.0.113.10
A regra prática, então, é que uma mudança no meio da conexão de uma saída para outra é uma relação nova, não uma migração. Se o projeto exige que a mesma conexão continue, a decisão tinha de ser tomada antes do primeiro SYN, e nenhuma regra de pacotes acrescentada depois pode reconstruí-la de forma limpa.
Verificação 4: o requisito real é latência, não saída?
Muitíssimos pedidos de «mande o tráfego massivo para outro lugar» são na verdade queixas de que uma transferência grande faz o trabalho interativo parecer lento. Isso é um problema de escalonamento, e tem uma resposta de escalonamento: uma fila justa ou uma política de largura de banda suportada no caminho existente impede que um fluxo massivo deixe uma mensagem de chat sem recursos, sem mover nenhum dos dois.
tc qdisc replace dev eth0 root cake bandwidth 100mbit
Tratar o sintoma assim mantém a decisão de saída onde a política de segurança a colocou, e é reversível com um único comando. Mudar a saída para toda uma classe de tráfego é uma mudança de política com consequências de autenticação, registro e regras de acesso, então não deveria ser a primeira ferramenta a que se recorre numa queixa de latência.
Se o requisito é realmente uma saída de internet diferente, diga isso com essas palavras e implemente numa fronteira suportada: uma conexão nova a partir de um fluxo de trabalho aprovado, ou uma aplicação que abre a própria requisição por uma saída escolhida. Depois registre quais tarefas usam qual saída, para que a próxima pessoa não precise inferir isso de uma tabela de roteamento.
Mantenha a lista de verificação no registro da mudança: o ponto de decisão, o campo ou a tarefa que o conduz, se o fluxo já existe e se o sintoma medido era latência ou saída. Quatro perguntas, e uma política que responde às quatro é uma que você pode operar em vez de defender.