A versão TL; DR
Assista a este elenco ASCII ou a este vídeo - depois, encontre as razões pelas quais isso está acontecendo. A descrição de texto a seguir fornece mais contexto.
Detalhes da configuração
- A Machine 1 é um laptop Arch Linux, no qual
ssh
é gerado, conectando-se a um SBC com Armbian (Orange PI Zero). - O próprio SBC é conectado via Ethernet a um roteador DSL e possui um IP 192.168.1.150
- O laptop está conectado ao roteador via WiFi - usando um dongle oficial Raspberry PI WiFi.
- Há também outro laptop (Máquina 2) conectado via Ethernet ao roteador DSL.
Comparando o link com o iperf3
Quando comparado iperf3
, o vínculo entre o laptop e o SBC é inferior aos 56 MBits / s teóricos - como esperado, pois essa é uma conexão Wi-Fi em um edifício de apartamentos de 2,4 GHz muito lotado .
Mais especificamente: após a execução iperf3 -s
no SBC, os seguintes comandos são executados no laptop:
# iperf3 -c 192.168.1.150
Connecting to host 192.168.1.150, port 5201
[ 5] local 192.168.1.89 port 57954 connected to 192.168.1.150 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 2.99 MBytes 25.1 Mbits/sec 0 112 KBytes
...
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 28.0 MBytes 23.5 Mbits/sec 5 sender
[ 5] 0.00-10.00 sec 27.8 MBytes 23.4 Mbits/sec receiver
iperf Done.
# iperf3 -c 192.168.1.150 -R
Connecting to host 192.168.1.150, port 5201
Reverse mode, remote host 192.168.1.150 is sending
[ 5] local 192.168.1.89 port 57960 connected to 192.168.1.150 port 5201
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 3.43 MBytes 28.7 Mbits/sec
...
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 39.2 MBytes 32.9 Mbits/sec 375 sender
[ 5] 0.00-10.00 sec 37.7 MBytes 31.6 Mbits/sec receiver
Então, basicamente, o upload para o SBC atinge cerca de 24 MBits / s, e o download a partir dele ( -R
) atinge 32 MBits / s.
Benchmarking com SSH
Dado isso, vamos ver como o SSH se sai. Eu experimentei os problemas que levaram a este post ao usar rsync
e borgbackup
- ambos usando SSH como uma camada de transporte ... Então, vamos ver como o SSH funciona no mesmo link:
# cat /dev/urandom | \
pv -ptebar | \
ssh [email protected] 'cat >/dev/null'
20.3MiB 0:00:52 [ 315KiB/s] [ 394KiB/s]
Bem, essa é uma velocidade abismal! Muito mais lento que a velocidade esperada do link ...
(Caso você não esteja ciente pv -ptevar
: ele exibe a taxa atual e média de dados passando por ele. Nesse caso, vemos que a leitura /dev/urandom
e o envio de dados via SSH para o SBC está atingindo, em média, 400 KB / s - ou seja, 3,2 MBits / s, um número bem menor que os 24 MBits / s esperados.)
Por que nosso link está funcionando com 13% de sua capacidade?
Talvez seja /dev/urandom
culpa nossa ?
# cat /dev/urandom | pv -ptebar > /dev/null
834MiB 0:00:04 [ 216MiB/s] [ 208MiB/s]
Não, definitivamente não.
Talvez seja o próprio SBC? Talvez seja muito lento para processar? Vamos tentar executar o mesmo comando SSH (ou seja, enviar dados para o SBC), mas desta vez a partir de outra máquina (Máquina 2) conectada pela Ethernet:
# cat /dev/urandom | \
pv -ptebar | \
ssh [email protected] 'cat >/dev/null'
240MiB 0:00:31 [10.7MiB/s] [7.69MiB/s]
Não, isso funciona bem - o daemon SSH no SBC pode (facilmente) manipular os 11 MBytes / s (ou seja, os 100 MBits / s) fornecidos pelo link Ethernet.
E a CPU do SBC é carregada ao fazer isso?
Não.
Então...
- Em termos de rede (conforme
iperf3
), devemos ser capazes de fazer 10x a velocidade - nossa CPU pode acomodar facilmente a carga
- ... e não envolvemos nenhum outro tipo de E / S (por exemplo, unidades).
O que diabos está acontecendo?
Netcat e ProxyCommand para o resgate
Vamos tentar netcat
conexões simples e antigas - elas funcionam tão rápido quanto o esperado?
No SBC:
# nc -l -p 9988 | pv -ptebar > /dev/null
No laptop:
# cat /dev/urandom | pv -ptebar | nc 192.168.1.150 9988
117MiB 0:00:33 [3.82MiB/s] [3.57MiB/s]
Funciona! E roda na velocidade esperada - muito melhor, 10x melhor -.
Então, o que acontece se eu executar o SSH usando um ProxyCommand para usar nc?
# cat /dev/urandom | \
pv -ptebar | \
ssh -o "Proxycommand nc %h %p" [email protected] 'cat >/dev/null'
101MiB 0:00:30 [3.38MiB/s] [3.33MiB/s]
Trabalho! 10x velocidade.
Agora estou um pouco confuso - ao usar um "nu" nc
como um Proxycommand
, você não está basicamente fazendo exatamente a mesma coisa que o SSH? ou seja, criando um soquete, conectando-se à porta 22 da SBC e depois colocando o protocolo SSH sobre ela?
Por que existe essa enorme diferença na velocidade resultante?
PS: Este não foi um exercício acadêmico - meu borg
backup é executado 10 vezes mais rápido por causa disso. Só não sei por que :-)
EDIT : Adicionado um "vídeo" do processo aqui . Contando os pacotes enviados a partir da saída do ifconfig, é claro que em ambos os testes estamos enviando 40 MB de dados, transmitindo-os em aproximadamente 30K pacotes - apenas muito mais devagar quando não estiver em uso ProxyCommand
.
fonte
nc
usa buffer de linha, enquantossh
que não tem buffer. Portanto (ou se houver), o tráfego ssh envolve mais pacotes.Respostas:
Muito obrigado às pessoas que enviaram idéias nos comentários. Eu passei por todos eles:
Gravando pacotes com tcpdump e comparando o conteúdo no WireShark
Não houve diferença de importância nos pacotes gravados.
Verificando a modelagem de tráfego
Não fazia ideia disso - mas, depois de examinar a página de manual "tc", pude verificar se
tc filter show
não retorna nadatc class show
não retorna nadatc qdisc show
... retorna estes:
... que não parecem diferenciar entre "ssh" e "nc" - na verdade, não tenho certeza se a modelagem de tráfego pode operar no nível do processo (eu esperaria que funcionasse em endereços / portas / Diferenciado Serviços no cabeçalho IP).
Debian Chroot, para evitar "esperteza" em potencial no cliente SSH do Arch Linux
Não, mesmos resultados.
Finalmente - Nagle
Executando um traço no remetente ...
... e olhando o que exatamente acontece no soquete que transmite os dados, notei essa "configuração" antes do início da transmissão:
Isso configura o soquete SSH para desativar o algoritmo do Nagle. Você pode pesquisar no Google e ler tudo sobre ele - mas o que isso significa é que o SSH está dando prioridade à capacidade de resposta em relação à largura de banda - instrui o kernel a transmitir qualquer coisa escrita neste soquete imediatamente e não "atrasa" a espera de agradecimentos do controle remoto.
O que isso significa, em termos simples, é que, em sua configuração padrão, o SSH NÃO é uma boa maneira de transportar dados - não quando o link usado é lento (o que ocorre com muitos links WiFi). Se estamos enviando pacotes pelo ar que são "principalmente cabeçalhos", a largura de banda é desperdiçada!
Para provar que esse era realmente o culpado, usei LD_PRELOAD para "eliminar" este syscall específico:
Há - velocidade perfeita (bem, tão rápido quanto o iperf3).
Moral da história
Nunca desista :-)
E se você usa ferramentas como
rsync
ouborgbackup
que transportam seus dados pelo SSH, e seu link é lento, tente impedir que o SSH desative o Nagle (como mostrado acima) - ou useProxyCommand
para alternar o SSH para se conectar vianc
. Isso pode ser automatizado em seu $ HOME / .ssh / config:... para que todos os usos futuros de "orangepi" como host de destino no ssh / rsync / borgbackup passem a ser usados
nc
para conectar-se (e, portanto, deixar Nagle em paz).fonte