概要 - 爲什麼需要監控文件系統?
在日常工作中,人們往往需要知道在某些文件(夾)上都有那些變化,比如:
- 通知配置文件的改變
- 跟蹤某些關鍵的系統文件的變化
- 監控某個分區磁盤的整體使用情況
- 系統崩潰時進行自動清理
- 自動觸發備份進程
- 向服務器上傳文件結束時發出通知
通常使用文件輪詢的通知機制,但是這種機制只適用於經常改變的文件(因爲它可以確保每過x秒就可以得到i/o),其他情況下都非常低效,並且有時候會丟失某些類型的變化,例如文件的修改時間沒有改變。像Tripwire這樣的數據完整性系統,它們基於時間調度來跟蹤文件變化,但是如果想實時監控文件的變化的話,那麼時間調度就束手無策了。Inotify就這樣應運而生了。本文將簡要介紹inotify,告訴我們如何監控文件夾,如何一有變化就報告相關消息事件,並介紹了一些相關工具, 我們可以把它們添加到自己的工具箱中。
Inotify到底是什麼?
Inotify是一種文件變化通知機制,Linux內核從2.6.13開始引入。在BSD和Mac OS系統中比較有名的是kqueue,它可以高效地實時跟蹤Linux文件系統的變化。近些年來,以fsnotify作爲後端,幾乎所有的主流Linux發行版都支持Inotify機制。如何知道你的Linux內核是否支持Inotify機制呢?很簡單,執行下面這條命令:
% grep INOTIFY_USER /boot/config-$(uname -r)
CONFIG_INOTIFY_USER=y
如果輸出('CONFIG_INOTIFY_USER=y'),那麼你可以馬上享受Inotify之旅了。
安裝程序inotify
下載inotify ; 地址:http://inotify-tools.sourceforge.net/
編譯安裝
./configure
make
make install
安裝完畢後會有一個inotifywait命令,可以通過man inotifywait 查看具體的命令幫助。主要通過inotifywait 監控具體目錄和文件的變動。
inotify 可以監視的文件系統事件包括:
IN_ACCESS,即文件被訪問
IN_MODIFY,文件被 write
IN_ATTRIB,文件屬性被修改,如 chmod、chown、touch 等
IN_CLOSE_WRITE,可寫文件被 close
IN_CLOSE_NOWRITE,不可寫文件被 close
IN_OPEN,文件被 open
IN_MOVED_FROM,文件被移走,如 mv
IN_MOVED_TO,文件被移來,如 mv、cp
IN_CREATE,創建新文件
IN_DELETE,文件被刪除,如 rm
IN_DELETE_SELF,自刪除,即一個可執行文件在執行時刪除自己
IN_MOVE_SELF,自移動,即一個可執行文件在執行時移動自己
IN_UNMOUNT,宿主文件系統被 umount
IN_CLOSE,文件被關閉,等同於(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
IN_MOVE,文件被移動,等同於(IN_MOVED_FROM | IN_MOVED_TO)
注:上面所說的文件也包括目錄。
inotifywait 命令的常用參數包括:
-m, --monitor 保持一直監聽
-r, --recursive 若有多級目錄循環遞歸每一層。
-q, --quiet 靜默式運行
-e <event>, --event <event> create,move,delete,modify
簡單的文件變化通知樣例:
好的開始是成功的一半,對於瞭解Inotify機制來說,讓我們從使用inotifywait程序開始,它包含在inotify-tools工具包中。假如我們打算監控/srv/test文件夾上的操作,只需執行:
% inotifywait -rme modify,attrib,move,close_write,create,delete,delete_self /srv/test
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
上述任務運行的同時,我們在另一個shell裏依次執行以下操作:創建文件夾,然後在新文件夾下創建文件,接着刪除新創建的文件:
% mkdir /srv/test/infoq
% echo TODO > /srv/test/infoq/article.txt
% rm /srv/test/infoq/article.txt
在運行inotifywait的shell中將會打印以下信息:
/srv/test/ CREATE,ISDIR infoq
/srv/test/infoq/ CREATE article.txt
/srv/test/infoq/ MODIFY article.txt
/srv/test/infoq/ CLOSE_WRITE,CLOSE article.txt
/srv/test/infoq/ DELETE article.txt
顯而易見,只要有變化我們就會收到相關的通知。如果想了解關於Inotify提供的事件(如modify, atrrib等)的詳細信息,請參考inotifywatch的manpage。實際使用時,如果並不想監控某個大文件夾,那麼就可以使用inotifywait的exclude選項。例如:我們要忽略文件夾/srv/test/large,那麼就可以這樣來建立監控:
% inotifywait --exclude '^/srv/test/(large|ignore)/' -rme modify,attrib,move,close_write,create,delete,delete_self /srv/test
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
上面的例子中,在exclude選項的匹配串中我們使用了正則表達式,因爲我們不想將名稱中含有large或ignore的文件也排除掉。我們可以測試一下:
% echo test > /srv/test/action.txt
% echo test > /srv/test/large/no_action.txt
% echo test > /srv/test/ignore/no_action.txt
% echo test > /srv/test/large-name-but-action.txt
這裏inotifywait應該只會報告'action.txt'和'large-name-but-action.txt'兩個文件的變化,而忽略子文件夾'large'和'ignore'下的文件,結果也確實如此;
/srv/test/ CREATE action.txt
/srv/test/ MODIFY action.txt
/srv/test/ CLOSE_WRITE,CLOSE action.txt
/srv/test/ CREATE large-name-but-action.txt
/srv/test/ MODIFY large-name-but-action.txt
/srv/test/ CLOSE_WRITE,CLOSE large-name-but-action.txt
另外,通過使用-t選項我們還可以定義inotifywait的監控時間,既可以讓它執行一段時間,也可以讓它一直運行。util-linux-ng的logger命令也可以實現此功能,不過得先把相關的消息事件發送到syslog,然後從syslog服務器再分析整合。
Inotifywatch - 使用inotify來統計文件系統訪問信息
Inotify-tools中還有一個工具叫inotifywatch,它會先監聽文件系統的消息事件,然後統計每個被監聽文件或文件夾的消息事件,之後輸出統計信息。比如我們想知道某個文件夾上有那些操作:
% inotifywatch -v -e access -e modify -t 120 -r ~/InfoQ
Establishing watches...
Setting up watch(es) on /home/mika/InfoQ
OK, /home/mika/InfoQ is now being watched.
Total of 58 watches.
Finished establishing watches, now collecting statistics.
Will listen for events for 120 seconds.
total modify filename
2 2 /home/mika/InfoQ/inotify/
很顯然,這裏我們監控的是~/InfoQ文件夾,並且可以看到/home/mika/InfoQ/inotify上發生了兩個事件。方法雖簡單,但卻很有效。
Inotify的配置選項
使用Inotify時,要特別注意內核中關於它的兩個配置。首先/proc/sys/fs/inotify/max_user_instances 規定了每個用戶所能創建的Inotify實例的上限;其次/proc/sys/fs/inotify/max_user_watches規定了每個Inotify實例最多能關聯幾個監控(watch)。你可以很容易地試驗在運行過程中達到上限,如:
% inotifywait -r /
Setting up watches. Beware: since -r was given, this may take a while!
Failed to watch /; upper limit on inotify watches reached!
Please increase the amount of inotify watches allowed per user via `/proc/sys/fs/inotify/max_user_watches'.
如果要改變這些配置,只要向相應的文件寫入新值即可,如下所示:
# cat /proc/sys/fs/inotify/max_user_watches
8192
# echo 16000 > /proc/sys/fs/inotify/max_user_watches
# cat /proc/sys/fs/inotify/max_user_watches
16000
使用Inotify的一些工具
近一段時間出現了很多基於Inotify的超炫的工具,如incron,它是一個類似於cron的守護進程(daemon),傳統的cron守護進程都是在規定的某個時間段內執行,而incron由於使用了Inotify,可以由事件觸發執行。同時incron的安裝簡單而直觀,比如在debian上,首先在/etc/incron.allow中添加使用incron的用戶(debian默認不允許用戶使用incron,因爲如果incron使用不慎的話,例如形成死循環,則會導致系統宕機):
# echo username > /etc/incron.allow
然後調用”incrontab -e“, 在彈出的編輯器中插入我們自己的規則,例如下面的這條簡單的規則,文件一變化incron就會發郵件通知我們:
/srv/test/ IN_CLOSE_WRITE mail -s "$@/$#\n" root
從現在開始,一旦/src/test文件夾中的文件被修改,就會發送一封郵件。但是注意不要讓incron監控整個子目錄樹,因爲Inotify只關注inodes,而不在乎是文件還是文件夾,所以基於Inotify的軟件都需要自己來處理/預防遞歸問題。關於incontab詳細使用,請參考incrontab的manpage。
如果你還要處理incoming文件夾,那麼你可能需要inoticoming。當有文件進入incoming文件夾時Inoticoming就會執行某些動作,從而可以用inoticoming來管理debian的軟件倉庫(例如軟件倉庫中一旦有上傳源碼包或是新添加的二進制包就立刻自動進行編譯),另外,還可以用它來監控系統是否有新上傳文件,如果有就發送通知。類似的工具還有(它們都各有專長):inosync(基於消息通知機制的文件夾同步服務),iwatch(基於Inotify的程序,對文件系統進行實時監控),以及lsyncd(一個守護進程(daemon),使用rsync同步本地文件夾)。
Inotify甚至對傳統的Unix工具也進行了改進,例如tail。使用inotail,同時加上-f選項,就可以取代每秒輪詢文件的做法。此外,GNU 的coreutils從版本7.5開始也支持Inotify了,我們可以運行下面的命令來確認:
# strace -e inotify_init,inotify_add_watch tail -f ~log/syslog
[...]
inotify_init() = 4
inotify_add_watch(4, "/var/log/syslog", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1
從現在開始,通過輪詢來確實文件是否需要重新讀取的方法應該作爲古董了。
在腳本中使用Inotify
Inotify機制並不侷限於工具,在腳本語言中也完全可以享受Inotify的樂趣,如Python中可以使用pyinotify和inotifyx,Perl中有Filesys-Notify-Simple和Linux-Inotify2,Inotify的Ruby版有ruby-inotifyrb-inoty和fssm。
總結
綜上所述,Inotify爲Linux提供了一套高效監控和跟蹤文件變化的機制,它可以實時地處理、調試以及監控文件變化,而輪詢是一種延遲機制。對於系統管理員,關於實現事件驅動的服務如系統備份,構建服務以及基於文件操作的程序調試等,Inotify無疑提供了強大的支持。
查看英文原文:Inotify: Efficient, Real-Time Linux File System Event Monitoring
inotify + rsync
作爲系統運維人員,在工作中大多會遇到集羣服務器的維護,在規模不大的時候,採用手動部署逐臺更新項目配置,可能會應付的了不會出問題,可是一旦業務擴增服務器的規模擴大一個級別,則手動逐臺更改配置文件則效率開始變的地下和容易產生錯誤。
實際示例:
#cat inotify.sh
#!/bin/sh
src=/usr/local/nginx/conf/
des=inotifyhome
ip="172.16.1.2 172.16.1.4 172.16.1.5"
user=sysman
/usr/local/bin/inotifywait -mrq -e modify,delete,create,attrib $src | while read file
do
for i in $ip
do
rsync -vzrtopgl --delete --progress --files-from=file.list --password-file=/etc/rsyncd.pwd $src
done
done
運行腳本
[root@localhost]# inotify.sh &