ใครเป็นผู้ใช้ทรัพยากรที่ไม่รู้ค่าของฉัน


49

หลังจากอัปเกรดเป็น Fedora 15 เมื่อเร็ว ๆ นี้ฉันพบว่ามีเครื่องมือจำนวนหนึ่งที่ล้มเหลวพร้อมข้อผิดพลาดตามบรรทัดของ:

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

ไม่ใช่แค่tailการรายงานปัญหาเกี่ยวกับ inotify เช่นกัน มีวิธีใดที่จะซักถามเคอร์เนลเพื่อค้นหาว่ากระบวนการหรือกระบวนการใดที่ใช้ทรัพยากรที่ไม่มีการระบุ? การsysctlตั้งค่าที่ไม่เกี่ยวข้องกับ inotify ปัจจุบันมีลักษณะดังนี้:

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

คำตอบ:


39

ดูเหมือนว่าหากกระบวนการสร้างอินสแตนซ์ inotify ผ่าน inotify_init () ไฟล์ผลลัพธ์ที่แสดงถึง filescriptor ในระบบไฟล์ / proc เป็น symlink ไปยังไฟล์ 'anon_inode: inotify' (ไม่ใช่ที่มีอยู่)

$ 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

ยกเว้นว่าฉันเข้าใจผิดแนวคิดคำสั่งต่อไปนี้ควรแสดงรายการกระบวนการ (การแสดงของพวกเขาใน / proc) เรียงลำดับตามจำนวนอินสแตนซ์อินสแตนซ์ที่พวกเขาใช้

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

8
ยอดเยี่ยมขอบคุณ! ฉันไม่รู้เกี่ยวกับ inotify inodes ที่ปรากฏใน / proc สำหรับวัตถุประสงค์ของฉันคำสั่งสามารถทำให้สิ่งนี้ง่ายขึ้น:find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print
larsks

ฉันดีใจที่มันช่วย และทางออกของคุณที่มี find -lname นั้นดีกว่าของฉันมากสำหรับ loop และ readlink
Petr Uzel

3
โปรดทราบว่าคุณอาจเลิกใช้นาฬิกาได้ (ไม่ใช่กรณี) เช่นในระบบของฉันที่ให้จำนวนเด็กน้อย แต่มีนาฬิกานับหมื่นนับพันจากการค้นหาเดสก์ทอปของ KDE มันเลวร้ายเกินไปมีไม่ได้เป็นวิธีที่ง่ายต่อการตรวจสอบจำนวนนาฬิกา / กรณีในการใช้งานเนื่องจากเคอร์เนลรู้ได้อย่างชัดเจน ...
derobert

เพื่อแสดงบรรทัดคำสั่งของโปรแกรมที่ละเมิด:find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -exec sh -c 'cat $(dirname {})/../cmdline; echo ""' \; 2>/dev/null
Mark K Cowan

@derobert ฉันสร้างสคริปต์เพื่อแสดงรายการกระบวนการที่ใช้เวลาในการเฝ้าดูซึ่งมักเป็นสิ่งที่ผู้คนให้ความสนใจ ดูคำตอบของฉันด้านล่าง
oligofren

25

คุณอาจไม่ได้ระบุจำนวนนาฬิกามากกว่าอินสแตนซ์ หากต้องการทราบว่าใครกำลังสร้างนาฬิกาจำนวนมาก:

  1. ทำecho 1 >> /sys/kernel/debug/tracing/events/syscalls/sys_exit_inotify_add_watch/enableเพื่อเปิดใช้งานการติดตามการเพิ่มนาฬิกา
  2. ทำcat /sys/kernel/debug/tracing/tracing_enabledเพื่อให้แน่ใจว่ามันถูกตั้งค่าเป็น 1 และถ้ามันไม่ได้ทำecho 1 >> /sys/kernel/debug/tracing/tracing_enabled;
  3. รีสตาร์ทกระบวนการด้วย inotify อินสแตนซ์ (พิจารณาตามที่อธิบายไว้ในคำตอบของ Petr Uzel) ว่าคุณสงสัยว่าจะสร้างนาฬิกาเป็นจำนวนมาก และ
  4. อ่านไฟล์/sys/kernel/debug/tracing/traceเพื่อดูจำนวนนาฬิกาที่ถูกสร้างและกระบวนการใด

เมื่อเสร็จแล้วตรวจสอบให้แน่ใจว่าได้ echo 0 ลงในไฟล์เปิดใช้งาน (และไฟล์ tracing_enabled หากคุณต้องเปิดใช้งานด้วย) เพื่อปิดการติดตามดังนั้นคุณจะไม่ได้รับประสิทธิภาพการทำงานของการติดตามต่อไป


มันเป็นแอปพลิเคชั่นสำรองที่สร้างนาฬิกาที่ไม่ระบุจำนวนมากและโซลูชันในคำตอบที่ได้รับการยอมรับช่วยระบุผู้กระทำผิด อย่างไรก็ตามก่อนหน้านี้ฉันไม่คุ้นเคยกับการติดตามการโทรของระบบที่คุณแสดงไว้ที่นี่ เด็ดมาก ขอบคุณสำหรับข้อมูล!
larsks

2
คุณแน่ใจหรือไม่ว่าเป็น '/ sys / kernel / debug / tracing / tracing_enabled' ในระบบของฉันดูเหมือนว่าเส้นทางที่ถูกต้องคือ '/ sys / kernel / debug / ติดตาม / tracing_on' ...
Kartoch

ไม่มี / sys / kernel / debug / ติดตาม / events / syscalls / sys_exit_inotify_add_watch / enableหรือ/ sys / kernel / debug / ติดตาม / tracing_enabledบน Gentoo Linux แต่มี/ sys / kernel / debug / tracing_enabledอยู่ ทำไมถึงเป็นอย่างนั้น?
zeekvfu

ตามที่ @Kartoch หมายถึงคุณต้องทำecho 1 | sudo tee /sys/kernel/debug/tracing/tracing_onกับ distros ที่ทันสมัย ​​(Ubuntu 18.04.2 LTS)
oligofren

มันไม่เพียงพอที่จะทำคำสั่งสำหรับฉันฉันยังต้องทำ: `cd / sys / kernel / debug / tracing /; ฟังก์ชั่น echo> current_tracer; echo SyS_inotify_add_watch> set_ftrace_filter`
oligofren

7

ดังที่ @Jonathan Kamens กล่าวว่าคุณอาจจะดูไม่ทัน ฉันมีสคริปต์เพสตรี้ , inotify-consumers, ที่แสดงนี้สำหรับคุณ:

$ 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

ที่นี่คุณจะเห็นได้อย่างรวดเร็วว่าทำไมขีด จำกัด เริ่มต้นของนักดู 8K นั้นน้อยเกินไปบนเครื่องพัฒนาเนื่องจากอินสแตนซ์ของ WebStorm เพียงแค่เพิ่มความเร็วสูงสุดเมื่อพบnode_modulesโฟลเดอร์ที่มีโฟลเดอร์นับพัน เพิ่ม webpack watcher เพื่อรับประกันปัญหา ...

เพียงแค่คัดลอกเนื้อหาของสคริปต์ (หรือไฟล์บน GitHub) และวางไว้ที่ไหนสักแห่งในของคุณเช่น$PATH /usr/local/binสำหรับการอ้างอิงเนื้อหาหลักของสคริปต์คือสิ่งนี้

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

ในกรณีที่คุณสงสัยว่าจะเพิ่มขีด จำกัด ได้อย่างไรต่อไปนี้เป็นวิธีทำให้ถาวร:

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

1
คำแนะนำอื่น ๆ มากมายนั้นใช้งานไม่ได้สำหรับฉัน แต่สคริปต์นี้ใช้ได้ดีกับ Fedora 29 ขอบคุณ!
Richard S. Hall

6

ฉันพบปัญหานี้และไม่มีคำตอบใดที่ให้คำตอบว่า " แต่ละกระบวนการใช้นาฬิกาเป็นจำนวนเท่าไร" ผู้เดินสมุทรรายหนึ่งทั้งหมดให้คุณเปิดอินสแตนซ์ได้กี่ครั้งซึ่งเป็นเพียงส่วนหนึ่งของเรื่องราวและเนื้อหาการติดตามมีประโยชน์สำหรับการดูนาฬิกาใหม่ที่กำลังเปิดเท่านั้น

TL; DR:นี่จะให้ไฟล์ที่มีรายการinotifyอินสแตนซ์ที่เปิดอยู่และจำนวนนาฬิกาที่พวกเขามีรวมถึง pids และไบนารีที่วางไข่เรียงลำดับตามลำดับจากมากไปน้อยตามจำนวนการดู:

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

นั่นเป็นปัญหาใหญ่ดังนั้นนี่คือวิธีที่ฉันไปถึงที่นั่น ในการเริ่มต้นฉันรันtailไฟล์ทดสอบและดูไฟล์ fd ที่เปิดอยู่:

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

ดังนั้น 4 คือ fd ที่เราต้องการตรวจสอบ มาดูกันว่ามีอะไรบ้างในเรื่องfdinfoนั้น:

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

ดูเหมือนว่ารายการสำหรับนาฬิกาที่อยู่ด้านล่าง!

ลองทำอะไรกับนาฬิกามากขึ้นคราวนี้ด้วยinotifywaitยูทิลิตี้ดูสิ่งที่อยู่ใน/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! รายการเพิ่มเติม! ดังนั้นเราควรมีหกสิ่งในเวลา/tmpนั้น:

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

ยอดเยี่ยม ใหม่ของฉันinotifywaitมีหนึ่งรายการในfdรายการ (ซึ่งเป็นสิ่งที่หนึ่งสมุทรอื่น ๆ ที่นี่นับ) แต่หกรายการในfdinfoไฟล์ ดังนั้นเราจึงสามารถทราบได้ว่าจำนวนการเฝ้าดู fd ที่กำหนดสำหรับกระบวนการที่กำหนดนั้นใช้งานอย่างไรโดยดูจากfdinfoไฟล์ ทีนี้มารวมกันกับข้างต้นเพื่อหยิบรายการกระบวนการที่มีการแจ้งเตือนนาฬิกาเปิดอยู่และใช้การนับรายการในแต่ละfdinfoรายการ นี่คล้ายกับข้างบนดังนั้นฉันจะทิ้งหนึ่งซับไว้ที่นี่:

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

มีบางสิ่งที่หนาในที่นี่ แต่พื้นฐานคือฉันใช้awkในการสร้างfdinfoเส้นทางจากlsofเอาท์พุท, คว้าหมายเลข pid และ fd, ปอกธง u / r / w จากหลัง จากนั้นสำหรับแต่ละfdinfoเส้นทางที่สร้างฉันจะนับจำนวนinotifyบรรทัดและส่งออกจำนวนและ pid

มันคงจะดีถ้าฉันมีกระบวนการอะไรที่ pids เหล่านี้แสดงอยู่ในที่เดียวกันใช่ไหม? ฉันคิดอย่างนั้น ดังนั้นในบิตยุ่งโดยเฉพาะฉันตัดสินโทรdirnameสองครั้งบนfdinfoเส้นทางเพื่อรับแพ็ค/proc/<pid>เพิ่ม/exeไปแล้วทำงานreadlinkบนที่เพื่อรับชื่อ exe ของกระบวนการ โยนลงไปที่นั่นเช่นกันเรียงตามจำนวนนาฬิกาและเปลี่ยนเส้นทางไปยังไฟล์เพื่อความปลอดภัยและเราจะได้รับ:

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

ทำงานโดยไม่ต้อง sudo เพียงแค่แสดงกระบวนการของฉันฉันเปิดตัวข้างต้นฉันได้รับ:

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

ที่สมบูรณ์แบบ! รายการกระบวนการ fd's และจำนวนการเฝ้าดูแต่ละครั้งใช้ซึ่งเป็นสิ่งที่ฉันต้องการ


เมื่อใช้lsofเพื่อจุดประสงค์นี้ฉันขอแนะนำให้ใช้-nPแฟล็กเพื่อหลีกเลี่ยงการค้นหา DNS และชื่อพอร์ตย้อนกลับโดยไม่จำเป็น ในกรณี-bwนี้แนะนำให้เพิ่มเพื่อหลีกเลี่ยงการบล็อก syscalls ด้วย ที่กล่าวว่าด้วยการlsofกลืนนาฬิกาเวลา 3 วินาทีบนเวิร์กสเตชันที่ถ่อมตนของฉัน (ซึ่งใช้เวลา 2 วินาทีในเคอร์เนล) วิธีนี้เหมาะสำหรับการสำรวจ แต่ก็ไม่เหมาะสำหรับการตรวจสอบ
BertD

ฉันพบว่าสายการบินหนึ่งของคุณช้ามาก แต่มีการปรับปรุงที่ดีมากในราคาที่สูญเสียข้อมูลบางส่วน (เราจะเห็นผู้ดูต่อกระบวนการมากกว่าที่จะอธิบายต่อไฟล์): ก่อนสร้างไฟล์ระดับกลาง: lsof | awk '/a_inode/ { gsub(/[urw]$/,"",$4); print "/proc/"$2"/fdinfo/"$4; }' | sed 's/fdinfo.*//' | sort | uniq > uniq-oจากนั้นcat 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

หากต้องการติดตามว่ากระบวนการใดใช้การ inotify watches (ไม่ใช่อินสแตนซ์) คุณสามารถใช้คุณสมบัติ ftrace แบบไดนามิกของเคอร์เนลหากเปิดใช้งานในเคอร์เนลของคุณ

CONFIG_DYNAMIC_FTRACEตัวเลือกเคอร์เนลที่คุณต้องการคือ

ขั้นแรกเมาท์ระบบไฟล์ debugfs หากยังไม่ได้เมาต์

mount -t debugfs nodev /sys/kernel/debug

ไปที่tracingไดเรกทอรีย่อยของไดเรกทอรี debugfs นี้

cd /sys/kernel/debug/tracing

เปิดใช้งานการติดตามการเรียกใช้ฟังก์ชัน

echo function > current_tracer

กรองการSyS_inotify_add_watchเรียกระบบเท่านั้น

echo SyS_inotify_add_watch > set_ftrace_filter

ล้างบัฟเฟอร์การติดตามแหวนถ้ามันไม่ว่างเปล่า

echo > trace

เปิดใช้งานการติดตามหากยังไม่ได้เปิดใช้งาน

echo 1 > tracing_on

เริ่มกระบวนการที่สงสัยใหม่อีกครั้ง (ในกรณีของฉันคือ crashplan ซึ่งเป็นแอปพลิเคชันสำรอง)

ดู inotify_watch ที่กำลังหมด

wc -l trace
cat trace

เสร็จสิ้น



1

ฉันได้แก้ไขสคริปต์ที่มีอยู่ในด้านบนเพื่อแสดงรายการของกระบวนการที่ใช้ทรัพยากรที่ไม่สมควร :

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

ผมคิดว่าไม่มีทางที่จะมาแทนที่คู่ของฉันsed


ใช่. ใช้อย่างใดอย่างหนึ่ง

cut -f 3 -d '/'   

หรือ

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

และคุณจะได้รับ pid เท่านั้น
นอกจากนี้ถ้าคุณเพิ่ม

2> /dev/null  

ในการค้นหาคุณจะกำจัดเส้นข้อผิดพลาดที่น่ารำคาญโดยการค้นหา ดังนั้นสิ่งนี้จะได้ผล:

ps -p $(find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print 2> /dev/null | sed -e 's/^\/proc\/\([0-9]*\)\/.*/\1/')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.