ssh多路传输multiplexing加速¶
Multiplexing的优点¶
SSH multiplexing 的一个优点是克服了创建一个新的TCP连接的消耗。对于一个主机可以接受的连接数量是有限的,并且对于一些主机限制更为明显,这和主机的负载有关,并且开启一个新的连接会有明显的延迟。当使用multiplexing的时候,重用一个已经开启的连接可以明显加速。
multiplexing和独立会话的区别是,在服务器和客户端,都只看到一个进程(即使多次连接会话)。并且,在服务器和客户机上,可以看到只打开了一个TCP连接;只不过,在客户端,后建立的会话都是通过 stream
的本地套接字来访问的。OpenSSH使用现有的TCP连接来实现多个SSH会话,这种方式降低了新建TCP连接的负载。
Multiplexing
的创建过程:
设置
ControlMaster
开启一个本地Unix domain socket其余的所有的ssh命令连接都通过Unix domain socket连接到
ControlMaster
ControlMaster
提供了以下优点:
使用已经存在的unix socket
没有新增的TCP/IP连接
不再需要密钥交换
不再需要认证等
以下是在一个Mac OS X 客户端,登陆过Linux服务器之后,关闭终端,然后又发起4次ssh登陆(没有退出)情况下的检查:
Mac OS X客户端检查进程:
ps aux | grep 192.168.1.1 | grep -v grep
可以看到,系统只建立了一个ssh连接进程(有一个 [mux]
标记是 Multiplexing
huatai 59773 0.0 0.0 2490964 600 ?? Ss 3:03PM 0:00.17 ssh: /Users/huatai/.ssh/192.168.1.1-22-root [mux]
Mac OS X客户端检查连接:
netstat -an | grep 192.168.1.1
可以看到,除了第一个ssh连接是直接连接服务器的22端口,其他ssh连接都是连接本地的socket:
tcp4 0 0 192.168.1.2.51210 192.168.1.1.22 ESTABLISHED
5a240da08f6284a9 stream 0 0 0 5a240da069f57959 0 0 /Users/huatai/.ssh/192.168.1.1-22-root.FqablQb5EvN7v2Yj
5a240da083696e09 stream 0 0 0 5a240da07cccff31 0 0 /Users/huatai/.ssh/192.168.1.1-22-root.FqablQb5EvN7v2Yj
5a240da08fe2c701 stream 0 0 0 5a240da05ffa3f91 0 0 /Users/huatai/.ssh/192.168.1.1-22-root.FqablQb5EvN7v2Yj
5a240da08a80ec79 stream 0 0 0 5a240da069f56441 0 0 /Users/huatai/.ssh/192.168.1.1-22-root.FqablQb5EvN7v2Yj
5a240da069f57251 stream 0 0 5a240da06f2ca8c9 0 0 0 /Users/huatai/.ssh/192.168.1.1-22-root.FqablQb5EvN7v2Yj
在Linux服务器上观察可以看到进程:
ps aux | grep ssh | grep -v grep
显示只有一个客户端连接:
root 1052 0.0 0.0 82548 3536 ? Ss Jan27 0:05 /usr/sbin/sshd -D
root 34640 0.0 0.0 140788 4988 ? Ss 15:03 0:00 sshd: root@pts/0,pts/1,pts/2,pts/3
观察客户端ssh连接也确实只有一个:
netstat -an | grep 192.168.1.2
输出显示:
tcp 0 36 192.168.1.1:22 192.168.1.2:51210 ESTABLISHED
从上述观察来看,启用了 Multiplexing
之后,客户机和服务器只需要建立一个SSH连接,就能够满足客户端大量的并发连接
设置Multiplexing¶
OpenSSH通过 ControlMaster
, ControlPath
和 ControlPersist
配置来实现multiplexing:
ControlMaster
决定ssh是否监听控制连接并且如何处理ControlPath
是控制套接字的位置ControlPersist
是配合ControlMaster
设置,如果设置成yes
则会在后台始终开启主连接来接受新的连接,只到被明确地杀死或者通过-O
参数关闭。
备注
ControlPersist
选项需要 OpenSSH 5.6以上版本支持,否则会ssh时会提示错误:
Bad configuration option: ControlPersist
在用户目录下配置
~/.ssh/config
内容如下:Host machine1 HostName machine1.example.org ControlPath ~/.ssh/controlmasters/%r@%h:%p ControlMaster auto ControlPersist 10m
上述配置,就会在 ~/.ssh/controlmasters/
目录下创建控制套接字
Host machine1
也如果配置成Host *
则表示匹配所有的主机,则不需要设置HostName
ControlPath ~/.ssh/controlmasters/%r@%h:%p
设置用于共享连接的控制unix套接字路径。变量%r
,%h
和%p
表示远程ssh连接的用户名,主机名和端口。ControlMaster
设置成auto
则会无条件接受新的连接,如果这个参数设置成10
就只能接受10个多路会话。ControlPersist 10m
设置主连接保持在后台打开的时间是10分钟。如果没有客户端连接,这个后台master连接将自动终止。
备注
从OpenSSH 6.7开始 %r@%h:%p
可以合并成 %C
,这个参数会自动生成 %l%h%p%r
的哈希,优点是可以唯一标识连接
也可以配置成通用配置(对所有服务器生效):
Host *
ServerAliveInterval 60
ControlMaster auto
ControlPath ~/.ssh/%h-%p-%r
ControlPersist yes
StrictHostKeyChecking no
Compression yes
备注
这里还添加了压缩以及不检查服务器SSH key(有安全风险,但是对于有安全控制对测试环境,不断重建服务器并使用相同IP,可能需要这个参数)
管理连接套接字¶
选项
-O
用来管理连接:ssh -O check machine1 ssh -O stop machine1
备注
这个 -O stop
会清除掉旧的控制套接字,原先的已经连接的会话不受影响。新的连接将建立新的TCP连接。
手工建立multiplex连接¶
使用参数 -M
和 -S
对应的就是 ControlMaster
和 ControlPath
,所以可以使用如下命令创建多路传输:
ssh -M -S /home/fred/.ssh/controlmasters/fred@server.example.org:22 server.example.org
后续的ssh可以使用 -S
参数复用前面创建的控制套接字:
ssh -S /home/fred/.ssh/controlmasters/fred@server.example.org:22 server.example.org
结束multiplex连接¶
ssh -O stop server1
ssh -O stop -S ~/.ssh/controlmasters/fred@server1.example.org:22 server1.example.org
mux_client_request_session: read from master failed: Broken pipe
¶
有时候执行SSH的时候会遇到长时间无响应,最后出现报错:
mux_client_request_session: read from master failed: Broken pipe
这是因为在 ~/.ssh/config
中配置了 ControlPersist yes
:
当
ControlPersist yes
结合ControlMaster
一起使用的时候,指定主连接应在初始客户端连接关闭后在后台保持打开状态(等待将来的客户端连接)。如果设置为
no
(默认值),则主连接不会置于后台,并会在初始客户端连接关闭后立即关闭。如果设置为yes
或0
,则主连接将无限期地保留在后台(直到通过诸如ssh -O exit
之类的机制被杀死或关闭)。如果设置为以秒为单位的时间,或 sshd_config(5) 中记录的任何格式的时间,则后台主连接将在保持空闲(没有客户端连接)指定时间后自动终止。
这个设置带来一个问题,就是在网络不稳定情况下(如wifi或网络连接出现问题,或者ISP问题导致互联网断开超过15分钟),此时持久连接会由于网络问题而终端。在这种网络问题出现后,如果再次运行 ssh
访问服务器,会尝试使用使用之前的socket连接,并在超时后打开一个新的连接。此时就会收到 mux_client_request_session: read from master failed: Broken pipe
报错。
没有什么好的解决方法,要么移除 ControlPersist yes
,要么忽略网络错误(不在可控范围内)。
使用 ssh -v
或者 ssh -vv
可以看到详细的ssh连接排查信息,可以帮助发现上述问题