Сокеты, найденные lsof, но не netstat

19

У меня есть приложение, которое исчерпывает файловые дескрипторы, очевидно, открывая сокеты, но я не могу точно выяснить, что делают эти сокеты. Они появляются в выводе lsof как

java    9689 appuser 1010u  sock       0,5          263746675 can't identify protocol
java    9689 appuser 1011u  sock       0,5          263746676 can't identify protocol
java    9689 appuser 1012u  sock       0,5          263746677 can't identify protocol
java    9689 appuser 1014u  sock       0,5          263746678 can't identify protocol
java    9689 appuser 1015u  sock       0,5          263746679 can't identify protocol
java    9689 appuser 1016u  sock       0,5          263746681 can't identify protocol

и в / proc / $ PID / fd как

lrwx------ 1 appuser appuser 64 Jun 23 11:49 990 -> socket:[263732085]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 991 -> socket:[263732086]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 992 -> socket:[263735307]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 993 -> socket:[263732088]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 995 -> socket:[263735308]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 996 -> socket:[263735309]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 997 -> socket:[263745434]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 998 -> socket:[263745435]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 999 -> socket:[263745436]

но нет аналогичного выхода в netstat -a.

Что это за сокеты и как я могу узнать, что они делают?

Изменить : я попытался запустить grep $SOCKET /proc/net, как рекомендовано в FAQ lsof , где $ SOCKET, например, 263746679, но это также не дало никаких результатов.


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

Роберт Мунтяну
источник
Мы также недавно столкнулись с этой проблемой с одним из наших веб-приложений .NET Core (сервер Ubuntu с Kestrel), но записанное устройство имеет «0,9» с именем «протокол: TCP». Попытка выяснить, какие именно устройства 0 и 9 оказались трудными. Но все симптомы выглядят как один и тот же случай открытия розеток без их связывания и использования.
Исллава

Ответы:

17

Это может произойти, если вы создаете сокет, но никогда не соединяетесь с ним () или bind (). Лучше всего сделать так, чтобы приложение (-fF) связывалось с приложением, а затем делало перекрестную ссылку с выводом lsof, чтобы определить, какие сокеты вызывают проблему. В качестве бонусного метода отладки: если вы упаковываете вызовы сокетов в отладочную информацию и записываете их в / dev / null, они будут отображаться сразу, без больших файлов журнала.

BMDan
источник
Спасибо, это звучит интересно. Я постараюсь выяснить, так ли это на самом деле с нашим приложением.
Роберт Мунтяну
1
Несколько по той же линии, потому что это Java, может быть очень трудно использовать strace; лучшим методом может быть создание собственного подкласса сокета, который регистрирует информацию перед передачей ее в родительский (реальный) сокет JDK. strace может видеть только базовые вызовы Java для ОС и не может видеть внутри ваших потоков, что на самом деле делает эти вызовы сокетов, чтобы strace все это выглядело как один большой шарик Java.
Троенгель
@troyengel: Я (заново) обнаружил Byteman ( jboss.org/byteman ), очень удобный инструмент, который позволяет мне вводить байт-код, необходимый для отслеживания этих вызовов.
Роберт Мунтяну
Самый полезный ответ, так что это получает награду. Благодарность!
Роберт Мунтяну
2

Используя Python, я столкнулся с той же проблемой на сокетах SSL:

  • Когда я использую socket.close (), сокет остается в состоянии CLOSE_WAIT в течение неопределенного времени
  • когда я использую socket.shutdown (), lsof говорит: «не могу определить протокол»

Решением было развернуть слой SSL перед закрытием:

  • origsock = socket.unwrap ()
  • origsock.close ()

Это правильно закрывает сокеты в моем приложении.

user48134
источник
1

Первое, что я хотел бы сделать, это вставить, если ваш файловый дескриптор ограничен:

~# vi /etc/sysctl.conf
fs.file-max = 331287

Далее я бы хотел убедиться, что ваша система обновлена, включая все библиотеки и серверы. Возможно, ваш сервер приложений Java устарел (если вы его используете). Также возможно, что ваш сервер приложений неверно сконфигурирован, вы должны взглянуть на свой файл конфигурации и уменьшить свой connectionTimeoutи / или ваш maxKeepAliveRequests(я не уверен, какой сервер приложений вы используете или используете ли вы его вообще ...).

Я не уверен, что делает это приложение, но если вы не думаете, что для этого требуются десятки тысяч сокетов, то это почти наверняка «утечка файлового дескриптора» в вашем Java-приложении. Возможно, вам придется отправить отчет об ошибке поставщику. В этом сообщении об ошибке вы должны включить информацию о том, как воссоздать проблему.

Вот несколько способов отладки проблемы.

Wireshark (или twireshark для клиентов) - лучший инструмент, чтобы увидеть, как используются эти сокеты. Wireshark поможет вам разобраться в типе трафика, передаваемого по проводам. Вполне вероятно, что первые несколько соединений будут успешными, а затем он достигнет предела дескриптора файла. Как только предел файлового дескриптора будет достигнут, Wireshark не собирается что-либо предпринимать (и в этом отношении neater - netstat), но это поможет сузить проблему. Может случиться так, что отправляется много исходящих SYN, однако SYN / ACK не принимаются, поэтому многие соединения tcp просто застряли в состоянии SYN_WAIT.

Если у вас есть доступ к исходному коду и вы знаете тип создаваемых сокетов (например, использование strace или просто поиск по коду), вы можете открыть проект в Eclipse (или другой IDE) и установить точку останова для функции, которая создает эти сокеты. Когда достигается точка останова, вы можете посмотреть на трассировку стека. Эта утечка файлового дескриптора может быть простым бесконечным циклом или, возможно, значение времени ожидания сокета слишком велико. Другая возможность заключается в том, что Java-приложение не выполняет socket.close()очистку соединений. Закрытие обычно выполняется в finelyблоке a try/catch(да, у сокета всегда должна быть попытка / перехват в Java, иначе он не будет собираться :). В конце концов, вполне вероятно, что приложение Java не обрабатывает свои IOException должным образом.

ладья
источник
Спасибо за ответ. Я на самом деле разрабатываю это приложение - контейнерную часть - а не просто управляю им, и я не смог найти никаких проблем, связанных с незакрытыми сокетами. Но подсказка wireshark / twireshark хороша, я буду использовать это.
Роберт Мунтяну
@Robert Munteanu Если вы создаете это приложение, то это вопрос для работы со стеком. Тем не менее, вы открываете слишком много розеток.
Ладья
Ладья: я разочаровался в поиске этого кода и попытался отследить его как системного администратора. Вот почему я разместил на SF. И да, я знаю, как-то слишком много открытых розеток. Но нет никаких подсказок относительно того, где ...
Роберт Мунтяну
@Robert Munteanu Вы должны установить точки останова при создании сокета и посмотреть на трассировку стека и память в этой точке. Я подозреваю, что вы попадаете в бесконечный цикл. Возможность просматривать любую переменную и шаг, хотя ваш код будет лучшим подходом для сложных задач, подобных этой.
Ладья
К сожалению, это происходит, по-видимому, случайным образом на одном из 20 серверов - не всегда одинаково - только в производственных средах и, возможно, два раза в неделю. В противном случае это было бы довольно просто выявить. В настоящее время я использую Byteman ( jboss.org/byteman ) для отслеживания создания сокетов / bind / connect / close вызовов. Надеюсь, что-то из этого получится.
Роберт Мунтяну