防止 "mux_client_request_session: read from master failed: Broken pipe" ssh 错误的最佳方法
Best way to prevent "mux_client_request_session: read from master failed: Broken pipe" ssh errors
我有一个 perl 脚本可以创建一个 ssh 隧道并通过它设置一个 Perl DBI 连接以查询远程主机上的数据库:
1 my $ssh = Net::OpenSSH->new('me@host.com');
2 $pid = $ssh->spawn({ssh_opts => '-L 127.0.0.1:12345:127.0.0.1:3306'}, 'sleep 3');
3 return DBI->connect($dsn, $db_user, $db_pass);
这在大约 80% 到 90% 的时间都有效,但其余时间我在尝试连接到数据库时遇到此错误:
mux_client_request_session: read from master failed: Broken pipe
在解决这个问题的过程中,我注意到如果我在第 2 行之后用 usleep (10000)
非常短暂地休眠程序,它 100% 的时间都可以工作。我不确定这是为什么,但我很好奇知道以及如何正确解决这个问题。
谢谢。
您的代码中存在竞争条件:spawn
运行在后台启动隧道的 ssh
命令,有时该命令比 DBI connect
启动 TCP 更快套接字,有时不是,所以 connect
失败。
无论如何,我通常推荐的创建隧道的方式是使用控制命令:
$ssh->system({ssh_opts => [-O => 'forward', '-L3066:localhost:3066']})
如果您想在与数据库的连接建立后删除隧道:
$ssh->system({ssh_opts => [-O => 'cancel', '-L3066:localhost:3066']});
此外,请注意,只要您要使用数据库连接,就必须保持 Net::OpenSSH
对象处于活动状态。
总结:
sub dbi_connect {
my $mysql_port = 3066;
my $local_port = 12345;
my $dsn = "DBI:mysql:database=$database;host=localhost;port=$local_port";
my $tunnel = join ':', $local_port, 'localhost', $mysql_port;
my $ssh = Net::OpenSSH->new($host, ...);
$ssh->system({ssh_opts => [-O => 'forward', "-L$tunnel"]});
my $dbi = DBI->connect($dsn, $db_user, $db_pass);
$ssh->system({ssh_opts => [-O => 'cancel', "-L$tunnel"]});
return ($dbi, $ssh);
}
另请参阅 PerlMonks 的 this post。
我有一个 perl 脚本可以创建一个 ssh 隧道并通过它设置一个 Perl DBI 连接以查询远程主机上的数据库:
1 my $ssh = Net::OpenSSH->new('me@host.com');
2 $pid = $ssh->spawn({ssh_opts => '-L 127.0.0.1:12345:127.0.0.1:3306'}, 'sleep 3');
3 return DBI->connect($dsn, $db_user, $db_pass);
这在大约 80% 到 90% 的时间都有效,但其余时间我在尝试连接到数据库时遇到此错误:
mux_client_request_session: read from master failed: Broken pipe
在解决这个问题的过程中,我注意到如果我在第 2 行之后用 usleep (10000)
非常短暂地休眠程序,它 100% 的时间都可以工作。我不确定这是为什么,但我很好奇知道以及如何正确解决这个问题。
谢谢。
您的代码中存在竞争条件:spawn
运行在后台启动隧道的 ssh
命令,有时该命令比 DBI connect
启动 TCP 更快套接字,有时不是,所以 connect
失败。
无论如何,我通常推荐的创建隧道的方式是使用控制命令:
$ssh->system({ssh_opts => [-O => 'forward', '-L3066:localhost:3066']})
如果您想在与数据库的连接建立后删除隧道:
$ssh->system({ssh_opts => [-O => 'cancel', '-L3066:localhost:3066']});
此外,请注意,只要您要使用数据库连接,就必须保持 Net::OpenSSH
对象处于活动状态。
总结:
sub dbi_connect {
my $mysql_port = 3066;
my $local_port = 12345;
my $dsn = "DBI:mysql:database=$database;host=localhost;port=$local_port";
my $tunnel = join ':', $local_port, 'localhost', $mysql_port;
my $ssh = Net::OpenSSH->new($host, ...);
$ssh->system({ssh_opts => [-O => 'forward', "-L$tunnel"]});
my $dbi = DBI->connect($dsn, $db_user, $db_pass);
$ssh->system({ssh_opts => [-O => 'cancel', "-L$tunnel"]});
return ($dbi, $ssh);
}
另请参阅 PerlMonks 的 this post。