Mengapa (atau bagaimana) jumlah deskriptor file terbuka yang digunakan oleh root melebihi ulimit -n?

13

Server kami baru-baru ini kehabisan file deskriptor, dan sehubungan dengan itu saya punya beberapa pertanyaan. ulimit -nseharusnya memberi saya jumlah maksimum deskriptor file terbuka. Angka itu adalah 1024. Saya memeriksa jumlah deskriptor file terbuka dengan menjalankan lsof -u root |wc -ldan mendapat 2500 fds. Itu jauh lebih dari 1024, jadi saya kira itu berarti angka 1024 adalah per proses, bukan per pengguna, seperti yang saya kira. Yah, saya berlari lsof -p$PidOfGlassfish|wc -ldan mendapatkan 1300. Ini adalah bagian yang tidak saya dapatkan. Jika ulimit -nbukan jumlah maksimum proses per pengguna atau per proses, lalu apa untungnya? Apakah itu tidak berlaku untuk pengguna root? Dan jika demikian, bagaimana saya bisa mendapatkan pesan kesalahan tentang kehabisan file descriptor?

EDIT: Satu-satunya cara saya bisa masuk akal ulimit -nadalah jika itu berlaku jumlah file yang terbuka (sebagaimana dinyatakan dalam manual bash) daripada jumlah menangani file (proses yang berbeda dapat membuka file yang sama). Jika ini masalahnya, maka cukup cantumkan jumlah file yang terbuka (memahami '/', sehingga tidak termasuk file yang dipetakan memori) tidak cukup:

lsof -u root |grep /|sort  -k9  |wc -l #prints '1738'

Untuk benar-benar melihat jumlah file yang terbuka, saya perlu memfilter pada kolom nama hanya mencetak entri unik. Jadi, yang berikut ini mungkin lebih benar:

lsof -u root |grep /|sort  -k9 -u |wc -l #prints '604'

Perintah di atas mengharapkan output pada format berikut dari lsof:

java      32008 root  mem       REG                8,2 11942368      72721 /usr/lib64/locale/locale-archive
vmtoolsd   4764 root  mem       REG                8,2    18624     106432 /usr/lib64/open-vm-tools/plugins/vmsvc/libguestInfo.so

Setidaknya ini memberi saya nomor kurang dari 1024 (angka yang dilaporkan oleh ulimit -n), jadi ini sepertinya langkah ke arah yang benar. "Sayangnya" Saya tidak mengalami masalah dengan kehabisan deskriptor file, jadi saya akan kesulitan memvalidasi ini.

oligofren
sumber
2
lsof melaporkan pemetaan memori serta file yang terbuka, jadi pipa 'wc' Anda menghasilkan perkiraan jumlah deskriptor file yang digunakan oleh proses itu secara berlebihan.
Richard Kettlewell
aha! sekarang itu info yang bagus. Tapi saya tidak yakin saya mengerti. Dengan "pemetaan memori", maksud Anda file yang dipetakan memori? Itu akan membutuhkan pegangan file untuk pemahaman saya, atau bagaimana lagi OS dapat memperbarui file?
oligofren
Dan tindak lanjut kedua: Apa cara yang baik untuk menemukan semua pegangan file terbuka - yang benar-benar dipengaruhi oleh batasan yang diberlakukan oleh "ulimit -n"?
oligofren
1
Pemetaan memori tidak memerlukan file terbuka. Jika Anda ingin membuat daftar file yang terbuka saja, memfilter output lsof mungkin merupakan pendekatan yang paling mudah.
Richard Kettlewell
Terima kasih, edit jawaban saya. Menggunakan ´lsof -u root | grep / | sort -k9 -u´ tampaknya memberikan jumlah jawaban yang masuk akal. Ini setidaknya angka kurang dari ulimit -n.
oligofren

Jawaban:

9

Saya menguji ini di Linux versi 2.6.18-164.el5 - Red Hat 4.1.2-46. Saya bisa melihat bahwa ulimit diterapkan per proses.

Parameter ditetapkan pada tingkat pengguna, tetapi diterapkan untuk setiap proses.

Misalnya: 1024 adalah batasnya. Beberapa proses dimulai dan file yang dibuka oleh masing-masing dihitung menggunakan

ls -l /proc/--$pid--/fd/ | wc -l

Tidak ada kesalahan ketika jumlah file dibuka oleh beberapa proses melewati 1024. Saya juga memverifikasi jumlah file unik yang menggabungkan hasil untuk proses yang berbeda dan menghitung file unik. Kesalahan mulai muncul hanya ketika jumlah untuk setiap proses melewati 1024. (java.net.SocketException: Terlalu banyak file yang terbuka di log proses)

Terpilih
sumber
Terima kasih telah menguji ini. Apakah Anda tahu mengapa lsof -p$PidOfGlassfish|wc -lmemberi saya 1300? Saya menduga dua pendekatan untuk penghitungan berbeda. Jika tidak, maka mungkin batasnya tidak berlaku untuk pengguna root?
oligofren
Hanya ingin tahu, mengapa menggunakan ls -lbukan ls? Yang terakhir memiliki baris tambahan (mis. total 5) Ketika ada 5 file. Dalam kasus seperti menggunakan ls -l contoh di atas akan melaporkan 6 tidak 5. Saya menggunakan ls /proc/<pid>/fd | wc -l.
starfry
@ starfry Itu hanya kecerobohan di pihak saya. Saya biasanya melakukan ini secara bertahap, dan ls -lmemberi saya satu entri per baris, yang kemudian saya pipa menjadi sesuatu yang lain. Tentu saja, ini juga terjadi ketika perpipaan normal ls(tetapi tidak sebaliknya).
oligofren
3

Ulimit adalah untuk menangani file. Ini berlaku untuk file, direktori, soket, epoll pipa, eventfds, timerfds dll.

Kapan saja selama proses startup batas mungkin telah diubah. Kunjungi /proc/<pid>/limitsdan lihat apakah nilainya telah diubah.

Matthew Ife
sumber
3

@oligofren

Saya juga dilakukan beberapa pengujian untuk menentukan bagaimana "ulimits -Sn"untuk "open files"diberlakukan.

  • Seperti poster yang dipilih dalam tautan , ulimit untuk "open files"memang diterapkan per proses. Untuk melihat batas proses saat ini:

    cat /proc/__process_id__/limits

  • Untuk menentukan berapa banyak file yang telah dibuka suatu proses, Anda perlu menggunakan perintah berikut:

    lsof -P -M -l -n -d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt' -p __process_id__ -a | awk '{if (NR>1) print}' | wc -l

Penjelasan di atas dan metode / hasil pengujian saya

The "-P -M -l -n"argumen untuk lsof hanya ada untuk membuat lsof beroperasi secepat mungkin. Jangan ragu untuk mengeluarkannya.

-P - inhibits the conversion of port numbers to port names for network files
-M - disable reporting of portmapper registrations for local TCP, UDP and UDPLITE ports
-l - inhibits the conversion of user ID numbers to login names
-n - inhibits the conversion of network numbers to host names for network files

The "-d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt'"menginstruksikan argumen lsofuntuk mengecualikan file deskriptor dari jenis: cwd / err / LTX / mem / mmap / pd / RTD / txt.

Dari halaman manual lsof:

   FD         is the File Descriptor number of the file or:

                   cwd  current working directory;
                   Lnn  library references (AIX);
                   err  FD information error (see NAME column);
                   jld  jail directory (FreeBSD);
                   ltx  shared library text (code and data);
                   Mxx  hex memory-mapped type number xx.
                   m86  DOS Merge mapped file;
                   mem  memory-mapped file;
                   mmap memory-mapped device;
                   pd   parent directory;
                   rtd  root directory;
                   tr   kernel trace file (OpenBSD);
                   txt  program text (code and data);
                   v86  VP/ix mapped file;

Saya dianggap "Lnn,jld,m86,tr,v86"tidak berlaku untuk Linux dan karenanya tidak repot-repot menambahkannya ke daftar pengecualian. Saya tidak yakin tentang itu "Mxx".

Jika aplikasi Anda menggunakan file / perangkat yang dipetakan memori maka Anda mungkin ingin menghapus "^mem"dan "^mmap"dari daftar pengecualian.

Sunting --- mulai snip ---

Sunting: Saya menemukan tautan berikut yang menunjukkan bahwa:

memori yang dipetakan .so-file secara teknis tidak sama dengan file yang ditangani aplikasi. / proc // fd adalah titik pengukuran untuk deskriptor file terbuka

Jadi, jika proses Anda menggunakan file yang dipetakan memori, Anda perlu memfilter file * .so.

Juga, Sun's JVM akan memetakan file jar

JARfile yang dipetakan dengan memori, dalam hal ini file yang menampung "kelas JDK." Ketika Anda memetakan memori sebuah JAR, Anda dapat mengakses file di dalamnya dengan sangat efisien (dibandingkan membacanya dari awal setiap kali). Sun JVM akan memetakan-memori semua JAR di classpath; jika kode aplikasi Anda perlu mengakses JAR, Anda juga dapat memetakannya dalam memori.

Jadi hal-hal seperti tomcat / glassfish juga akan menampilkan file jar yang dipetakan memori. Saya belum menguji apakah ini masuk dalam "ulimit -Sn"batas.

EDIT --- end snip ---

Secara empiris, saya telah menemukan bahwa "cwd,rtd,txt"yang tidak dihitung berkaitan dengan per proses batas file (ulimit -sN).

Saya tidak yakin apakah "err,ltx,pd"dihitung terhadap batas file karena saya tidak tahu cara membuat file menangani jenis deskriptor ini.

The "-p __process_id__"Membatasi argumen lsofhanya kembali informasi untuk __process_id__ditentukan. Hapus ini jika Anda ingin mendapatkan hitungan untuk semua proses.

The "-a"argumen digunakan untuk DAN pada pilihan (yaitu "p" dan "d" argumen).

The "awk '{if (NR>1) print}'"pernyataan digunakan untuk melewatkan header yang lsofcetakan dalam output.

Saya diuji menggunakan skrip perl berikut:

File: test.pl
---snip---
#!/usr/bin/perl -w
foreach $i (1..1100) {
  $FH="FH${i}";
  open ($FH,'>',"/tmp/Test${i}.log") || die "$!";
  print $FH "$i\n";
}
---snip---

Saya harus menjalankan skrip dalam perl debugger untuk memastikan skrip tidak berhenti dan merilis file deskriptor.

Untuk mengeksekusi: perl -d test.pl

Di debugger perl, Anda dapat menjalankan program dengan memasukkan cdan menekan enter dan jika Anda ulimit -Snmemiliki nilai 1024 , Anda akan menemukan bahwa program berhenti setelah membuat Test1017.logfile masuk /tmp.

Jika sekarang Anda mengidentifikasi pid dari proses perl dan menggunakan lsofperintah di atas Anda akan melihat bahwa itu juga menghasilkan 1024 .

Hapus "wc -l"dan ganti dengan "less"untuk melihat daftar file yang dihitung menuju batas 1024 . Hapus "-d ^....."argumen juga untuk melihat bahwa cwd,txtdan rtddeskriptor tidak masuk dalam batas.

Jika Anda sekarang menjalankan "ls -l /proc/__process_id__/fd/ | wc -l", Anda akan melihat nilai 1025 dikembalikan. Ini karena lsmenambahkan "total 0"header ke outputnya yang dihitung.

catatan:

Untuk memeriksa apakah OS kehabisan deskriptor file, lebih baik membandingkan nilai:

cat /proc/sys/fs/file-nr | awk '{print $1}'

dengan

cat /proc/sys/fs/file-max

https://www.kernel.org/doc/Documentation/sysctl/fs.txt mendokumentasikan apa file-nrdan file-maxartinya.

Jinesh Choksi
sumber
0

Sepertinya alasanmu adalah seperti, "Aku harus menurunkan batas itu jadi aku tidak kehabisan deskriptor yang berharga". Yang benar adalah sebaliknya - jika server Anda kehabisan file deskriptor, Anda perlu menaikkan batas dari 1.024 ke sesuatu yang lebih besar. Untuk glassfishimplementasi yang realistis , 32.768 masuk akal.

Secara pribadi, saya selalu menaikkan batas menjadi sekitar 8.192 sistem - 1.024 hanya konyol. Tetapi Anda ingin menaikkan glassfishlebih tinggi. Periksa /etc/security/limits.conf. Anda dapat menambahkan entri khusus untuk glassfishberjalan pengguna sebagai.

David Schwartz
sumber
Saya tidak yakin bagaimana Anda bisa menafsirkan saya berarti :-) Apa yang saya bertanya-tanya adalah mengapa itu tampaknya tidak berlaku. Saya akan mengaturnya lebih tinggi, tetapi saya ingin memahami cara kerjanya juga. Jika batasnya 1024, lalu bagaimana Glassfish bisa memiliki 1.300 pegangan?
oligofren
'lsof -u root | grep / | sort -k9 -u' mencetak entri deskriptor file unik. Saya kira jumlah baris dari ini adalah angka aktual yang berlaku pada ulimit -n.
oligofren
0

Anda ingin melihat batas seluruh sistem yang diatur di / proc / sys / fs / file-max dan sesuaikan di sana (hingga reboot berikutnya) atau set fs.file-max di sysctl.conf untuk membuatnya permanen. Ini mungkin membantu - http://www.randombugs.com/linux/tuning-file-descriptors-limits-on-linux.html

rnxrx
sumber
1
Komentar tentang bash itu tidak akurat. ulimit memberlakukan batasan per user-id, untuk proses yang dimulai melalui shell, yang pada dasarnya adalah segalanya berkat bagaimana pohon proses dihasilkan pada sistem operasi mirip Unix. Itu bukan bash.
EightBitTony
Maaf - akan diedit, tetapi komentar tentang batas sistem masih berlaku.
rnxrx
Sangat tidak mungkin dia memukul batas sistem yang luas. Mungkin, tetapi sangat tidak mungkin.
David Schwartz
EightBitTony: ulimit tidak menetapkan ulimit per set batas user-id. Per prosesnya ketika pam_limits diterapkan. Ulimit bahwa itu adalah "per pengguna" adalah "ulimit -u" "Jumlah maksimum proses yang tersedia untuk satu pengguna"
No Username
0

Kesalahan umum untuk membandingkan hasil panggilan lsof mentah dengan batas yang seharusnya.

Untuk batas global (/ proc / sys / fs / file-max) Anda harus melihat / proc / sys / fs / file-nr -> nilai fist menunjukkan apa yang digunakan dan nilai terakhir adalah batas

Batas OpenFile adalah untuk setiap proses tetapi dapat didefinisikan pada pengguna, lihat perintah "ulimit -Hn" untuk batas pengguna dan lihat /etc/security/limits.conf untuk definisi. Umumnya diterapkan dengan "pengguna aplikasi" misalnya: "kucing jantan": tetapkan batas hingga 65000 untuk kucing jantan pengguna yang akan berlaku pada proses java yang dijalankannya.

Jika Anda ingin memeriksa batas yang diterapkan pada suatu proses, dapatkan PID-nya dan kemudian: cat / proc / $ {PID} / limit Jika Anda ingin memeriksa berapa banyak file yang dibuka oleh suatu proses, dapatkan PID-nya dan kemudian: ls -1 / proc / {PID} / fd | wc-l (catatan untuk ls 'minus satu', bukan untuk berbaur dengan 'minus el')

Jika Anda ingin mengetahui detail dengan lsof tetapi hanya untuk penangan file yang menghitung batas, cobalah dengan thoses: lsof -p $ {PID} | grep -P "^ (\ w + \ s +) {3} \ d + \ D +" lsof -p $ {PID} -d '^ cwd, ^ err, ^ ltx, ^ mem, ^ mmap, ^ pd, ^ rtd, ^ txt '-a

Catatan: 'file' adalah file / pipa / koneksi tcp / dll.

Perhatikan bahwa kadang-kadang Anda mungkin harus melakukan root atau menggunakan sudo untuk mendapatkan hasil yang benar untuk perintah, tanpa hak istimewa kadang-kadang Anda tidak memiliki kesalahan, hanya sedikit hasil.

dan akhirnya jika Anda ingin tahu apa 'file' pada sistem file Anda diakses oleh suatu proses, lihat: lsof -p {PID} | grep / | awk '{print $ 9}' | sortir | uniq

Selamat bersenang-senang !

Ronan Kerdudou
sumber