前言

最近发现ansible 执行速度非常慢,执行一次playbook任务部分服务器甚至7秒以上,开启 facts 缓存、pipelining 、mitogen plugin等提升均不大,pipelining 会影响 sudo,而 mitogen 又会影响 api 的执行;正一筹莫展时,灵机一动想到了为什么不建立SSH长连接呢?这样就只需要建立一次连接,第二次直接复用大大减少ssh连接时间。遂上网查资料,并记录一下

简介

SSH 协议运行在TCP之上,当使用SSH与远程服务器建立连接时,你必须创建一条新的TCP连接。在你真正开始做有意义的动作之前,客户端和服务端都必须经过一系列协议交互,而这个协议交互的过程会花费一定的时间。

当远程部署使用SSH协议部署服务时,比如Ansible运行一个 playbook,它会创建许多SSH连接,用于传输文件或者运行命令等。Ansible每一次与服务器创建一条新SSH连接,都必须走一遍这样的协议交互。

OpenSSH是目前主流的SSH工具,如果你用的是 Linux或MacOS,那么几乎都会有预装的SSH客户端。OpenSSH支持一项优化,叫作SSH 多路复用(SSH multiplexing),有时候也叫作长连接保持(ControlPersist)。当你使用SSH多路复用连接同一个服务器的SSH会话时将会共享同一条TCP连接,这样消耗在TCP建立连接的时间就只会发生在第一次连接的时候。

当启用了多路复用:

  1. 首次SSH到服务器时,OpenSSH将启动主连接;
  2. OpenSSH创建一个UNIX 套接字(控制套接字,Control socket)维持与远程服务器的连接;
  3. 当下一次SSH到服务器时,OpenSSH将会使用已建立的控制套接字与服务器通信,而不再是重新建立新的TCP连接

主连接保持的时间根据用户的配置决定,超时后SSH客户端将会关闭这个连接。Ansible的默认配置是60s。

配置多路复用

SSH可以为给定计算机上的每个用户使用方便的配置文件。使用以下命令创建该文件:

1
2
3
4
5
# cat .ssh/config
Host *
    ControlMaster auto
    ControlPath ~/.ssh/%r@%h:%p.socket
    ControlPersist 10m

如果您连接到多个网络(例如您的LAN和/或WAN外部),则上述文件将起作用。该配置的细分为:

  • Host -连接名称
  • ControlMaster 支持通过单个网络连接共享多个会话。设置为auto时,SSH将尝试使用主连接,但如果不存在,将回退到新连接。
  • ControlPath 用于共享共享的控制unix套接字的路径。变量是:%r远程用户名,%h远程主机和%p远程端口。
  • ControlPersist 保持时间,10m告诉SSH,如果超过10分钟都没有其它的SSH连接建立则关掉这个连接。
    • 因为我这边是运维服务器,我直接配置成了5d

建议针对特定的IP进行单独配置,而不是粗暴的使用 *

通过-O check 来检查是否建立了一个主连接:

1
ssh -O check user@Server

如果主进程正在运行的话,返回将会类似于:

1
Master running (pid=30656)

如果使用 ps 30656来查看对应的进程,结果则类似于:

1
2
PID TTY      STAT   TIME COMMAND
30656 ?        Ss     0:00 ssh: /root/.ssh/root@localhost:22.socket [mux]

也可以主动使用 -O exit 参数来主动强制关闭

1
ssh -O exit user@Server

正常连接时延测试

1
2
3
4
5
time ssh localhost /bin/true

real	0m0.023s
user	0m0.004s
sys	0m0.0

来源

SSH 复用部分来自《SSH 多路复用及长连接保持