कौन मेरे संसाधनों का उपभोग कर रहा है?


49

फेडोरा 15 में हाल ही में अपग्रेड करने के बाद, मुझे पता चला है कि कई उपकरण त्रुटियों के साथ विफल हो रहे हैं:

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

यह सिर्फ tailinotify के साथ समस्याओं की रिपोर्ट नहीं है। क्या कर्नेल से पूछताछ करने का कोई तरीका है जिससे पता लगाया जा सके कि कौन सी प्रक्रिया या प्रक्रियाएँ इन-टॉटिज़ संसाधनों का उपभोग कर रही हैं? वर्तमान inotify- संबंधित sysctlसेटिंग्स इस तरह दिखती हैं:

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

जवाबों:


39

ऐसा लगता है कि यदि प्रक्रिया inotify_init () के माध्यम से inotify आवृत्ति बनाता है, तो परिणामस्वरूप फ़ाइल जो / proc फ़ाइल सिस्टम में फ़ाइलस्क्रिप्ट का प्रतिनिधित्व करती है, वह (गैर-मौजूदा) '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

जब तक मैं अवधारणा को गलत नहीं समझ लेता, तब तक निम्न आदेश आपको प्रक्रियाओं की सूची (उनके प्रतिनिधित्व / खरीद में) दिखा सकते हैं, जो उनके द्वारा उपयोग किए जाने वाले इनोटीफाइड इंस्टेंसेस की संख्या द्वारा क्रमबद्ध हैं।

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

8
बहुत बड़िया धन्यवाद! मुझे पता नहीं था कि इनोटाइज़ इनोडेस के बारे में / proc में दिखा रहा है। मेरे उद्देश्यों के लिए, इस आदेश को सरल बनाया जा सकता है:find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print
लार्क्स

मुझे खुशी है कि इसने मदद की। और खोजने के साथ अपने समाधान -lname वास्तव में लूप और रीडलिंक के लिए खदान की तुलना में बहुत अच्छा है।
पेट्र उज़ेल

3
ध्यान दें कि आप घड़ियों से बाहर भी हो सकते हैं (उदाहरण नहीं)। उदाहरण के लिए, मेरे सिस्टम पर, जो कम-किशोर संख्याओं को उदाहरण देता है, लेकिन केडीई के डेस्कटॉप खोज से कई दसियों घड़ियां हैं। इसका बहुत बुरा वहाँ जाँच करने के लिए कितने घड़ियों / उदाहरणों, उपयोग में हैं के बाद से गिरी स्पष्ट रूप से जानता है एक आसान तरीका नहीं है ...
derobert

अपमानजनक कार्यक्रमों की कमांड लाइन दिखाने के लिए:find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -exec sh -c 'cat $(dirname {})/../cmdline; echo ""' \; 2>/dev/null
मार्क के कोवान

@derobert मैंने वॉचर्स का उपभोग करने वाली प्रक्रियाओं को सूचीबद्ध करने के लिए एक स्क्रिप्ट बनाई, जो आमतौर पर किसी को परवाह है। मेरा जवाब नीचे देखें।
ओलिगोफ़्रेन

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. आवृत्तियों को रोकें के साथ प्रक्रियाओं को फिर से शुरू करें (पेट्र उज़ेल के उत्तर में वर्णित के रूप में निर्धारित) कि आपको बहुत सी घड़ियां बनाने का संदेह है; तथा
  4. /sys/kernel/debug/tracing/traceदेखने के लिए फ़ाइल पढ़ें कि कितनी घड़ियाँ बनाई गई हैं और किन प्रक्रियाओं से।

जब आप कर लें, तो सक्षम फ़ाइल (और अनुरेखण_अनुकूलित फ़ाइल यदि आप को सक्षम करने के लिए) को ट्रेसिंग को बंद करने के लिए 0 प्रतिध्वनित करना सुनिश्चित करें ताकि आप ट्रेस करने के लिए प्रदर्शन हिट को बाधित न करें।


यह एक बैकअप एप्लिकेशन था जो बहुत सारे इनोटिफ़ वॉच का निर्माण कर रहा था, और स्वीकृत उत्तर में समाधान से अपराधी को पहचानने में मदद मिली। हालाँकि, मैं पहले आपके द्वारा यहाँ प्रदर्शित सिस्टम कॉल ट्रेसिंग से परिचित नहीं था। बहुत ही शांत। जानकारी के लिए धन्यवाद!
लार्क्स

2
क्या आप सुनिश्चित हैं कि यह '/ sys / कर्नेल / डिबग / ट्रेसिंग / अनुरेखण_सक्षम' है? मेरे सिस्टम पर ऐसा लगता है कि सही रास्ता है '/ sys / कर्नेल / डिबग / ट्रेसिंग / ट्रैसिंग_ऑन ...
Kartoch

Gentoo लिनक्स पर कोई / sys / कर्नेल / डिबग / ट्रेसिंग / इवेंट / syscalls / sys_exit_inotify_add_watch नहीं है या न ही / sys / कर्नेल / डिबग / ट्रेसिंग / अनुरेखण / सक्षम है , लेकिन / sys / कर्नेल / डिबग / ट्रेसिंग / पताका मौजूद है। ऐसा क्यों है?
zeekvfu

जैसा कि @ कार्टोच का अर्थ है, आपको echo 1 | sudo tee /sys/kernel/debug/tracing/tracing_onआधुनिक डिस्ट्रोस (उबंटू 18.04.2 एलटीएस) पर करने की आवश्यकता है ।
ओलिगोफ़्रेन

मेरे लिए आज्ञाएँ करना पर्याप्त नहीं था, मुझे भी करने की आवश्यकता थी: `सीडी / एसआईएस / कर्नेल / डिबग / ट्रेसिंग /; गूंज समारोह> current_tracer; इको SyS_inotify_add_watch> set_ftrace_filter`
oligofren

7

जैसा कि @ जोनाथन कमेंस ने कहा, आप शायद घड़ियों से बाहर चल रहे हैं। मैं एक है पूर्व बनाया स्क्रिप्ट , 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 देखने वालों की डिफ़ॉल्ट सीमा एक विकास मशीन पर बहुत कम है, क्योंकि node_modulesहजारों फ़ोल्डरों के साथ एक फ़ोल्डर का सामना करते समय बस वेबस्टॉर्म उदाहरण जल्दी से इसे अधिकतम करता है । समस्याओं की गारंटी के लिए एक वेबपैक पहरेदार जोड़ें ...

बस स्क्रिप्ट की सामग्री की प्रतिलिपि बनाएँ (या 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
कई अन्य सुझावों ने मेरे लिए अच्छा काम नहीं किया, लेकिन इस स्क्रिप्ट ने फेडोरा 29 पर बहुत अच्छा काम किया। धन्यवाद!
रिचर्ड एस। हॉल

6

मैं इस समस्या में भाग गया, और इनमें से कोई भी उत्तर आपको "कितनी घड़ियों का उपयोग कर रहा है, जो वर्तमान में उपयोग कर रहा है?" वन-लाइनर्स आप सभी को देते हैं कि कितने उदाहरण खुले हैं, जो केवल कहानी का हिस्सा है, और ट्रेस सामान केवल नई घड़ियों को खोलने के लिए उपयोगी है।

टीएल; डीआर: यह आपको खुले inotifyउदाहरणों की एक सूची और उनके पास मौजूद घड़ियों की संख्या के साथ-साथ उन पाईदों और बायनेरिज़ के साथ एक फ़ाइल प्राप्त करेगा , जिन्हें वॉच काउंट द्वारा अवरोही क्रम में सॉर्ट किया गया है:

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 एफडी है जिसे हम जांचना चाहते हैं। आइए देखें कि इसमें क्या 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

अहा! अधिक प्रविष्टियाँ! तो हमारे पास छह चीजें होनी चाहिए /tmp:

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

अति उत्कृष्ट। मेरी नई inotifywaitकी सूची में एक प्रविष्टि है fd(जो कि अन्य वन-लाइनर्स की गिनती यहां है), लेकिन इसकी fdinfoफाइल में छह प्रविष्टियां हैं । तो हम यह पता लगा सकते हैं कि किसी दिए गए प्रक्रिया के लिए दिए गए एफडी में से कितनी घड़ियों का उपयोग इसकी 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, पीआईडी ​​और एफडी संख्या को हथियाने, बाद वाले से यू / आर / डब्ल्यू ध्वज को छीनता हूं । फिर प्रत्येक निर्मित fdinfoपथ के लिए, मैं inotifyलाइनों की संख्या गिनता हूं और गिनती और पिड का उत्पादन करता हूं ।

यह अच्छा होगा यदि मेरे पास ये प्रक्रियाएं एक ही स्थान पर प्रतिनिधित्व करती हैं, हालांकि, सही है? मुझे ऐसा लगा। इसलिए, एक विशेष रूप से गड़बड़ बिट में, मैं पैक करने के लिए पैक करने के लिए 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

बिना सूदो के दौड़ना मेरी प्रक्रियाओं को दिखाने के लिए जो मैंने ऊपर शुरू की, मुझे मिलता है:

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मेरे विनम्र कार्य केंद्र (जिसमें 2 सेकंड कर्नेल में बिताए जाते हैं) पर दीवार घड़ी के समय के 3 सेकंड के साथ छेड़छाड़ के साथ , यह दृष्टिकोण अन्वेषण के लिए अच्छा है, लेकिन निगरानी के उद्देश्यों के लिए अनुपयुक्त है।
बर्टड

मैंने पाया कि आपका वन-लाइनर बेहद धीमा है, लेकिन जानकारी के कुछ नुकसान की कीमत पर एक अच्छा सुधार संभव है (हम फ़ाइल डिस्क्रिप्टर के बजाय प्रति प्रक्रिया पर नजर रखने वाले देखेंगे): पहले एक मध्यवर्ती फ़ाइल उत्पन्न करें: 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 घड़ियों का उपयोग करती हैं (उदाहरणों की नहीं) आप कर्नेल की डायनेमिक फ़ुट्रेस सुविधा का उपयोग कर सकते हैं यदि यह आपके कर्नेल में सक्षम है।

आपके लिए आवश्यक कर्नेल विकल्प है CONFIG_DYNAMIC_FTRACE

यदि यह पहले से माउंट नहीं है, तो पहले डीबगफ़्स फ़ाइल सिस्टम माउंट करें।

mount -t debugfs nodev /sys/kernel/debug

tracingइस डीबगफ़ निर्देशिका के उपनिर्देशिका के अंतर्गत जाएं

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

संदिग्ध प्रक्रिया को पुनरारंभ करें (मेरे मामले में यह क्रैशप्लेन था, एक बैकअप एप्लिकेशन)

देखो inotify_watch समाप्त हो रहा है

wc -l trace
cat trace

किया हुआ


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

1

मैं प्रक्रियाओं उन उपभोग कर रहे हैं की सूची दिखाने के ऊपर में स्क्रिप्ट वर्तमान में बदलाव कर दिया inotify संसाधन:

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

मुझे लगता है कि मेरी डबल सेड को बदलने का एक तरीका है ।


हाँ। या तो उपयोग करें

cut -f 3 -d '/'   

या

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

और आप केवल पीआईडी ​​प्राप्त करेंगे।
साथ ही अगर आप जोड़ते हैं

2> /dev/null  

खोजने में, आप किसी भी pesky त्रुटि लाइनों से छुटकारा पा लेंगे। तो यह काम करेगा:

ps -p $(find /proc/*/fd/* -type l -lname 'anon_inode:inotify' -print 2> /dev/null | sed -e 's/^\/proc\/\([0-9]*\)\/.*/\1/')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.