ProxyCommand를 통해 SSH 속도가 크게 향상되었는데 그 이유는 무엇입니까?


14

TL; DR 버전

이 ASCII 캐스트 또는 이 비디오를 시청 한 다음 이러한 상황이 발생하는 이유를 생각해보십시오. 다음의 텍스트 설명은 더 많은 컨텍스트를 제공합니다.

설정 세부 사항

  • Machine 1은 Arch Linux 랩톱으로, sshArmbian 실행 SBC (오렌지 PI Zero)에 연결됩니다.
  • SBC 자체는 이더넷을 통해 DSL 라우터에 연결되며 IP는 192.168.1.150입니다.
  • 랩탑은 공식 Raspberry PI WiFi 동글을 사용하여 WiFi를 통해 라우터에 연결됩니다.
  • 이더넷을 통해 DSL 라우터에 연결된 다른 랩탑 (기계 2)도 있습니다.

위상

iperf3와의 링크 벤치마킹

로 벤치마킹 할 때 iperf3랩탑과 SBC 간의 링크는 이론적으로 56MBits / sec 미만입니다. 이는 매우 "붐비는 2.4GHz" (아파트 빌딩) 내의 WiFi 연결이기 때문 입니다.

보다 구체적으로 : iperf3 -sSBC에서 실행 한 후 다음 명령이 랩톱에서 실행됩니다.

# 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

따라서 기본적으로 SBC에 업로드하면 약 24MBits / sec에 도달하고 다운로드 ( -R)는 32MBits / sec에 도달합니다.

SSH로 벤치마킹

그렇다면 SSH가 어떻게 작동하는지 봅시다. 내가 처음 사용하는 경우이 게시물을 주도하는 문제를 경험 한 rsyncborgbackup: 그럼 같은 링크에 어떻게 SSH가 수행을 보자 ... 둘 전송 계층으로 ssh를 사용하여 -

# cat /dev/urandom | \
    pv -ptebar | \
    ssh  root@192.168.1.150 'cat >/dev/null'
20.3MiB 0:00:52 [ 315KiB/s] [ 394KiB/s]

글쎄요, 그건 끔찍한 속도입니다! 많은 느린 예상 연결 속도보다 ... (혹시 인식하지 pv -ptevar:. 그것을 통과하는 데이터의 현재 및 평균 속도를 표시이 경우, 우리가 보는 그에서 읽기 /dev/urandom와 SBC에 SSH를 통해 데이터를 전송 평균 400KB / s에 도달합니다 (예 : 3.2MBits / sec, 예상 24MBits / sec보다 훨씬 낮음).

링크의 용량이 13 % 인 이유는 무엇입니까?

아마도 우리 /dev/urandom의 잘못일까요?

# cat /dev/urandom | pv -ptebar > /dev/null
834MiB 0:00:04 [ 216MiB/s] [ 208MiB/s]

아뇨.

아마도 SBC 자체일까요? 처리하기에는 너무 느릴까요? 동일한 SSH 명령 (예 : SBC로 데이터 전송)을 실행 해 보겠습니다. 이번에는 이더넷을 통해 연결된 다른 시스템 (기계 2)에서 다음을 수행하십시오.

# cat /dev/urandom | \
    pv -ptebar | \
    ssh  root@192.168.1.150 'cat >/dev/null'
240MiB 0:00:31 [10.7MiB/s] [7.69MiB/s] 

SBC의 SSH 데몬은 이더넷 링크가 제공하는 11MBytes / sec (즉, 100MBits / sec)를 (쉽게) 처리 할 수 ​​있습니다.

그리고이 작업을 수행하는 동안 SBC의 CPU 가로 드됩니까?

CPU가 쉽게 처리

아니.

그래서...

  • 네트워크 단위로 (당 iperf3) 우리는 속도의 10 배를 할 수 있어야합니다
  • 우리의 CPU는 쉽게 부하를 수용 할 수 있습니다
  • ... 우리는 다른 종류의 I / O (예 : 드라이브)를 포함하지 않습니다.

도대체 무슨 일이야?

구조에 대한 Netcat 및 ProxyCommand

평범한 오래된 netcat연결을 시도해 봅시다. 예상대로 빨리 연결됩니까?

SBC에서 :

# nc -l -p 9988 | pv -ptebar > /dev/null

노트북에서 :

# cat /dev/urandom | pv -ptebar | nc 192.168.1.150 9988
117MiB 0:00:33 [3.82MiB/s] [3.57MiB/s] 

효과가있다! 그리고 예상보다 훨씬 빠르며 10 배 더 빠릅니다.

nc를 사용하기 위해 ProxyCommand를 사용하여 SSH를 실행하면 어떻게됩니까?

# cat /dev/urandom | \
    pv -ptebar | \
    ssh -o "Proxycommand nc %h %p" root@192.168.1.150 'cat >/dev/null'
101MiB 0:00:30 [3.38MiB/s] [3.33MiB/s]

공장! 10 배속.

이제는 약간 혼란스러워합니다. "naked"를 ncProxycommand사용할 때 기본적으로 SSH와 동일한 작업을 수행하지 않습니까? 즉, 소켓을 만들고 SBC의 포트 22에 연결 한 다음 SSH 프로토콜을 삽니까?

결과 속도에 왜 이렇게 큰 차이가 있습니까?

PS 이것은 아니었다 학술 운동 - 내 borg백업이 10 배 빠른 이것 때문에 실행됩니다. 난 그냥 왜 :-) 몰라

편집 : 여기 에 프로세스의 "비디오"를 추가했습니다 . ifconfig의 출력에서 ​​전송 된 패킷을 계산할 때 두 테스트에서 40MB의 데이터를 전송하여 약 30K 패킷으로 전송한다는 것은 분명합니다 ProxyCommand.


버퍼링? nc라인 버퍼링을 사용하는 반면 버퍼링 은 사용 하지 않는다고 생각 합니다 ssh. 따라서 ssh 트래픽에는 더 많은 패킷이 포함됩니다.
Ralph Rönnquist

나는 전문가는 아니지만 오렌지 0에는 CPU로 제어되는 하나의 USB 버스 만 있고 네트워크는 USB 버스를 통과하며 CPU는 소프트웨어를 통해 임의의 숫자를 만들어야합니다 (아키텍처를 통해 그런 종류의 칩은 없습니다) 하드웨어)와 동시에 ssh 사이퍼가 진행 중이며 아마도 ssh 압축도 있습니다. 나는이 모든 것을 확인하지 않았기 때문에 내가 잘못 말하는 것이 가능합니다.
D' Arcy Nader

2
@ D' ArcyNader : 아니오, 당신이 잘못했다고 두려워요. Tbe / dev / urandom은 랩탑에서 발생하며 (x86)-Machine 2에서 SBC와 동일한 속도로 테스트하여 최고 속도 (100MBits / sec)에 도달하여 SBC가 트래픽을 처리하는 데 아무런 문제가 없음을 증명했습니다. 문제는 랩톱에서 SSH를 사용하는 경우와 netcat을 사용하도록 SSH 호출을 다시 변경하면 나타납니다. 그래서 dev / urandom을 수행하고 여전히 모든 데이터를 파이핑하면 문제가 사라집니다. BTW, 단일 USB 버스는 주황색 PI가 아닌 Raspberry PI의 문제입니다.
ttsiodras

도와주지 않으면 미안 해요 설명해 주셔서 감사합니다.
D' Arcy Nader

@ RalphRönnquist :이 토끼 구멍의 원인이 된 원래 사용 사례는 rsync 및 borgbackup을 통해 백업되었습니다. 많은 도구가 SSH를 전송 메커니즘으로 사용하며 제 경우에는 이로 인해 어려움을 겪었습니다. 내가 경험하고있는 것이 실제로 "표준"SSH 동작 인 경우 netcat ProxyCommand를 통해 SSH를 생성하기 위해 모든 백업 도구에 풀 요청을 제출하면 전 세계에서 백업 속도가 즉시 빨라질 것으로 예상됩니다! 나는 그런 "거대한"발견을했다는 것을 믿을 수 없다.
ttsiodras

답변:


14

의견에 아이디어를 제출 한 사람들에게 감사드립니다. 나는 그들 모두를 겪었다.

tcpdump로 패킷 기록 및 WireShark의 내용 비교

# tcpdump -i wlan0 -w good.ssh & \
     cat signature | ssh -o "ProxyCommand nc %h %p" \
        root@192.168.1.150 'cat | md5sum' ; \
     killall tcpdump
# tcpdump -i wlan0 -w bad.ssh & \
     cat signature | ssh root@192.168.1.150 'cat | md5sum' ; \
     killall tcpdump

기록 된 패킷에서 중요성의 차이는 없었다.

트래픽 조절 확인

이것에 대해 전혀 몰랐습니다 – "tc"맨 페이지를보고 나서

  • tc filter show 아무것도 반환하지 않습니다
  • tc class show 아무것도 반환하지 않습니다
  • tc qdisc show

... 이것을 반환합니다 :

qdisc noqueue 0: dev lo root refcnt 2
qdisc noqueue 0: dev docker0 root refcnt 2
qdisc fq_codel 0: dev wlan0 root refcnt 2 limit 10240p flows 1024 quantum 1514 target 5.0ms interval 100.0ms memory_limit 32Mb ecn 

... "ssh"와 "nc"를 구분하지 않는 것 같습니다. 실제로 트래픽 조절이 프로세스 수준에서 작동 할 수 있는지 확실하지 않습니다 (주소 / 포트 / 차별에서 작동 할 것으로 예상됩니다) IP 헤더의 서비스 필드).

아치 리눅스 SSH 클라이언트에서 잠재적 인 "영리함"을 피하기위한 데비안 Chroot

아뇨, 같은 결과입니다.

마지막으로-Nagle

발신자에서 strace 수행 중 ...

pv data | strace -T -ttt -f ssh 192.168.1.150 'cat | md5sum' 2>bad.log

... 그리고 데이터를 전송하는 소켓에서 정확히 어떤 일이 발생하는지 살펴보면 실제 전송이 시작되기 전에이 "설정"을 발견했습니다.

1522665534.007805 getsockopt(3, SOL_TCP, TCP_NODELAY, [0], [4]) = 0 <0.000025>
1522665534.007899 setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0 <0.000021>

이것은 Nagle 알고리즘을 비활성화하기 위해 SSH 소켓을 설정합니다. 구글은 모든 것을 읽을 수있다. 그러나 의미하는 바는 SSH가 대역폭보다 응답성에 우선 순위를두고 있다는 점이다. 커널은이 소켓에 쓰여진 모든 것을 즉시 전송하도록 지시하고 원격으로부터 승인을 기다리지 않고 "지연"한다.

이것이 의미하는 바는 기본 구성에서 SSH가 데이터를 전송하는 좋은 방법이 아니라는 것입니다. 사용되는 링크가 느린 경우가 아닙니다 (많은 WiFi 링크의 경우). "대부분 헤더"인 패킷을 무선으로 보내면 대역폭이 낭비됩니다!

이것이 실제로 범인임을 증명하기 위해 LD_PRELOAD를 사용하여이 특정 syscall을 "삭제"했습니다.

$ cat force_nagle.c

#include <stdio.h>
#include <dlfcn.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>

int (*osetsockopt) (int socket, int level, int option_name,
           const void *option_value, socklen_t option_len) = NULL;

int setsockopt(int socket, int level, int option_name,
           const void *option_value, socklen_t option_len)
{
    int ret;
    if (!osetsockopt) {
        osetsockopt = dlsym(RTLD_NEXT, "setsockopt");
    }

    if (option_name == TCP_NODELAY) {
        puts("No, Mr Nagle stays.");
        return 0;
    }
    ret = osetsockopt(socket, level, option_name, option_value, option_len);
    return ret;
}

$ gcc -fPIC -D_GNU_SOURCE -shared -o force_nagle.so force_nagle.c -ldl

$ pv /dev/shm/data | LD_PRELOAD=./force_nagle.so ssh root@192.168.1.150 'cat >/dev/null'
No, Mr Nagle stays.
No, Mr Nagle stays.
 100MiB 0:00:29 [3.38MiB/s] [3.38MiB/s] [================================>] 100%   

완벽한 속도 (iperf3만큼 빠름).

이야기의 사기

절대 포기하지 마 :-)

그리고 SSH를 통해 데이터를 전송하는 것과 같은 도구를 사용 rsync하거나 borgbackup링크가 느린 경우 링크가 느리면 SSH가 Nagle을 비활성화하지 않도록 설정하거나 (위 그림 참조) ProxyCommandSSH를 통해 연결을 통해 연결하십시오 nc. $ HOME / .ssh / config에서 자동화 할 수 있습니다.

$ cat .ssh/config
...
Host orangepi
    Hostname 192.168.1.150
    User root
    Port 22
    # Compression no
    # Cipher None
    ProxyCommand nc %h %p
...

ssh / rsync / borgbackup에서 대상 호스트로 "orangepi"를 향후에 모두 사용 nc하면 연결에 사용 되므로 Nagle을 그대로 둡니다.


고마워, 내 생명을 구했어! 왜 이것을 제어 할 수있는 설정이 없는지 이해하기 위해 ssh 사람들에게 연락하려고 했습니까?
static_rtti

1
나의 발견이 당신에게도 도움이 되었기 때문에 기쁩니다! SSH 사람들과 연락하기 위해 시도했지만, 결국 아무 일도 일어나지 않았습니다 : bugzilla.mindrot.org/show_bug.cgi?id=2848
ttsiodras

버그에 자신을 추가했습니다. 누가 결국에 무슨 일이 일어날 지 알고 있습니다! 어쨌든 훌륭한 조사.
static_rtti
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.