如何持久化存储paramiko SSHClient连接对象以复用?
无法持久化Paramiko SSH连接对象?试试这些替代方案
首先得明确一点:你没法直接序列化/持久化Paramiko的SSHClient对象,就像你遇到的错误提示那样,这些对象里包含了锁、网络套接字这类操作系统级别的资源,这些东西是没法被pickle(shelve底层用的就是pickle)序列化保存的。而且就算能保存,等你下次加载出来,原来的网络连接大概率已经超时断开了,根本没法用。
那针对你频繁建立连接耗时30秒的问题,给你几个实用的解决方案:
1. 维护一个长连接池,复用已有连接
与其想着保存连接对象,不如在程序运行期间维护一个活跃的连接池,每次需要操作服务器时优先复用现有连接:
- 用一个全局字典存储已建立的
SSHClient实例,键可以是服务器的IP/唯一标识 - 每次需要使用连接前,先检查这个连接是否还存活(比如调用
get_transport().is_active(),或者执行一条简单的测试命令echo "test") - 如果连接已断开,就重新建立并替换字典里的旧实例;如果正常,直接复用
示例代码大概是这样:
import paramiko # 全局连接池,键为服务器唯一标识,值为SSHClient实例 ssh_pool = {} def get_ssh_client(server_id, host, username, password): # 检查连接池是否有可用连接 if server_id in ssh_pool: client = ssh_pool[server_id] # 验证连接是否处于活跃状态 if client.get_transport() and client.get_transport().is_active(): return client # 连接失效,移除旧实例 del ssh_pool[server_id] # 新建连接,添加优化参数减少耗时 client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 禁用不必要的密钥查找、代理检测,加快连接速度 client.connect( host, username=username, password=password, look_for_keys=False, allow_agent=False, compress=True # 启用压缩减少传输耗时 ) ssh_pool[server_id] = client return client
2. 优化连接建立速度,减少单次连接耗时
你说每次建立连接要30秒,这其实偏慢,大概率可以通过参数优化提速:
- 禁用冗余密钥查找:在
connect()里加上look_for_keys=False, allow_agent=False(如果不用密钥登录的话),避免Paramiko遍历本地密钥文件浪费时间 - 启用压缩:添加
compress=True,减少握手过程的数据传输量 - 直接指定密钥路径:如果用密钥登录,用
key_filename="/path/to/your/private_key"明确指定密钥位置,不要让程序自动查找 - 替换域名为IP:如果用域名连接,换成服务器IP试试,有时DNS解析慢会拖长连接时间
3. 利用OpenSSH的连接复用功能(ControlSocket)
如果你可以接受用subprocess调用系统ssh命令而非纯Paramiko,OpenSSH自带的连接复用能极大减少重复连接的耗时:
- 在
~/.ssh/config里添加如下配置:
这样第一次连接后,后续的ssh命令会复用已有的连接套接字,无需重新进行密钥交换和握手Host * ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 1h - 如果一定要用Paramiko,也可以尝试基于这个控制套接字建立连接,但操作相对麻烦,不如直接用系统ssh命令便捷
总结
别再想着持久化连接对象了——网络连接是依赖实时状态的资源,本身就不具备可持久化的属性。优先考虑连接池复用活跃连接,同时优化连接建立参数减少单次耗时,这两个方案是最直接有效的。
内容的提问来源于stack exchange,提问作者greymatter
相关产品推荐
相关产品推荐

