La versión TL; DR
Mire este elenco de ASCII o este video , luego descubra cualquier razón por la que esto está sucediendo. La descripción del texto que sigue proporciona más contexto.
Detalles de la configuración
- Machine 1 es una computadora portátil Arch Linux, en la cual
ssh
se genera, conectándose a un SBC que funciona con Armbian (un Orange PI Zero). - El SBC está conectado a través de Ethernet a un enrutador DSL y tiene una IP de 192.168.1.150
- La computadora portátil está conectada al enrutador a través de WiFi, utilizando un dongle oficial Raspberry PI WiFi.
- También hay otra computadora portátil (Máquina 2) conectada a través de Ethernet al enrutador DSL.
Evaluación comparativa del enlace con iperf3
Cuando se compara con iperf3
, el enlace entre la computadora portátil y el SBC es inferior a los 56 MBits / seg teóricos, como se esperaba, ya que se trata de una conexión WiFi dentro de un " edificio de apartamentos " muy "abarrotado de 2,4 GHz" .
Más específicamente: después de ejecutar iperf3 -s
en el SBC, los siguientes comandos se ejecutan en la computadora portátil:
# 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
Básicamente, la carga en el SBC alcanza aproximadamente 24 MBits / seg, y la descarga desde este ( -R
) alcanza los 32 MBits / seg.
Benchmarking con SSH
Dado eso, veamos cómo le va a SSH. La primera vez que experimenté los problemas que llevaron a esta publicación fue cuando usé rsync
y borgbackup
, ambos usaron SSH como capa de transporte ... Entonces, veamos cómo SSH se desempeña en el mismo enlace:
# cat /dev/urandom | \
pv -ptebar | \
ssh [email protected] 'cat >/dev/null'
20.3MiB 0:00:52 [ 315KiB/s] [ 394KiB/s]
Bueno, eso es una velocidad abismal! Mucho más lento que la velocidad de enlace esperada ...
(En caso de que no lo sepa pv -ptevar
: muestra la velocidad actual y promedio de datos que lo atraviesan. En este caso, vemos que leer /dev/urandom
y enviar los datos a través de SSH al SBC en promedio alcanza los 400 KB / s, es decir, 3.2 MBits / seg, una cifra mucho menor que los 24 MBits / seg esperados).
¿Por qué nuestro enlace funciona al 13% de su capacidad?
¿Acaso /dev/urandom
es culpa nuestra ?
# cat /dev/urandom | pv -ptebar > /dev/null
834MiB 0:00:04 [ 216MiB/s] [ 208MiB/s]
No, definitivamente no.
¿Es quizás el SBC mismo? ¿Quizás es demasiado lento para procesar? Intentemos ejecutar el mismo comando SSH (es decir, enviar datos al SBC) pero esta vez desde otra máquina (Máquina 2) que está conectada a través de Ethernet:
# cat /dev/urandom | \
pv -ptebar | \
ssh [email protected] 'cat >/dev/null'
240MiB 0:00:31 [10.7MiB/s] [7.69MiB/s]
No, esto funciona bien: el demonio SSH en el SBC puede (fácilmente) manejar los 11 MB / s (es decir, los 100 MB / s) que proporciona su enlace Ethernet.
¿Y se carga la CPU del SBC al hacer esto?
No
Entonces...
- En cuanto a la red (según
iperf3
), deberíamos poder hacer 10 veces la velocidad - nuestra CPU puede acomodar fácilmente la carga
- ... y no involucramos ningún otro tipo de E / S (por ejemplo, unidades).
¿Qué diablos está pasando?
Netcat y ProxyCommand al rescate
Probemos simplemente viejo netcat
conexiones : ¿funcionan tan rápido como podríamos esperar?
En el SBC:
# nc -l -p 9988 | pv -ptebar > /dev/null
En la laptop:
# cat /dev/urandom | pv -ptebar | nc 192.168.1.150 9988
117MiB 0:00:33 [3.82MiB/s] [3.57MiB/s]
¡Funciona! Y funciona a la velocidad esperada, mucho mejor, 10 veces mejor.
Entonces, ¿qué sucede si ejecuto SSH usando un 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]
¡Trabajos! 10x velocidad.
Ahora estoy un poco confundido, cuando uso un "desnudo" nc
comoProxycommand
, ¿no estás haciendo exactamente lo mismo que hace SSH? es decir, ¿crear un socket, conectarse al puerto 22 del SBC y luego traspasar el protocolo SSH?
¿Por qué hay esta gran diferencia en la velocidad resultante?
PD: Este no fue un ejercicio académico : mi borg
copia de seguridad se ejecuta 10 veces más rápido debido a esto. Simplemente no sé por qué :-)
EDITAR : Se agregó un "video" del proceso aquí . Contando los paquetes enviados desde la salida de ifconfig, está claro que en ambas pruebas estamos enviando 40MB de datos, transmitiéndolos en aproximadamente 30K paquetes, solo que mucho más lento cuando no se usa ProxyCommand
.
fuente
nc
usa buffering de línea, mientras quessh
no tiene buffering. Entonces (o si es así) el tráfico ssh involucra más paquetes.Respuestas:
Muchas gracias a las personas que enviaron ideas en los comentarios. Los revisé todos:
Grabar paquetes con tcpdump y comparar los contenidos en WireShark
No hubo diferencias de importancia en los paquetes grabados.
Comprobación de la conformación del tráfico
No tenía idea de esto, pero después de mirar la página de manual "tc", pude verificar que
tc filter show
no devuelve nadatc class show
no devuelve nadatc qdisc show
... devuelve estos:
... que no parecen diferenciar entre "ssh" y "nc"; de hecho, ni siquiera estoy seguro de si la conformación del tráfico puede funcionar en el nivel del proceso (espero que funcione en direcciones / puertos / diferenciados Campo de servicios en encabezado IP).
Debian Chroot, para evitar la posible "inteligencia" en el cliente SSH de Arch Linux
No, los mismos resultados.
Finalmente - Nagle
Realizando un strace en el remitente ...
... y mirando exactamente qué sucede en el socket que transmite los datos, noté esta "configuración" antes de que comience la transmisión real:
Esto configura el socket SSH para deshabilitar el algoritmo de Nagle. Puede buscar en Google y leer todo al respecto, pero lo que significa es que SSH está dando prioridad a la capacidad de respuesta sobre el ancho de banda: le indica al núcleo que transmita todo lo escrito en este socket de inmediato y no "demore" la espera de acuses de recibo desde el control remoto.
Lo que esto significa, en términos simples, es que en su configuración predeterminada, SSH NO es una buena forma de transportar datos, no cuando el enlace utilizado es lento (como es el caso de muchos enlaces WiFi). Si estamos enviando paquetes por el aire que son "en su mayoría encabezados", ¡se desperdicia el ancho de banda!
Para demostrar que este fue realmente el culpable, usé LD_PRELOAD para "soltar" esta llamada al sistema específica:
Ahí: velocidad perfecta (bueno, tan rápido como iperf3).
Moral de la historia
Nunca te rindas :-)
Y si utiliza herramientas como
rsync
oborgbackup
que transportan sus datos a través de SSH, y su enlace es lento, intente evitar que SSH desactive Nagle (como se muestra arriba), o useProxyCommand
para cambiar SSH para conectarsenc
. Esto se puede automatizar en su $ HOME / .ssh / config:... para que todos los usos futuros de "orangepi" como host de destino en ssh / rsync / borgbackup de ahora en adelante se usen
nc
para conectarse (y, por lo tanto, dejar a Nagle solo).fuente