这两天一直都在研究openssh多路复用,碰到了一些问题,所以记录一下。
版本:OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010
配置:默认配置的基础上进行配置
所谓多路复用,在手册上是这么解释的:“在一个单一的网络连接上共享多重会话。”那为什么要使用openssh多路复用?先看看下面的测试:
这里用200个127.0.0.1来模拟200台远程机器,用下面的脚本来进行ssh测试:
[root@centos6-1 stest]# head ip.txt
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
.........
[root@centos6-1 stest]# cat ssht.sh
#!/bin/bash
while read line;do
ssh -n $line "echo ok &>/dev/null" && echo -e "\e[1;32m OK \e[0m" || echo -e "\e[1;31m FAIL \e[0m"
done < ip.txt
然后执行 time sh ssht.sh ,结果为:
[root@centos6-1 stest]# time sh ssht.sh
OK
OK
OK
OK
OK
OK
OK
...
real 0m17.460s
user 0m1.109s
sys 0m0.607s
全部成功,花了17秒秒多时间。
现在,我们开启多路复用功能。ssh客户端有两个配置文件:
~/.ssh/config#用户配置文件
/etc/ssh/ssh_config#全部配置文件
我们这里建立用户配置文件吧,vim ~/.ssh/config ,默认这个文件是不存在的,输入:
Host *
StrictHostKeyChecking no
ControlMaster auto
ControlPath /tmp/%r@%h:%p
ControlMaster打开会话共享功能,这里选项有auto、yes、no、autoask,具体含义参考man ssh_config 页。
ControlPath会话socket控制文件路径,%r表示用户,%h表示主机,%p表示端口
然后,建立socket文件,因为我使用的是OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010版本,不存在socket文件它也不会自动创建,所以要建立一下socket文件。命令为:
ssh -M -N -f 127.0.0.1
然后就会在/tmp/下生成一个名为root@127.0.0.1:22的socket文件,同时这个ssh连接一直保持在后台运行。接着我们再次执行上面的脚本测试:
[root@centos6-1 stest]# time sh ssht.sh
OK
OK
OK
OK
OK
OK
...
OK
real 0m10.001s
user 0m0.809s
sys 0m0.573s
全部成功,很明显时间缩短了不少,为什么? 因为ssh连接已经存在了,省去了每次ssh连接所花的时间。
这样,那加大机器量,在ip.txt里增加机器,模拟到2000台机器试试。
注释掉多路复用功能再次测试
这个时候出现了不少要输入密码的情况了,不知道为什么?我是使用key认证的,按道理是不会提示输入密码的。在/var/log/secure里也发现了如下日志:
Nov 7 00:21:31 centos6-1 sshd[17918]: debug1: restore_uid: 0/0
Nov 7 00:21:31 centos6-1 sshd[17918]: error: RSA_public_decrypt failed: error:0407006A:lib(4):func(112):reason(106)
Nov 7 00:21:31 centos6-1 sshd[17918]: debug1: ssh_rsa_verify: signature incorrect
Nov 7 00:21:31 centos6-1 sshd[17918]: Failed publickey for root from 127.0.0.1 port 50325 ssh2
key认证失败了,然后就弹出了要输入密码了,而且日志是狂刷呀,嘿嘿,断断续续下来花了5分多钟,因为中间出现了要输入密码等交互动作,所以延长了些。
OK
OK
OK
OK
OK
OK
real 5m30.409s
user 0m9.750s
sys 0m6.190s
好吧,那再次打开多路复用功能看看情况。
OK
OK
OK
real 1m41.759s
user 0m8.477s
sys 0m5.613s
时间大大缩短了,2000个机器操作完毕只花了1分多钟,而且没有一个失败的,没有上述需要输入密码的情况。
可是,你满足了这个耗时么?很明显不满足,还是太慢了。那就让我们改下脚本,来并发操作试试,脚本如下:
[root@centos6-1 stest]# cat tssht.sh
#!/bin/bash
Thread=5
CurFileName=ip.txt
FifoFile="$$.fifo"
mkfifo $FifoFile
exec 6<>$FifoFile
rm $FifoFile
for ((i=0;i<=$Thread;i++));do echo;done >&6
exec 5
trap 'kill -9 0;exit 1' 1 2 3 15
while read -u5 line;do
read -u6
{
ssh $line "echo OK &>/dev/null" && echo -e "\e[1;32m OK \e[0m" || echo -e "\e[1;31m FAIL \e[0m"
echo >&6
} &
done
wait
[root@centos6-1 stest]#
先同时并发5个看看:
OK
OK
OK
real 0m28.061s
user 0m4.778s
sys 0m3.009s
很好,全部成功,只花了28秒。那修改脚本,加大并发量,加大到8个看看:
OK
OK
OK
real 0m25.010s
user 0m4.833s
sys 0m3.306s
全部成功,花了25秒,继续加大到15个看看:
OK
channel 9: open failed: administratively prohibited: open failed
FAIL
OK
OK
OK
channel 1: open failed: administratively prohibited: open failed
channel 2: open failed: administratively prohibited: open failed
OK
FAIL
FAIL
OK
OK
channel 1: open failed: administratively prohibited: open failed
FAIL
OK
OK
channel 7: open failed: administratively prohibited: open failed
channel 8: open failed: administratively prohibited: open failed
OK
OK
OK
OK
FAIL
FAIL
channel 12: open failed: administratively prohibited: open failed
channel 13: open failed: administratively prohibited: open failed
FAIL
FAIL
channel 0: open failed: administratively prohibited: open faile
噢耶,出现了大量错误了!
channel 49: open failed: administratively prohibited: open failed
啥情况这是?查看/var/log/secure日志。发现有如下:
Nov 7 00:38:17 centos6-1 sshd[18830]: debug1: channel 10: new [server-session]
Nov 7 00:38:17 centos6-1 sshd[18830]: debug1: session_open: channel 10
Nov 7 00:38:17 centos6-1 sshd[18830]: error: no more sessions
没有更多的会话?明白了,然后修改sshd配置,其中有一个#MaxSessions 10,没错,默认最多允许10个会话,那我们就改大它:
MaxSessions 100
然后重启,service sshd restart,再试试:
噢,还是channel 9: open failed: administratively prohibited: open failed这种错误。
整了好久都没整明白。
把socket文件删掉,重新建立一个socket文件试试。嘿,错误居然没有了。
很显然,是原来的socket文件保持的有原来的信息,当修改了配置之后得重新建立socket才可以保存新的信息。
OK
OK
OK
OK
real 0m24.749s
user 0m5.007s
sys 0m3.830s 全部成功完成,花了24秒。时间是越来越少,所以ssh的会话共享还是蛮有用的。
另外:在过程当中可能会碰到ControlSocket /tmp/.ssh/root@127.0.0.1:22 already exists, disabling multiplexing这种错误。
这种错误的话在进行ssh操作之前没有创建socket文件,然后操作了ssh会根据config配置文件自动创建,但是第二个连接也同样会创建,所以就报错了,完了貌似还会自动删除,所以最好在进行ssh操作之间先创建好socket文件,就不会有问题了。当然,这个是5.3版本的ssh会这样。
我测试了最新版的6.3版本的ssh,如果不存在socket文件,会自动创建,第二次执行的时候就不会报这种错误了。
而且,貌似从5.5版本开始,增加了ControlPersist选项,可以控制会话保持的时间。
参考: