У меня есть код perl, работающий под mod_perl, который подключается к серверу openldap slapd с помощью модуля Net::LDAP.
Я пытаюсь установить тайм-аут подключения следующим образом:
my $ldap = Net::LDAP->new($server, timeout => 120);
но когда slapd сильно загружен, попытки подключения прерываются примерно через 20 секунд.
Net::LDAP использует IO::Socket и IO::Select для реализации обработки соединения, в частности этот код в IO::Socket (обратите внимание, что я добавил немного дополнительного кода отладки):
sub connect {
@_ == 2 or croak 'usage: $sock->connect(NAME)';
my $sock = shift;
my $addr = shift;
my $timeout = ${*$sock}{'io_socket_timeout'};
my $err;
my $blocking;
my $start = scalar localtime;
$blocking = $sock->blocking(0) if $timeout;
if (!connect($sock, $addr)) {
if (defined $timeout && ($!{EINPROGRESS} || $!{EWOULDBLOCK})) {
require IO::Select;
my $sel = new IO::Select $sock;
undef $!;
if (!$sel->can_write($timeout)) {
$err = $! || (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1);
$@ = "connect: timeout";
}
elsif (!connect($sock,$addr) &&
not ($!{EISCONN} || ($! == 10022 && $^O eq 'MSWin32'))
) {
# Some systems refuse to re-connect() to
# an already open socket and set errno to EISCONN.
# Windows sets errno to WSAEINVAL (10022)
my $now = scalar localtime;
$err = $!;
$@ = "connect: (1) $! : start = [$start], now = [$now], timeout = [$timeout] : " . Dumper(\%!);
}
}
elsif ($blocking || !($!{EINPROGRESS} || $!{EWOULDBLOCK})) {
$err = $!;
$@ = "connect: (2) $!";
}
}
$sock->blocking(1) if $blocking;
$! = $err if $err;
$err ? undef : $sock;
}
и я вижу вывод журнала следующим образом:
connect: (1) Connection timed out : start = [Tue Jun 19 14:57:44 2012], now = [Tue Jun 19 14:58:05 2012], timeout = [120] : $VAR1 = {
'EBADR' => 0,
'ENOMSG' => 0,
<snipped>
'ESOCKTNOSUPPORT' => 0,
'ETIMEDOUT' => 110,
'ENXIO' => 0,
'ETXTBSY' => 0,
'ENODEV' => 0,
'EMLINK' => 0,
'ECHILD' => 0,
'EHOSTUNREACH' => 0,
'EREMCHG' => 0,
'ENOTEMPTY' => 0
};
: Started attempt at Tue Jun 19 14:57:44 2012
Откуда берется 20-секундный тайм-аут подключения?
РЕДАКТИРОВАТЬ: теперь я нашел виновника: /proc/sys/net/ipv4/tcp_syn_retries, для которого по умолчанию установлено значение 5, а 5 попыток занимают около 20 секунд. http://www.sekuda.com/overriding_the_default_linux_kernel_20_second_tcp_socket_connect_timeout