Manjusaka

Manjusaka

關於 inotify 的 Linux 小筆記

最近還是無心寫甚麼文章,說好的寫幾篇關於 Raft 的論文也因為一些事情延遲了。但是想了想還是準備寫點什麼,於是寫個小的水文來記錄下關於今天碰到的一個 Linux 內核參數的問題,順便做個筆記

開始#

我是一個不太喜歡 Mac 的人,所以我自己在家使用的開發環境是 Manjaro(這裡打個廣告,非常棒的發行版,堪稱開箱即用,廣告五毛一條)。然後程式碼工具就是 Jetbrains 的全家桶和 VSCode 搭配使用。

今天打開 Goland 的時候,發現 IDE 給了這樣一個 Warning ,External file changes sync may be slow: The current inotify(7) watch limit is too low.

於是大家知道,我是個看著這些 warning 有強迫症的人,於是我就去查了查

簡單聊聊#

我們平常經常會有需求,去監控一個檔案或者一個目錄下的變化,比如創建檔案,刪除檔案等。我們常規的做法可能是一個直接暴力輪詢的方式來做

但是這樣的性能會極差。那麼我們有沒有甚麼手段來處理一下這個事情呢?

有的! Linux 提供了對應的 API 來處理這事,這就是我們今天要聊到的 inotify

按照官方的說法,inotify 其實很簡單,

The inotify API provides a mechanism for monitoring file system events. Inotify can be used to monitor individual files, or to monitor directories. When a directory is monitored, inotify will return events for the directory itself, and for files inside the directory.

大意就是說 inotify 是用來監控檔案系統事件的。可以使用在單個檔案或者目錄上。被監聽的檔案目錄本身的變化或者內部檔案的變化都在監聽範圍內。

在監聽了對應的檔案後,inotify 將返回如下事件

  1. IN_ACCESS 檔案可讀

  2. IN_ATTRIB 元數據變化

  3. IN_CLOSE_WRITE File opened for writing was closed

  4. IN_CLOSE_NOWRITE File not opened for writing was closed

  5. IN_CREATE 被監聽的目錄下有檔案 / 目錄被創建

  6. IN_DELETE 被監聽的目錄下有檔案 / 目錄被刪除

  7. IN_DELETE_SELF 被監聽的檔案 / 目錄被刪除

  8. IN_MODIFY 檔案被修改

  9. IN_MOVE_SELF 被監聽的檔案 / 目錄被移動

  10. IN_MOVED_FROM 有檔案 / 目錄從被監聽的目錄中被移出

  11. IN_MOVED_TO 有檔案 / 目錄移動至被監聽的目錄中

  12. IN_OPEN 檔案被打開

總共 12 類事件,已經能涵蓋住我們常見的需求。但是 inotify 也有其自己的弊端。

  1. 不支持遞歸監聽。舉個例子,我監聽 A 目錄,我可以捕獲到在 A 目錄下創建 B 目錄這個事件。但是我們沒法監聽到 B 目錄下事件,除非將 B 目錄也添加到監聽隊列中

  2. Python 可用的 inotify 很少

對於第一個缺陷。常見的解決手段,是我們自行實現遞歸監聽。當主目錄下存在創建檔案 / 目錄事件的時候,我們將對應的檔案 / 目錄也添加到監聽隊列中。

但是這樣就帶來一個新的問題。如果一個非常大的專案,我們按照這樣的方式去做,那麼最後對應的記憶體損耗是很嚇人的。所以在 inotify 設計之初,就通過一些內核參數做了一些限制

我們常見的有兩個

  1. /proc/sys/fs/inotify/max_queued_events 限制事件隊列長度,一旦出現事件堆積,那麼新的事件將被廢棄

  2. /proc/sys/fs/inotify/max_user_watches 限制每個 User ID 能夠創建的 watcher 數,以免監聽過多導致記憶體爆炸

在默認情況下 max_user_watches 的值取決於不同的 Linux 發行版,對於大多數發行版而言,其值相對較小。也就是說一旦達到限制,那麼將沒法添加新的 watcher。這也是 IDE 為什麼會提示
External file changes sync may be slow: The current inotify(7) watch limit is too low. 的原因

可以通過修改 /etc/sysctl.conf 來修改對應的參數,最後解決這個問題

最後#

Linux 果然是個寶庫。感覺隔三差五就會遇到自己沒涉及到的東西。所以還是記錄下來,當作一篇水文,順便供自己參閱

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。