LINUX.ORG.RU

TCP socket timeout problem


0

1

Возникла проблема : есть два хоста(A-клиент и B-сервер). С хоста A создается соединение к хосту B по SSH. После прошедшии некоторого времени и большого количества переподключений(обусловленно спецификой работы алгоритма создания подключений) получил следующую ситуацию:
1) netstat --inet - на хосте A, показывает открытое соединение.
2) netstat --inet - на хосте B, не показывает никаких соединений с A
3) после попытки убить соединение на A при помощи cutter выяснилось что оно не фигурирует в /proc/net/ip_conntrack

Соединение висит уже 6 часов и отваливаться не думает. Основная проблема в том что для него вызывана процедура блокирующего чтения, которая не может отвалиться и вызывает проблемы в работе программы.

Вопросы:
1) как может возникнуть подобная ситуация, разве соединение не должно отваливаться по таймауту?
2) как лучше всего решать подобные ситуации(желательно системными настройками, так как доступа к вызову read - нет)?


1) например, если после успешного выполнения three-way-handshake (или позднее по ходу жизни соединения, но когда одна сторона не ожидает приема данных) на сокете с включенным keepalive с нулевым интервалом, по какой-либо причине пакеты второй стороны не будут доходить до первой, то после определенного количества попыток вторая сторона решит, что соединение пропало и закроет его (или скажем если вторую сторону ребутнули по питанию и она не закрыла корректно соединение). при этом первая сторона все еще будет считать соединение открытым.

2) устанавливать SO_KEEPALIVE в ненулевое значение. Я так понимаю, что ситуация уже есть, тогда рекомендую перезапустить серверное приложение, это должно закрыть все TCPCB. /proc/net/ip_conntrack и cutter тут вообще ни при чем, это механизм netfilter.

Программисты, большая просьба. Концепции, как известно, текут, и концепция прозрачной сети течет очень сильно. Пожалуйста, читайте хотя бы Стивенса прежде чем пользоваться вызовом socket().

val-amart ★★★★★
()
Ответ на: комментарий от val-amart

пардон, в вашем случае висит соединение на клиенте, вот его и надо kill().

если это все же ssh, то в конфиге опцию просто выставите и все.

общесистемно это делается через sysctl:

net.ipv4.tcp_keepalive_time
net.ipv4.tcp_keepalive_intvl
net.ipv4.tcp_keepalive_probes
val-amart ★★★★★
()
Ответ на: комментарий от val-amart

net.ipv4.tcp_keepalive_intvl = 75 net.ipv4.tcp_keepalive_probes = 9 net.ipv4.tcp_keepalive_time = 7200

keepalive - не нулевое, но соединение до сих пор висит. Даже ifconfig eth0 down не помог

recon88
() автор топика
Ответ на: комментарий от recon88

Все дело в НАТе.

$ cat /etc/sysctl.conf
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_time = 30
Дает 40 секунд на сессию :)

Jetty ★★★★★
()
Ответ на: комментарий от Jetty

если можно - по подробней, текущая сессия висит уже 20 часов, и даже согласно моим настройкам должна уже отвалиться

recon88
() автор топика
Ответ на: комментарий от Jetty

проблема в том что программу нельзя убивать, а также в том, что сокет трактуется программой как работающий, и не отваливается по таймауту

recon88
() автор топика

Коннект прошел, но ты об этом где-то забыл (потерял fd ?) Странно что на клиенте висяк, но в любом случае, промотри логику. Где-то получился эдакий дедлок.

Убить можно попробовать подключившись с gdb и call shutdown(..) / call close(..)

vasily_pupkin ★★★★★
()
Ответ на: комментарий от Jetty

Да, пытается читать

Thread: http-0.0.0.0-8080-1 : priority:5, demon:true, threadId:1696, threadState:RUNNABLE, lockName:null

java.net.SocketInputStream.socketRead0(Native Method)
java.net.SocketInputStream.read(SocketInputStream.java:129)
org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:700)
org.apache.coyote.http11.InternalInputBuffer.parseRequestLine(InternalInputBuffer.java:366)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:805)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
java.lang.Thread.run(Thread.java:595)

recon88
() автор топика
Ответ на: комментарий от recon88

> keepalive - не нулевое, но соединение до сих пор висит. Даже ifconfig eth0 down не помог.

во-первых, системные настройки можно оверрайдить при создании сокета. во-вторых, эти настройки применяются только при создании сокета, если поменять после создания, они ничего не дадут (на случай если ты их сейчас только выставил). в-третьих, насколько мне известно, других вариантов кроме как убить процесс у тебя нет. опускание интерфейса и не должно помочь, с чего ты взял что поможет?

val-amart ★★★★★
()
Ответ на: комментарий от recon88

текущие настройки отдельно взятого открытого сокета? без грязных хаков, только в программе с отрытым фд на этот сокет, через getsockopt().

val-amart ★★★★★
()
Ответ на: комментарий от recon88

он у тебя ничего не проверяет, он просто висит в сисколле read(). а чем вас это не устраивает - то что он будет так вечно висеть?

val-amart ★★★★★
()
Ответ на: комментарий от val-amart

да, в другом потоке висит поток ожидающий данные(общение между ними реализованно на блокирующей очереди), и блокирующий работу остальной части системы

recon88
() автор топика
Ответ на: комментарий от recon88

ну так пришли ему эти данные ;) а потом разорви соединение (или просто сразу разорви), и если твое приложение имеет нормальный error-handling оно просто его переоткроет.

val-amart ★★★★★
()
Ответ на: комментарий от recon88

это уж не говоря о том, что если это такая важная система что ее нельзя перезапустить, то я не понимаю почему она на томкате, не кластеризирована, что тут делаешь ты и где твои админы.

val-amart ★★★★★
()
Ответ на: комментарий от val-amart

1) сделанна на джибосе
2) не пойму причем здесь кластеризация
3) каким образом прислать данные? тред висит в одном из вызовов Ganymed SSH библиотеки, в приложении обработка ошибок есть. Проблема именно в том что доступ к соединению не отваливается

recon88
() автор топика
Ответ на: комментарий от recon88

2) при том, что в кластере высокой доступности можно было бы просто потушить ноду.
3) сгенерировать пакет TCP RST с правильными параметрами источника и получателя (IP/port) и sequence number.

val-amart ★★★★★
()
Ответ на: комментарий от val-amart

все-таки главный вопрос - как избежать подобных случаев в будущем : или разбираться с настройками соединений, или делать супервайзер который будет проверять зависшие соединения. Спасибо за исчерпывающие ответы

recon88
() автор топика
Ответ на: комментарий от recon88

разбираться с настройками, однозначно. посмотрите в коде, как создается сокет и какие опции устанавливаются (можете сюда сбросить). ну сделаете вы мониторинг (что само по себе правильно и нужно), но как вы будете реагировать на проблему? имхо, костыль.

val-amart ★★★★★
()
Ответ на: комментарий от recon88

врядли

Тогда наверное ничего не поделаешь. Тушите свет.

pathfinder ★★★★
()
Ответ на: комментарий от recon88

все-таки главный вопрос - как избежать подобных случаев в будущем

Софт должен быть нормально написан. Либо Keep-Alive, либо проверка наличия связи на прикладном уровне. Других нормальных путей ИМХО нет.

супервайзер который будет проверять зависшие соединения

Супермегавайзер, думаю, доставит больше проблем, чем пользы.

pathfinder ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.