Soket ditemukan oleh lsof tetapi tidak oleh netstat

19

Saya memiliki aplikasi yang kehabisan deskriptor file, tampaknya dengan membuka soket, tetapi saya tidak dapat mengetahui dengan tepat apa yang dilakukan soket ini. Ini muncul di output lsof sebagai

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

dan di / proc / $ PID / fd as

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]

tetapi tidak ada keluaran serupa di netstat -a.

Apa soket ini dan bagaimana saya bisa mengetahui apa yang mereka lakukan?

Sunting : Saya telah mencoba menjalankan grep $SOCKET /proc/net, seperti yang direkomendasikan di FAQ lsof , di mana $ SOCKET misalnya 263746679, tetapi itu tidak memberikan hasil juga.


Sebagai latar belakang, aplikasi adalah wadah untuk banyak tugas yang, antara lain, melakukan panggilan jaringan. Saya perlu memilih yang mengamuk, tetapi sampai saya tahu dengan siapa soket itu berkomunikasi, saya terjebak.

Robert Munteanu
sumber
Kami juga menghadapi masalah ini baru-baru ini dengan salah satu aplikasi web .NET Core kami (server Ubuntu dengan Kestrel), tetapi perangkat yang direkam adalah "0,9" dengan nama "protokol: TCP". Mencoba mencari tahu persis apa perangkat 0 dan 9 terbukti sulit. Tetapi gejalanya semua terasa seperti kasus membuka soket yang sama tanpa mengikat dan menggunakannya.
icelava

Jawaban:

17

Ini dapat terjadi jika Anda membuat soket, tetapi tidak pernah menghubungkan () atau mengikat () dengannya. Taruhan terbaik Anda mungkin untuk strace (-fF) aplikasi, dan kemudian referensi silang dengan output lsof untuk menentukan soket mana yang menyebabkan masalah. Sebagai metode bonus untuk debugging: jika Anda membungkus panggilan socket Anda dengan informasi debugging dan menuliskannya ke / dev / null, itu akan muncul dalam strace tanpa memberi Anda file-file log besar yang lucu.

BMDan
sumber
Terima kasih, ini kedengarannya menarik. Saya akan mencoba mencari tahu apakah memang demikian halnya dengan aplikasi kita.
Robert Munteanu
1
Agak sepanjang garis yang sama, karena ini adalah Jawa bisa sangat sulit untuk menggunakan strace; metode yang lebih baik mungkin dengan membuat subkelas soket Anda sendiri yang mencatat informasi sebelum meneruskannya ke soket JDK induk (nyata). strace hanya dapat melihat panggilan Java yang mendasari ke OS dan tidak dapat melihat di dalam utas Anda untuk apa yang sebenarnya membuat panggilan soket, untuk strace itu semua hanya tampak seperti satu bola besar java.
troyengel
@troyengel: Saya telah menemukan Byteman ( jboss.org/byteman ) alat yang sangat rapi yang memungkinkan saya untuk menyuntikkan bytecode yang diperlukan untuk melacak panggilan-panggilan ini.
Robert Munteanu
Jawaban yang paling berguna, jadi ini adalah hadiahnya. Terima kasih!
Robert Munteanu
2

Menggunakan Python, saya mengalami masalah yang sama pada soket SSL:

  • Ketika saya menggunakan socket.close (), socket tetap dalam keadaan CLOSE_WAIT untuk waktu yang tidak ditentukan
  • ketika saya menggunakan socket.shutdown (), lsof mengatakan "tidak dapat mengidentifikasi protokol"

Solusinya adalah membuka bungkusan lapisan SSL sebelum ditutup:

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

Ini menutup soket dengan benar di aplikasi saya.

pengguna48134
sumber
1

Hal pertama yang akan saya lakukan adalah menambahkan jika batas deskriptor file Anda:

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

Selanjutnya saya akan memastikan sistem Anda mutakhir, ini mencakup semua perpustakaan dan server. Kemungkinan server aplikasi Java Anda kedaluwarsa (jika Anda menggunakannya). Ini juga kemungkinan bahwa server aplikasi Anda salah konfigurasi, Anda harus melihat file konfigurasi Anda dan menurunkan Anda connectionTimeoutdan / atau Anda maxKeepAliveRequests(Saya tidak yakin server aplikasi apa yang Anda gunakan atau jika Anda menggunakan salah satu ...).

Saya tidak yakin apa yang aplikasi ini lakukan, tetapi jika Anda tidak berpikir itu membutuhkan puluhan ribu soket maka ini hampir pasti merupakan "file descriptor leak" di aplikasi Java Anda. Anda mungkin harus mengirim laporan bug ke vendor. Dalam laporan bug ini Anda harus memasukkan informasi tentang cara membuat kembali masalah.

Berikut adalah beberapa cara untuk men-debug masalah ini.

Wireshark (atau twireshark untuk cli) adalah alat terbaik untuk melihat bagaimana soket ini digunakan. Wireshark akan memberi Anda rincian jenis lalu lintas yang dilemparkan ke kawat. Kemungkinan beberapa koneksi pertama akan berhasil dan kemudian akan mencapai batas deskriptor file. Setelah batas deskriptor file tercapai, Wireshark tidak akan mengambil apa-apa (dan lebih rapi adalah netstat dalam hal ini), tetapi ini akan membantu mempersempit masalah. Mungkin ada kasus di mana banyak SYN keluar sedang dikirim, namun tidak ada SYN / ACK yang diterima sehingga banyak koneksi tcp hanya macet di negara SYN_WAIT.

Jika Anda memiliki akses ke kode sumber dan Anda tahu jenis soket yang dibuat (seperti menggunakan strace atau hanya mencari kode) maka Anda dapat membuka proyek di Eclipse (atau IDE lain) dan menetapkan titik istirahat pada fungsi yang sedang membuat soket ini. Ketika breakpoint terkena, maka Anda dapat melihat jejak tumpukan. Deskriptor file ini bocor mungkin infinite loop sederhana atau mungkin nilai timeout soket terlalu besar. Kemungkinan lain adalah aplikasi java tidak melakukan socket.close()untuk membersihkan koneksi. Melakukan penutupan biasanya dilakukan di finelyblok a try/catch(Ya soket harus selalu mencoba / menangkap di Jawa atau tidak akan membangun :). Pada akhirnya, kemungkinan aplikasi Java tidak menangani IOException dengan benar.

Benteng
sumber
Terima kasih atas jawabannya. Saya sebenarnya sedang mengembangkan aplikasi ini - bagian kontainer - daripada hanya mengaturnya, dan saya tidak dapat menemukan masalah apa pun yang berkaitan dengan soket yang tidak ditutup. Tapi petunjuk wireshark / twireshark baik, saya akan menggunakannya.
Robert Munteanu
@Robert Munteanu Jika Anda sedang membangun aplikasi ini maka ini adalah pertanyaan untuk stackoverflow. Tidak pernah kurang Anda membuka terlalu banyak soket.
Benteng
Benteng: Aku menyerah untuk mencari tahu tentang kode ini, dan mencoba melacaknya sebagai sysadmin. Itu sebabnya saya diposting di SF. Dan ya, entah kenapa terlalu banyak soket terbuka. Tetapi tidak ada petunjuk tentang ke mana ...
Robert Munteanu
@Robert Munteanu Anda harus mengatur titik istirahat pada pembuatan soket dan melihat jejak tumpukan dan memori pada saat itu. Saya curiga Anda jatuh ke lingkaran yang tak terbatas. Mampu melihat variabel dan langkah apa pun meskipun kode Anda akan menjadi pendekatan terbaik untuk masalah kompleks seperti ini.
Benteng
Sayangnya Rook ini terjadi secara acak di salah satu dari 20 server - tidak selalu sama -, hanya di lingkungan produksi, dan mungkin dua kali per minggu. Kalau tidak, akan lebih mudah untuk dihilangkan. Saat ini saya menggunakan Byteman ( jboss.org/byteman ) untuk melacak pembuatan soket / mengikat / menghubungkan / menutup panggilan. Semoga ada sesuatu yang keluar darinya.
Robert Munteanu