Mam aplikację, której brakuje deskryptorów plików, najwyraźniej przez otwarcie gniazd, ale nie mogę dokładnie dowiedzieć się, co robią te gniazda. Pojawiają się one w wynikach lsof jako
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
oraz w / proc / $ PID / fd jako
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]
ale nie ma podobnego wyniku w netstat -a
.
Co to są te gniazda i jak mogę dowiedzieć się, co robią?
Edycja : Próbowałem uruchomić grep $SOCKET /proc/net
, zgodnie z zaleceniami w lsof FAQ , gdzie $ SOCKET to na przykład 263746679, ale to również nie dało rezultatów.
Jako tło aplikacja jest pojemnikiem na wiele zadań, które między innymi wykonują połączenia sieciowe. Muszę wyróżnić ten, który wpadnie w szał, ale dopóki nie dowiem się, z kim komunikują się te gniazda, utknąłem.
Odpowiedzi:
Może się to zdarzyć, jeśli utworzysz gniazdo, ale nigdy nie łącz z nim gniazda () ani bind (). Najlepszym rozwiązaniem może być zapisanie (-fF) aplikacji, a następnie odsyłanie do wyniku lsof w celu ustalenia, które gniazda powodują problem. Jako dodatkowa metoda debugowania: jeśli otoczysz wywołania gniazda informacjami debugowania i wypiszesz je w katalogu / dev / null, pojawi się ono w trybie ciągłym bez dostarczania komicznie dużych plików dziennika.
źródło
Za pomocą Pythona napotkałem ten sam problem na gniazdach SSL:
Rozwiązaniem było rozpakowanie warstwy SSL przed zamknięciem:
To poprawnie zamyka gniazda w mojej aplikacji.
źródło
Pierwszą rzeczą, którą bym zrobił, było zwiększenie, jeśli limit deskryptora pliku:
Następnie upewnię się, że twój system jest aktualny, dotyczy to wszystkich bibliotek i serwerów. Możliwe, że Twój serwer aplikacji Java jest nieaktualny (jeśli go używasz). Istnieje również możliwość, że serwer aplikacji jest źle skonfigurowany, powinieneś spojrzeć na plik konfiguracyjny i obniżyć swój
connectionTimeout
i / lub swójmaxKeepAliveRequests
(nie jestem pewien, jakiego serwera aplikacji używasz, czy w ogóle go używasz ...).Nie jestem pewien, co robi ta aplikacja, ale jeśli uważasz, że nie wymaga dziesiątek tysięcy gniazd, prawie na pewno jest to „wyciek deskryptora pliku” w Twojej aplikacji Java. Może być konieczne wysłanie raportu o błędzie do dostawcy. W tym raporcie o błędzie należy podać informacje o sposobie odtworzenia problemu.
Oto kilka sposobów debugowania problemu.
Wireshark (lub twireshark dla cli) to najlepsze narzędzie, aby zobaczyć, jak te gniazda są używane. Wireshark da ci podział na rodzaj ruchu wyrzucanego przez drut. Najprawdopodobniej kilka pierwszych połączeń zakończy się powodzeniem, a następnie osiągnie limit deskryptora pliku. Po przekroczeniu limitu deskryptora pliku Wireshark nie będzie niczego wychwytywał (a do tego fajniejszy jest netstat), ale pomoże to zawęzić problem. Może się zdarzyć, że wysyłanych jest wiele wychodzących SYN, jednak żadne SYN / ACK nie są odbierane, dlatego wiele połączeń TCP zostaje zablokowanych w stanie SYN_WAIT.
Jeśli masz dostęp do kodu źródłowego i znasz typ tworzonych gniazd (np. Użycie strace lub po prostu przeszukiwanie kodu), możesz otworzyć projekt w Eclipse (lub innym IDE) i ustawić punkt przerwania dla funkcji, która tworzy te gniazda. Kiedy punkt przerwania zostanie trafiony, możesz spojrzeć na ślad stosu. Ten wyciek deskryptora pliku może być zwykłą nieskończoną pętlą lub może wartość limitu czasu gniazda jest zbyt duża. Inną możliwością jest to, że aplikacja Java nie wykonuje
socket.close()
czyszczenia połączeń. Zamykanie jest zwykle wykonywane wfinely
blokutry/catch
(Tak, gniazdo musi zawsze mieć try / catch w Javie, inaczej się nie zbuduje :). Pod koniec dnia jest prawdopodobne, że aplikacja Java nie obsługuje poprawnie wyjątku IOException.źródło