Soquetes encontrados por lsof, mas não por netstat

19

Eu tenho um aplicativo que está ficando sem descritores de arquivo, aparentemente abrindo soquetes, mas não consigo descobrir exatamente o que esses soquetes fazem. Eles aparecem na saída 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

e em / 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]

mas não há saída semelhante em netstat -a.

O que são esses soquetes e como posso descobrir o que eles fazem?

Edit : Eu tentei rodar grep $SOCKET /proc/net, como recomendado nas FAQs lsof , onde $ SOCKET é, por exemplo, 263746679, mas isso também não deu resultados.


Como pano de fundo, o aplicativo é um contêiner para várias tarefas que, entre outras, realizam chamadas de rede. Eu preciso destacar o que fica furioso, mas até descobrir com quem essas tomadas se comunicam, eu estou preso.

Robert Munteanu
fonte
Também enfrentamos esse problema recentemente com um de nossos aplicativos da web .NET Core (servidor Ubuntu com Kestrel), mas o dispositivo registrado é "0,9" com o nome "protocol: TCP". Tentar descobrir exatamente quais são os dispositivos 0 e 9 provou ser difícil. Mas todos os sintomas parecem com o mesmo caso de abrir soquetes sem amarrá-los e usá-los.
icelava 04/10

Respostas:

17

Isso pode ocorrer se você criar um soquete, mas nunca conectar () ou vincular () a ele. Sua melhor aposta pode ser rastrear (-fF) o aplicativo e fazer referência cruzada com a saída de lsof para determinar quais soquetes estão causando o problema. Como um método bônus de depuração: se você agrupar suas chamadas de soquete com informações de depuração e gravá-las em / dev / null, elas aparecerão estritamente sem fornecer arquivos de log hilariamente grandes.

BMDan
fonte
Obrigado, isso parece interessante. Vou tentar descobrir se esse é realmente o caso da nossa aplicação.
Robert Munteanu
1
Um pouco na mesma linha, porque é Java, pode ser muito difícil de usar strace; um método melhor pode ser criar sua própria subclasse de soquete que registre informações antes de passá-las ao soquete JDK pai (real). O strace só pode ver as chamadas Java subjacentes ao sistema operacional e não pode ver dentro de seus threads o que realmente está fazendo essas chamadas de soquete. Strace tudo parece apenas uma grande bola de java.
troyengel
@troyengel: Eu (re) descobri o Byteman ( jboss.org/byteman ) uma ferramenta muito elegante que me permite injetar o bytecode necessário para rastrear essas chamadas.
Robert Munteanu
Resposta mais útil, então isso recebe a recompensa. Obrigado!
Robert Munteanu
2

Usando o Python, encontrei o mesmo problema nos soquetes SSL:

  • Quando uso socket.close (), o soquete permanece no estado CLOSE_WAIT por tempo indeterminado
  • quando eu uso socket.shutdown (), lsof diz "não é possível identificar o protocolo"

A solução foi desembrulhar a camada SSL antes de fechar:

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

Isso fecha os soquetes corretamente no meu aplicativo.

user48134
fonte
1

A primeira coisa que eu faria é incrementar se o descritor do seu arquivo limitar:

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

Em seguida, verifique se o seu sistema está atualizado, incluindo todas as bibliotecas e servidores. É possível que seu servidor de aplicativos Java esteja desatualizado (se você estiver usando um). Também é possível que seu servidor de aplicativos esteja configurado incorretamente; você deve examinar seu arquivo de configuração e diminuir seu connectionTimeoute / ou seu maxKeepAliveRequests(não tenho certeza de qual servidor de aplicativos você está usando ou se você está usando um ...).

Não sei ao certo o que esse aplicativo faz, mas se você acha que não requer dezenas de milhares de soquetes, é quase certamente um "vazamento de descritor de arquivo" no aplicativo Java. Pode ser necessário enviar um relatório de bug ao fornecedor. Neste relatório de bug, você deve incluir informações sobre como recriar o problema.

Aqui estão algumas maneiras de depurar o problema.

O Wireshark (ou twireshark para o cli) é a melhor ferramenta para ver como esses soquetes estão sendo usados. O Wireshark mostra a você o tipo de tráfego que está sendo jogado pela rede. É provável que as primeiras conexões sejam bem-sucedidas e atinja o limite do descritor de arquivo. Quando o limite do descritor de arquivo for atingido, o Wireshark não perceberá nada (e mais limpo é o netstat), mas isso ajudará a diminuir o problema. Talvez haja um caso em que muitos SYNs de saída estejam sendo enviados, no entanto, nenhum SYN / ACK esteja sendo recebido, portanto, muitas conexões tcp ficam presas no estado SYN_WAIT.

Se você tiver acesso ao código-fonte e souber o tipo de soquetes que estão sendo criados (como usar strace ou apenas pesquisar o código), poderá abrir o projeto no Eclipse (ou outro IDE) e definir um ponto de interrupção na função que está criando esses soquetes. Quando o ponto de interrupção é atingido, você pode observar o rastreamento da pilha. Esse descritor de arquivo vaza talvez um loop infinito simples ou talvez o valor do tempo limite do soquete seja muito grande. Outra possibilidade é que o aplicativo java não esteja socket.close()limpando as conexões. Fazer um fechamento é geralmente feito no finelybloco de a try/catch(Sim, um soquete deve sempre ter uma tentativa / captura em Java ou não será construído :). No final do dia, é provável que o aplicativo Java não esteja lidando adequadamente com as IOException.

Torre
fonte
Obrigado pela resposta. Na verdade, estou desenvolvendo esse aplicativo - a parte do contêiner - em vez de apenas gerenciá-lo, e não consegui encontrar nenhum problema relacionado ao fechamento de soquetes. Mas a dica wireshark / twireshark é boa, vou usar isso.
Robert Munteanu
@ Robert Munteanu Se você estiver construindo este aplicativo, essa é uma pergunta para o stackoverflow. Não obstante, você está abrindo muitos soquetes.
Rook
Rook: Eu desisti de descobrir isso em termos de código e tentei localizá-lo como administrador de sistemas. É por isso que eu postei no SF. E sim, eu sei que de alguma maneira muitas tomadas estão abertas. Mas há indícios de zero como para onde ...
Robert Munteanu
@Robert Munteanu Você precisa definir pontos de interrupção na criação do soquete e observar o rastreamento e a memória da pilha nesse ponto. Eu suspeito que você está caindo em um loop infinito. Ser capaz de analisar qualquer variável e avançar no código será a melhor abordagem para problemas complexos como esse.
Rook
Infelizmente, isso acontece aparentemente aleatório em um dos 20 servidores - nem sempre iguais -, apenas em ambientes de produção e talvez duas vezes por semana. Caso contrário, teria sido bastante simples apontar. Atualmente, estou usando o Byteman ( jboss.org/byteman ) para rastrear a criação de soquetes / ligar / conectar / fechar chamadas. Espero que algo saia disso.
Robert Munteanu