PHP通过SSH连接MySQL的实现方案及相关问题咨询
问题解答
问题1:PHP连接字符串写法与每次建立SSH隧道的问题
1.1 PHP连接字符串实现方式
由于服务器B仅开放22端口,MySQL的3306端口无法直接访问,需先建立SSH隧道,再通过本地转发端口连接MySQL,以下是两种常见实现:
方式一:用exec临时建隧道(适合低并发场景)
先在服务器A执行端口转发命令,再用PHP连接本地端口:
// 建立SSH隧道:将本地3307端口转发到服务器B的3306端口 exec('ssh -f -N -L 3307:127.0.0.1:3306 usera@192.168.0.102'); // PDO连接MySQL示例 try { $pdo = new PDO( 'mysql:host=127.0.0.1;port=3307;dbname=DBtest;charset=utf8mb4', 'usera', '123456', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); // 执行查询逻辑 $stmt = $pdo->query('SELECT * FROM your_table'); $data = $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { die('连接或查询失败: ' . $e->getMessage()); }
方式二:用proc_open管理隧道进程(更可控)
直接在PHP中管理SSH进程,避免残留僵尸进程:
// 定义SSH隧道命令 $cmd = 'ssh -N -L 3307:127.0.0.1:3306 usera@192.168.0.102'; $descriptorspec = [ 0 => ['pipe', 'r'], // 标准输入 1 => ['pipe', 'w'], // 标准输出 2 => ['pipe', 'w'] // 标准错误 ]; // 启动SSH进程 $process = proc_open($cmd, $descriptorspec, $pipes); if (is_resource($process)) { // 连接MySQL $pdo = new PDO( 'mysql:host=127.0.0.1;port=3307;dbname=DBtest;charset=utf8mb4', 'usera', '123456' ); // 业务逻辑... // 关闭隧道进程 proc_close($process); } else { die('SSH隧道建立失败'); }
1.2 每次建立SSH隧道的问题
- 性能开销大:每次连接都要完成SSH握手(密钥交换、身份验证等),会显著增加数据库操作的响应时间,高并发场景下延迟会被放大。
- 资源占用过高:每个隧道对应一个SSH进程,高并发时会产生大量进程,消耗服务器A的CPU、内存资源,甚至触发服务器B的SSH连接数限制。
- 稳定性差:PHP脚本异常退出时,可能残留僵尸SSH进程,长期积累会占用大量系统资源。
问题2:持久SSH连接的实现与断开重连
2.1 建立持久SSH连接的可行性
完全可以通过autossh工具在两台服务器间建立持久化SSH端口转发,PHP只需连接本地转发端口即可,无需每次建隧道。
配置步骤:
- 在服务器A配置SSH免密登录到服务器B:
# 生成密钥对(一路回车即可) ssh-keygen -t rsa # 将公钥复制到服务器B ssh-copy-id usera@192.168.0.102
- 安装autossh(以CentOS为例):
yum install autossh -y
- 启动持久化SSH隧道:
# 将服务器A的3307端口持久转发到服务器B的3306端口 autossh -M 20000 -f -N -L 3307:127.0.0.1:3306 usera@192.168.0.102
参数说明:
-M 20000:指定autossh的监控端口,用于检测连接状态-f:后台运行-N:仅做端口转发,不执行远程命令
- 设置开机自启(可选):
编辑/etc/rc.local,添加上述autossh命令,确保服务器重启后自动建立隧道。
2.2 PHP的简化连接字符串
此时PHP连接逻辑和连接本地MySQL完全一致:
try { $pdo = new PDO( 'mysql:host=127.0.0.1;port=3307;dbname=DBtest;charset=utf8mb4', 'usera', '123456', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); // 业务逻辑... } catch (PDOException $e) { die('连接失败: ' . $e->getMessage()); }
2.3 意外断开的自动重连
autossh本身具备连接监控和自动重连机制:
- 通过
-M端口定期检测SSH连接状态,发现断开会自动重建隧道。 - 可配合SSH存活检测参数增强稳定性,编辑服务器A的
~/.ssh/config文件:
Host 192.168.0.102 ServerAliveInterval 30 ServerAliveCountMax 3
参数说明:
ServerAliveInterval 30:每30秒向服务器B发送一次存活检测包ServerAliveCountMax 3:连续3次检测无响应则断开连接,触发autossh重连
网络波动导致连接断开时,autossh会自动恢复隧道,PHP无需额外修改,正常连接本地转发端口即可。
内容的提问来源于stack exchange,提问作者TMCHAN2020
相关产品推荐
相关产品推荐

