Uma shell interativa sobre o túnel congela durante vários segundos enquanto uma cópia de ficheiros decorre, e depois retoma como se nada tivesse acontecido. A transferência é a única coisa com um problema, mas a shell também espera, e ambas recuperam no mesmo momento. Esse padrão é a assinatura de um fluxo fiável que transporta muitas conversas, e sobrevive a quase todas as afinações que as pessoas tentam primeiro.

Vale a pena ler o sintoma com atenção porque aponta para um mecanismo e não para uma definição: a pausa é partilhada, logo a causa é partilhada, e o objeto partilhado é a ligação externa. Tudo o resto no registo parece normal enquanto acontece.

O sintoma: tudo pára ao mesmo tempo

Duas ligações internas a bloquear ao mesmo tempo são a pista. Uma transferência lenta e uma shell lenta são conversas TCP separadas, com números de sequência e estado de congestionamento separados, pelo que uma falha numa não deveria tocar na outra. Quando param em uníssono, algo acima delas está a ordenar os seus bytes.

Esse algo é o transporte do túnel. No modo TCP, o OpenVPN escreve os pacotes encapsulados numa única ligação TCP para o par, e o contrato do TCP é a entrega por ordem de um único fluxo de bytes. Os bytes posteriores não são entregues à aplicação antes dos que faltam, independentemente da conversa interna a que pertencem.

Note o que o sintoma não diz. Não diz que o caminho está quebrado, que o servidor está sobrecarregado ou que a cifra é lenta. Esses produzem formas diferentes: débito uniformemente baixo, tempos limite ou falhas que afetam uma direção. Uma pausa partilhada que termina quando um segmento perdido é retransmitido é especificamente um efeito de ordenação.

Um fluxo de bytes externo, muitas conversas internas

Imagine o túnel a transportar uma transferência e uma shell ao mesmo tempo. Um segmento da ligação externa perde-se. Os segmentos seguintes podem chegar ao anfitrião recetor, e a pilha TCP recetora irá confirmá-los, mas não os pode entregar para cima enquanto a lacuna não for preenchida. O OpenVPN não tem, portanto, nada para ler para a shell, embora os bytes da própria shell tenham chegado há muito.

Isto é bloqueio à cabeça da fila dentro de uma ligação, e não exige que as duas aplicações partilhem uma ligação interna. Partilham a externa, o que basta.

O efeito de segunda ordem piora a situação. Um emissor interno que não vê confirmação pode retransmitir dados que a camada externa já está a tentar entregar. Essa retransmissão torna-se tráfego adicional do túnel num caminho que acabou de provar que pode perder segmentos, pelo que o trabalho de recuperação compete com a recuperação que importa.

Nada disto garante um colapso. Num caminho limpo, com idas e voltas curtas e filas generosas, o arranjo pode ser perfeitamente utilizável durante anos. A falha aparece quando perda, atraso e profundidade de fila se alinham, e é por isso que os relatos se concentram em uplinks congestionados e ligações móveis em vez de escritórios bem aprovisionados.

Porque é que um temporizador interno mais longo não pode ajudar

Elevar o tempo limite mínimo de retransmissão numa rota, com rto_min, adia a retransmissão por temporizador do tráfego TCP gerado localmente que usa essa rota. É um botão real com um efeito real, e trata do problema de segunda ordem em vez do primeiro.

ip route show
ip route show cache 2>/dev/null | head
ss -tin dst 10.70.0.1

O que não pode fazer é libertar bytes externos fora de ordem, recuperar o segmento em falta mais depressa, ou fazer o servidor de aplicações remoto adotar o mesmo temporizador. A pilha recetora continua a entregar por ordem, e o emissor no extremo distante continua a usar as suas próprias medições de ida e volta.

Também não desativa todos os outros mecanismos de recuperação de perdas. Onde uma perda real exige recuperação por temporizador, um mínimo maior faz a aplicação esperar mais antes de agir, o que é o oposto do que uma sessão sensível à latência precisa.

Um limite fixo de doze segundos aparece nos conselhos sobre este tema como se a existência de um túnel TCP o implicasse. O temporizador de retransmissão descrito na RFC 6298 deriva do tempo de ida e volta medido com recuo exponencial, pelo que um limite constante é uma escolha de política para um caminho específico e não um requisito do protocolo. Aplicado de forma ampla, esconde o sintoma ao mesmo tempo que altera a recuperação de todos os fluxos que essa rota cobre.

O que o tcp-nodelay faz e não faz

A opção de túnel que desativa o buffering ao estilo Nagle no socket de transporte tem um propósito estreito: impede que as escritas pequenas esperem por mais dados antes da transmissão. Isso ajuda o tráfego interativo a evitar um atraso extra num caminho que de resto está saudável.

Não transforma o transporte num transporte sem ordem, e não encurta a recuperação após um segmento perdido. Uma shell que pára por um tempo limite de retransmissão continuará a parar com essa opção ativa, porque a opção nunca tocou na regra de ordenação.

Confundir as duas é fácil porque ambas são descritas como correções de latência. Uma remove uma espera artificial introduzida pelo buffering; a outra exigiria mudar o que o transporte garante, e nenhuma opção de socket faz isso.

Como comparar transportes de forma justa

Se o operador o permitir e ambos os serviços existirem, compare um serviço UDP e um serviço TCP a transportar a mesma carga de trabalho pelo mesmo caminho de acesso ao mesmo servidor. Mudar de país, fornecedor ou geração de servidor entre os dois testes introduz uma variável que dominará o resultado.

Procure a pausa partilhada em vez de um número de débito. Várias aplicações internas a bloquear em conjunto durante uma perda externa é a observação que identifica o bloqueio à cabeça da fila; um único valor mais baixo num teste de velocidade não o faz.

Capturas autorizadas na interface do túnel e na interface física separam as duas camadas com clareza, porque as retransmissões internas e externas pertencem a ligações diferentes com espaços de sequência diferentes. Ver retransmissões internas enquanto o fluxo externo mostra uma lacuna é a prova direta.

Passar para UDP remove o fluxo fiável adicional e deixa o TCP interno fazer a sua própria recuperação. Não promete perda zero nem latência baixa, e um uplink saturado, filas sobredimensionadas ou um problema de MTU continuarão a precisar de correção. O tráfego fora do túnel nunca fica retido atrás da lacuna de sequência do túnel, embora ainda possa sofrer quando ambos os caminhos partilham uma ligação congestionada, e esse estrangulamento partilhado merece a sua própria investigação em vez de ser dobrado nesta.

Artigos relacionados