Kim benim inotify kaynaklarımı tüketiyor?


49

Fedora 15’e yapılan son güncellemeden sonra, bir dizi aracın şu satırlar boyunca hatayla başarısız olduğunu tespit ediyorum:

tail: inotify resources exhausted
tail: inotify cannot be used, reverting to polling

Sadece tailinotify ile ilgili problemleri de rapor etmiyor . Çekirdek sorgulamak için inotify kaynakları hangi süreç veya süreçleri tüketen bulmak için herhangi bir yolu var mı? Mevcut inotify ile ilgili sysctlayarlar şöyle görünür:

fs.inotify.max_user_instances = 128
fs.inotify.max_user_watches = 8192
fs.inotify.max_queued_events = 16384

Yanıtlar:


39

İşlem inotify_init () aracılığıyla inotify örneği oluşturuyorsa, / proc dosya sistemindeki filedescriptor öğesini temsil eden sonuç dosyası, (varolmayan) 'anon_inode: inotify' dosyasına giden bir bağlantı simgesidir.

$ cd /proc/5317/fd
$ ls -l
total 0
lrwx------ 1 puzel users 64 Jun 24 10:36 0 -> /dev/pts/25
lrwx------ 1 puzel users 64 Jun 24 10:36 1 -> /dev/pts/25
lrwx------ 1 puzel users 64 Jun 24 10:36 2 -> /dev/pts/25
lr-x------ 1 puzel users 64 Jun 24 10:36 3 -> anon_inode:inotify
lr-x------ 1 puzel users 64 Jun 24 10:36 4 -> anon_inode:inotify

Kavramı yanlış anlamadığım sürece, aşağıdaki komut, kullandıkları inotify örneklerinin sayısına göre sıralanan işlemlerin listesini (/ proc içindeki gösterimleri) göstermelidir.

for foo in /proc/*/fd/*; do readlink -f $foo; done | grep inotify | sort | uniq -c | sort -nr

8
Mükemmel teşekkür ederim! İnotify inode'larını / proc'ta gösteren bilmiyordum. Benim amaçlarıma göre, komut basitleştirilebilir:find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print
larsks

Yardım ettiğine sevindim. Ve find -name ile olan çözümünüz döngü ve okuma bağlantısı için benimkinden çok daha iyi.
Petr Uzel

3
Ayrıca, saat dışında da olabileceğinizi unutmayın (örnekler değil). Örneğin, benim sistemimde bu, gençlere çok az sayıda örnek veriyor, ancak KDE'nin masaüstü aramasından on binlerce saat var. Çekirdek açıkça bildiği için ne kadar saat / örnek kullanımda olduğunu kontrol etmenin kolay bir yolu yok ...
derobert

Suçlu programların komut satırlarını göstermek için:find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -exec sh -c 'cat $(dirname {})/../cmdline; echo ""' \; 2>/dev/null
Mark K Cowan,

@derobert Ben genellikle ilgilenen şey olan izleyicileri kullanan süreçleri listelemek için bir senaryo hazırladım. Aşağıdaki cevaba bakınız.
oligofren

25

Muhtemelen örneklerden ziyade inotify saatler tükeniyor . Kimin çok saat yarattığını bulmak için:

  1. echo 1 >> /sys/kernel/debug/tracing/events/syscalls/sys_exit_inotify_add_watch/enableSaat eklerinin izlenmesini sağlamak için yapın ;
  2. Do cat /sys/kernel/debug/tracing/tracing_enabledemin 1'e set ve bunu yapmak değilse oluyor yapmak echo 1 >> /sys/kernel/debug/tracing/tracing_enabled;
  3. Çok fazla saat oluşturduğunuzdan şüphelendiğiniz inotify örnekleriyle (Petr Uzel'in cevabında tanımlandığı şekilde belirlenir) işlemleri yeniden başlatın; ve
  4. /sys/kernel/debug/tracing/traceKaç saatin yaratıldığını ve hangi işlemlerin yapıldığını izlemek için dosyayı okuyun .

İşiniz bittiğinde, izlemeyi kapatmak için 0'ı etkinleştirme dosyasına (ve bunu etkinleştirmek zorunda kalırsanız tracing_enabled dosyası) eklemeye dikkat edin, böylece izlemeye devam etmenin performansına maruz kalmazsınız.


Çok sayıda inotify saati yaratan bir yedekleme uygulamasıydı ve kabul edilen cevabın çözümü suçluyu tanımlamaya yardımcı oldu. Ancak, daha önce burada gösterdiğiniz sistem çağrısı izlemesine aşina değildim. Çok havalı. Bilgi için teşekkürler!
lar

2
'/ sys / kernel / debug / tracing / tracing_enabled' olduğundan emin misin? Benim sistemimde doğru yol '/ sys / kernel / debug / tracing / tracing_on' ... gibi görünüyor ...
Kartoch

Orada hiçbir / sys / kernel / debug / izleme / etkinlik / syscalls / sys_exit_inotify_add_watch / etkinleştirmek ne de / sys / kernel / debug / izleme / tracing_enabled Gentoo Linux üzerinde, ama / sys / kernel / debug / izleme / tracing_enabled bulunmaktadır. Neden?
zeekvfu

@Kartoch'un belirttiği gibi, echo 1 | sudo tee /sys/kernel/debug/tracing/tracing_onmodern dağıtımlar yapmanız gerekiyor (Ubuntu 18.04.2 LTS).
oligofren

Benim için komutları yapmak yeterli değildi, benim de yapmam gerekiyordu: `cd / sys / kernel / debug / tracing /; echo işlevi> current_tracer; echo SyS_inotify_add_watch> set_ftrace_filter`
oligofren

7

@Jonathan Kamens'ın dediği gibi, muhtemelen saatler tükeniyor. Bir var önceden yapılmış senaryo , inotify-consumerssenin için o listeleri bu:

$ time inotify-consumers  | head

   INOTIFY
   WATCHER
    COUNT     PID     CMD
----------------------------------------
    6688    27262  /home/dvlpr/apps/WebStorm-2018.3.4/WebStorm-183.5429.34/bin/fsnotifier64
     411    27581  node /home/dvlpr/dev/kiwi-frontend/node_modules/.bin/webpack --config config/webpack.dev.js
      79     1541  /usr/lib/gnome-settings-daemon/gsd-xsettings
      30     1664  /usr/lib/gvfs/gvfsd-trash --spawner :1.22 /org/gtk/gvfs/exec_spaw/0
      14     1630  /usr/bin/gnome-software --gapplication-service

real    0m0.099s
user    0m0.042s
sys 0m0.062s

Burada, geliştirme makinesinde 8K izleyicilerin varsayılan sınırının neden çok az olduğunu hızlı bir şekilde görebilirsiniz; çünkü WebStorm örneği node_modules, binlerce klasör içeren bir klasörle karşılaştığında bu durumu hemen maksimuma çıkarır . Sorunları garantilemek için bir web paketi izleyici ekleyin ...

Sadece komut (veya GitHub'dan dosyası) içeriğini kopyalayıp Gözlerinde farklı bir yere koymak $PATHgibi /usr/local/bin. Başvuru için, betiğin ana içeriği sadece budur

find /proc/*/fd \
    -lname anon_inode:inotify \
    -printf '%hinfo/%f\n' 2>/dev/null \
    \
    | xargs grep -c '^inotify'  \
    | sort -n -t: -k2 -r 

Limitleri nasıl artıracağınızı merak ediyorsanız, işte bunu nasıl kalıcı hale getireceksiniz:

echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

1
Birçok başka öneri benim için işe yaramadı, ama bu senaryo Fedora 29'da harika çalıştı. Teşekkürler!
Richard S. Hall

6

Ben bu sorunu koştu ve bu cevapların hiçbiri size cevap vermek "kaç saatler her işlem şu anda kullanıyor?" Tek gömlekler, size hikayenin yalnızca bir parçası olan kaç örnek açık olduğunu gösterir ve iz öğeleri yalnızca yeni saatlerin açıldığını görmek için kullanışlıdır.

TL; DR: Bu, size açık inotifyörnekler listesi ve sahip oldukları saat sayısının yanı sıra, onları üreten pids ve binaries ile birlikte, saat sırasına göre azalan düzende sıralanan bir dosya getirecektir :

sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); exe=$(sudo readlink $(dirname $(dirname $fdi))/exe); echo -e $count"\t"$fdi"\t"$exe; done | sort -nr > watches

Bu büyük bir karışıklık topu, işte oraya nasıl geldim. Başlamak tailiçin bir test dosyasını çalıştırdım ve açtığı fd'ye baktım:

joel@gladstone:~$ tail -f test > /dev/null &
[3] 22734
joel@opx1:~$ ls -ahltr /proc/22734/fd
total 0
dr-xr-xr-x 9 joel joel  0 Feb 22 22:34 ..
dr-x------ 2 joel joel  0 Feb 22 22:34 .
lr-x------ 1 joel joel 64 Feb 22 22:35 4 -> anon_inode:inotify
lr-x------ 1 joel joel 64 Feb 22 22:35 3 -> /home/joel/test
lrwx------ 1 joel joel 64 Feb 22 22:35 2 -> /dev/pts/2
l-wx------ 1 joel joel 64 Feb 22 22:35 1 -> /dev/null
lrwx------ 1 joel joel 64 Feb 22 22:35 0 -> /dev/pts/2

Yani, 4 araştırmak istediğimiz fd. Bakalım bunun fdinfoiçin ne var :

joel@opx1:~$ cat /proc/22734/fdinfo/4
pos:    0
flags:  00
mnt_id: 11
inotify wd:1 ino:15f51d sdev:ca00003 mask:c06 ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:1df51500a75e538c

Bu saatin altındaki bir giriş gibi görünüyor!

Daha fazla saat içeren bir şey deneyelim, bu sefer inotifywaityardımcı programla birlikte , içinde ne olduğunu izleyerek /tmp:

joel@gladstone:~$ inotifywait /tmp/* &
[4] 27862
joel@gladstone:~$ Setting up watches.
Watches established.
joel@gladstone:~$ ls -ahtlr /proc/27862/fd | grep inotify
lr-x------ 1 joel joel 64 Feb 22 22:41 3 -> anon_inode:inotify
joel@gladstone:~$ cat /proc/27862/fdinfo/3
pos:    0
flags:  00
mnt_id: 11
inotify wd:6 ino:7fdc sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:dc7f0000551e9d88
inotify wd:5 ino:7fcb sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:cb7f00005b1f9d88
inotify wd:4 ino:7fcc sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:cc7f00006a1d9d88
inotify wd:3 ino:7fc6 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:c67f00005d1d9d88
inotify wd:2 ino:7fc7 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:c77f0000461d9d88
inotify wd:1 ino:7fd7 sdev:ca00003 mask:fff ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:d77f00000053c98b

Aha! Daha fazla giriş! O zaman altı şeyimiz olmalı /tmp:

joel@opx1:~$ ls /tmp/ | wc -l
6

Mükemmel. Benim yeni inotifywaitsahiptir biri onun girişi fd(burada diğer bir astarları sayma budur) listesinde, ama onun altı girdileri fdinfodosyası. Böylece, belirli bir işlem için verilen bir fd'nin fdinfodosyasına bakarak kaç saat kullandığını anlayabiliriz . Şimdi, saatlerin açık olduğunu bildiren ve her birinin girişlerini saymak için kullanan işlemlerin bir listesini almak için yukarıdakilerden bazılarını bir araya getirmek için fdinfo. Bu yukarıdakine benzer, bu yüzden sadece bir astarı buraya atacağım:

sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); echo -e $count"\t"$fdi; done

Burada bazı kalın şeyler var, ancak temel hususlar çıktıdan awkbir fdinfoyol oluşturmak lsof, pid ve fd numaralarını almak, u / r / w bayrağını sıyırmak için kullanmam. Daha sonra her inşa edilmiş fdinfoyol için inotifysatır sayısını sayıyorum ve sayımı ve pid'i çıktıyorum.

Bu çukurların aynı yerde temsil ettiği süreçleri olsa da iyi olurdu, değil mi? Ben de öyle düşünmüştüm. Yani, özellikle dağınık biraz, ben çağırmadan yerleşmiş dirnameiki kez fdinfoiçin paketi almak için yolun /proc/<pid>ekleyerek /exekendisine ve sonra çalışan readlinküzerinde bu sürecin exe adını alır. Şuraya atın, saat sayısına göre sıralayın ve güvenliğini sağlamak için bir dosyaya yönlendirin ve şunu elde ederiz:

sudo lsof | awk '/anon_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | while read fdi; do count=$(sudo grep -c inotify $fdi); exe=$(sudo readlink $(dirname $(dirname $fdi))/exe); echo -e $count"\t"$fdi"\t"$exe; done | sort -n > watches

Sadece yukarıda başlattığım işlemleri göstermek için sudo olmadan çalıştırıyorum :

joel@gladstone:~$ cat watches 
6   /proc/4906/fdinfo/3 /usr/bin/inotifywait
1   /proc/22734/fdinfo/4    /usr/bin/tail

Mükemmel! Bir süreç listesi, fd'ler ve her birinin kaç saat kullandığı, bu tam olarak ihtiyacım olan şeydi.


Kullanırken lsofbu amaçla, ben kullanarak öneriyoruz -nPters DNS ve liman isimlerin gereksiz aramaları önlemek için bayraklar. Bu özel durumda, -bwpotansiyel olarak engelleme sistemlerini engellememek için eklenmesi de önerilir. Yani birlikte, söz konusu lsof(2 saniye çekirdekte harcanır) benim mütevazı iş istasyonunda duvar saati süresi 3 saniye tamamını işgal, bu yaklaşım keşif ama izleme amaçları için uygun olmayan eyvah güzel.
BertD,

Tek astarınızın son derece yavaş olduğunu buldum, ancak bazı bilgi kayıpları pahasına güzel bir gelişme var (dosya tanımlayıcı yerine işlem başına izleyicileri göreceğiz): Önce bir ara dosya oluşturun: lsof | awk '/a_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | sed 's/fdinfo.*//' | sort | uniq > uniq-osonracat uniq-o | while read fdi; do count=$(cat ${fdi}fdinfo/* | grep -c inotify 2>/dev/null); exe=$(readlink ${fdi}exe); echo -e $count"\t"${fdi}"\t"$exe; done > watches
LLlAMnYP

5

Hangi işlemlerin saati inotify ettiğini (örnekleme yapılmadığını) izlemek için, çekirdeğinizde etkinleştirilmişse, çekirdeğin dinamik ftrace özelliğini kullanabilirsiniz.

İhtiyacınız olan çekirdek seçeneği CONFIG_DYNAMIC_FTRACE.

Önceden monte edilmemişse, önce debugfs dosya sistemini bağlayın.

mount -t debugfs nodev /sys/kernel/debug

Altından geçin tracingbu debugfs dizinin alt dizini

cd /sys/kernel/debug/tracing

İşlev çağrılarının izlenmesini etkinleştir

echo function > current_tracer

Yalnızca SyS_inotify_add_watchsistem çağrılarını filtrele

echo SyS_inotify_add_watch > set_ftrace_filter

Boş değilse izleme halkası arabelleğini temizleyin

echo > trace

Zaten etkin değilse izlemeyi etkinleştir

echo 1 > tracing_on

Şüphelenilen işlemi yeniden başlatın (benim durumumda crashplan, bir yedekleme uygulamasıydı)

Inotify_watch'ın yorulduğunu izle

wc -l trace
cat trace

Bitti


3
find /proc/*/fd/* -type l -lname 'anon_inode:inotify' 2>/dev/null | cut -f 1-4 -d'/' |  sort | uniq -c  | sort -nr

1

Yukarıda belirtilen betiği, kaynakları inotify alan işlemlerin listesini gösterecek şekilde değiştirdim :

ps -p `find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print | sed s/'^\/proc\/'/''/ | sed s/'\/fd.*$'/''/`

Sanırım çift seddimi değiştirmenin bir yolu var .


Evet. Either "kalıbını kullanınız

cut -f 3 -d '/'   

veya

sed -e 's/^\/proc\/\([0-9]*\)\/.*/\1'  

ve sen sadece parayı alacaksın.
Ayrıca, eklerseniz

2> /dev/null  

Bul'da bulduğunuz atılan sinir bozucu hata çizgilerinden kurtulacaksınız. Yani bu işe yarar:

ps -p $(find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print 2> /dev/null | sed -e 's/^\/proc\/\([0-9]*\)\/.*/\1/')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.