Enchufes encontrados por lsof pero no por netstat

19

Tengo una aplicación que se está quedando sin descriptores de archivo, aparentemente al abrir sockets, pero no puedo averiguar exactamente qué hacen estos sockets. Estos aparecen en la salida de lsof como

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

y en / proc / $ PID / fd como

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]

pero no hay salida similar en netstat -a.

¿Qué son estos enchufes y cómo puedo averiguar qué hacen?

Editar : He intentado ejecutar grep $SOCKET /proc/net, como se recomienda en las preguntas frecuentes de lsof , donde $ SOCKET es, por ejemplo, 263746679, pero tampoco dio resultados.


Como fondo, la aplicación es un contenedor para múltiples tareas que, entre otras, realizan llamadas de red. Necesito seleccionar el que se vuelve loco, pero hasta que descubra con quién se comunican esos enchufes, estoy atascado.

Robert Munteanu
fuente
También estamos enfrentando este problema recientemente con una de nuestras aplicaciones web .NET Core (servidor Ubuntu con Kestrel), pero el dispositivo grabado es "0,9" con el nombre "protocolo: TCP". Intentar descubrir exactamente qué dispositivos son 0 y 9 ha resultado ser difícil. Pero todos los síntomas parecen el mismo caso de abrir tomas sin atarlos y usarlos.
icelava

Respuestas:

17

Esto puede ocurrir si crea un socket, pero nunca se conecta () o enlaza () con él. Su mejor opción puede ser estratificar (-fF) la aplicación y luego hacer una referencia cruzada con la salida de lsof para determinar qué enchufes están causando el problema. Como método adicional de depuración: si envuelve sus llamadas de socket con información de depuración y las escribe en / dev / null, aparecerá en orden sin darle archivos de registro hilarantemente grandes.

BMDan
fuente
Gracias, esto suena interesante. Intentaré averiguar si ese es realmente el caso con nuestra aplicación.
Robert Munteanu
1
De alguna manera en la misma línea, porque esto es Java, podría ser muy difícil usar strace; un mejor método podría ser crear su propia subclase de socket que registre información antes de pasarla al socket JDK primario (real). strace solo puede ver las llamadas Java subyacentes al sistema operativo y no puede ver dentro de sus hilos lo que realmente está haciendo esas llamadas de socket, para strace todo parece una gran bola de Java.
troyengel
@troyengel: he (re) descubierto Byteman ( jboss.org/byteman ) una herramienta muy buena que me permite inyectar el bytecode necesario para rastrear estas llamadas.
Robert Munteanu
La respuesta más útil, por lo que esto obtiene la recompensa. ¡Gracias!
Robert Munteanu
2

Usando Python, he encontrado el mismo problema en los sockets SSL:

  • Cuando uso socket.close (), el socket permanece en estado CLOSE_WAIT por tiempo indefinido
  • cuando uso socket.shutdown (), lsof dice "no se puede identificar el protocolo"

La solución fue desenvolver la capa SSL antes de cerrar:

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

Esto cierra los enchufes correctamente en mi aplicación.

usuario48134
fuente
1

Lo primero que haría es aumentar si el límite de su descriptor de archivo:

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

A continuación, me aseguraría de que su sistema esté actualizado, esto incluye todas las bibliotecas y servidores. Es posible que su servidor de aplicaciones Java esté desactualizado (si está usando uno). También es una posibilidad que su servidor de aplicaciones esté mal configurado, debe mirar su archivo de configuración y bajar suconnectionTimeout y / o su maxKeepAliveRequests(no estoy seguro de qué servidor de aplicaciones está usando o si está usando uno ...).

No estoy seguro de lo que hace esta aplicación, pero si no crees que requiere decenas de miles de sockets, entonces es casi seguro que "fuga de descriptor de archivo" en su aplicación Java. Es posible que deba enviar un informe de error al proveedor. En este informe de error, debe incluir información sobre cómo volver a crear el problema.

Aquí hay algunas formas de depurar el problema.

Wireshark (o twireshark para el cli) es la mejor herramienta para ver cómo se utilizan estos enchufes. Wireshark le dará un desglose del tipo de tráfico que se lanza por el cable. Es probable que las primeras conexiones tengan éxito y luego lleguen al límite del descriptor de archivo. Una vez que se alcanza el límite del descriptor de archivos, Wireshark no va a detectar nada (y más limpio es netstat para el caso), pero esto ayudará a reducir el problema. Puede haber un caso en el que se envíen muchos SYN salientes, sin embargo, no se reciben SYN / ACK, por lo que muchas conexiones tcp simplemente se atascan en el estado SYN_WAIT.

Si tiene acceso al código fuente y sabe el tipo de sockets que se crean (como usar strace o simplemente buscar el código), puede abrir el proyecto en Eclipse (u otro IDE) y establecer un punto de interrupción en la función que está creando estos enchufes. Cuando se alcanza el punto de interrupción, puede ver el seguimiento de la pila. Esta fuga del descriptor de archivo puede ser un simple bucle infinito o tal vez el valor de tiempo de espera del socket es demasiado grande. Otra posibilidad es que la aplicación Java no esté haciendo una socket.close()limpieza de las conexiones. Hacer un cierre se hace comúnmente en el finelybloque de un try/catch(Sí, un socket siempre debe tener un try / catch en Java o no se compilará :). Al final del día, es probable que la aplicación Java no esté manejando sus IOException correctamente.

Torre
fuente
Gracias por la respuesta. De hecho, estoy desarrollando esta aplicación, la parte del contenedor, en lugar de solo administrarla, y no pude encontrar ningún problema relacionado con los zócalos no cerrados. Pero la sugerencia wireshark / twireshark es buena, lo usaré.
Robert Munteanu
@Robert Munteanu Si está creando esta aplicación, esta es una pregunta para stackoverflow. Sin embargo, está abriendo demasiados enchufes.
Torre el
Rook: Me di por vencido al encontrar esto en cuanto al código, y traté de rastrearlo como un administrador de sistemas. Por eso publiqué en SF. Y sí, sé que de alguna manera hay demasiados enchufes abiertos. Pero no hay pistas de dónde ...
Robert Munteanu
@Robert Munteanu Debe establecer puntos de interrupción en la creación del socket y observar la traza de la pila y la memoria en ese punto. Sospecho que estás cayendo en un bucle infinito. Poder mirar cualquier variable y paso a través de su código será el mejor enfoque para problemas complejos como este.
Torre
Rook, desafortunadamente, esto sucede aparentemente al azar en uno de los 20 servidores, no siempre el mismo, solo en entornos de producción y quizás dos veces por semana. De lo contrario, habría sido bastante fácil de sacar. Actualmente estoy usando Byteman ( jboss.org/byteman ) para rastrear la creación de socket / vincular / conectar / cerrar llamadas. Esperemos que algo salga de eso.
Robert Munteanu