天天看點

Linux檔案實時同步--inotify + rsync + pyinotify

   本文介紹下用法、注意事項、pyinotify多程序實作資料同步

   Inotify的出身:

   Linux 桌面系統與 MAC 或 Windows 相比有許多不如人意的地方,為了改善這種狀況,開源社群提出使用者态需要核心提供一些機制,以便使用者态能夠及時地得知核心或底層硬體裝置發生了什麼進而能夠更好地管理裝置,給使用者提供更好的服務。inotify 是一種檔案系統的變化通知機制,如檔案增加、删除等事件可以立刻讓使用者态得知,該機制是著名的桌面搜尋引擎項目 beagle 引入的,并在 Gamin 等項目中被應用。

   Inotify優點:

   之前的一種機制:dnotify有很多缺陷,被監視的目錄都會導緻過多的檔案描述符,對于移動儲存設備無法umount;監控對象基于目錄,對于檔案的變化需要緩存更多的stat結構資料。實作接口使用signal不是很友好;

   1、Inotify 不需要對被監視的目标打開檔案描述符,而且如果被監視目标在可移動媒體上,那麼在 umount 該媒體上的檔案系統後,被監視目标對應的 watch 将被自動删除,并且會産生一個 umount 事件。

   2、Inotify 既可以監視檔案,也可以監視目錄

   3、Inotify 使用系統調用而非 SIGIO 來通知檔案系統事件。

   4、Inotify 使用檔案描述符作為接口,因而可以使用通常的檔案 I/O 操作select 和 poll 來監視檔案系統的變化。

   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)

   檢視核心是否支援inotify機制

   grep INOTIFY_USER /boot/config-$(uname -r)

   輸出:CONFIG_INOTIFY_USER=y 表示支援inotify機制

   安裝部分:<code>yum install inotify-tools (版本為3.13)</code>

   inotify-tools包含兩個工具inotifywait(監測事件的發生);inotifywatch(事件變化統計)

   使用方法:

   可以通過man 解決:man inotifywait;man inotifywatch;man inotify

   相關參數設定:

/proc/sys/fs/inotify/max_queued_events 被監測對象的隊列最大數(對于較多檔案的情況,适當增大)  

  /proc/sys/fs/inotify/max_user_instances 被監測對象最大數,預設為8192

   官方簡單腳本舉例:

   該腳本簡單的精妙,但也存在不少不足;

   1、腳本執行為單程序,對于含有多個檔案的情況需要考慮并發執行

   2、wait會産生很多備援事件;比如對于在檔案中寫資料,打開檔案都會産生臨時檔案a`或者a.swp  a.swpx 檔案,讓rsync産生更多的備援計算;

   3、錯誤處理機制,腳本出現錯誤的處理的問題,比如rsync 連接配接失敗,是否隔一段時間重連等?

   但為了友善,個人使用了pyinotify 子產品實作以上功能:

   代碼示例為:

   稍後填充!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

<code>#!/usr/bin/env python</code>

<code>#encoding=utf8</code>

<code>import</code> <code>os</code>

<code>import</code> <code>subprocess</code>

<code>import</code> <code>time</code>

<code>import</code> <code>sys</code>

<code>from</code>  <code>pyinotify </code><code>import</code>  <code>WatchManager, Notifier,ProcessEvent,IN_DELETE, IN_CREATE,IN_MODIFY</code>

<code>class</code> <code>rsync_file_cmd():</code>

<code>    </code><code>def</code> <code>__init__(</code><code>self</code><code>,src_file,dst,dst_file):</code>

<code>        </code><code>self</code><code>.src_file</code><code>=</code><code>src_file</code>

<code>        </code><code>self</code><code>.dst</code><code>=</code><code>dst</code>

<code>        </code><code>self</code><code>.dst_file</code><code>=</code><code>dst_file</code>

<code>        </code><code>self</code><code>.cmd</code><code>=</code><code>'rsync -arz --timeout=60 -e "ssh -p 22" %s %s:%s'</code> <code>%</code><code>(</code><code>self</code><code>.src_file,</code><code>self</code><code>.dst,</code><code>self</code><code>.dst_file)</code>

<code>        </code><code>self</code><code>.del_cmd</code><code>=</code><code>'ssh -p 22  %s "rm -rf %s"'</code> <code>%</code> <code>(</code><code>self</code><code>.dst,</code><code>self</code><code>.dst_file)</code>

<code>class</code> <code>EventHandler(ProcessEvent):</code>

<code>    </code><code>"""Handle"""</code>

<code>    </code><code>def</code> <code>process_IN_CREATE(</code><code>self</code><code>, event):</code>

<code>        </code><code>if</code> <code>event.name.startswith(</code><code>'.'</code><code>) </code><code>or</code> <code>event.name.endswith(</code><code>'~'</code><code>) </code><code>or</code> <code>event.name</code><code>=</code><code>=</code><code>'4913'</code><code>:</code>

<code>            </code><code>pass</code>

<code>        </code><code>else</code><code>:</code>

<code>            </code><code>create_sync</code><code>=</code><code>rsync_file_cmd(</code><code>str</code><code>(event.pathname),</code><code>'[email protected]'</code><code>,</code><code>str</code><code>(event.pathname))</code>

<code>            </code><code>subprocess.call(create_sync.cmd,shell</code><code>=</code><code>True</code><code>)</code>

<code>    </code><code>def</code> <code>process_IN_DELETE(</code><code>self</code><code>, event):</code>

<code>            </code><code>delete_sync</code><code>=</code><code>rsync_file_cmd(</code><code>str</code><code>(event.pathname),</code><code>'[email protected]'</code><code>,</code><code>str</code><code>(event.pathname))</code>

<code>            </code><code>subprocess.call(delete_sync.del_cmd,shell</code><code>=</code><code>True</code><code>)</code>

<code>    </code><code>def</code> <code>process_IN_MODIFY(</code><code>self</code><code>, event):</code>

<code>            </code><code>modify_sync</code><code>=</code><code>rsync_file_cmd(</code><code>str</code><code>(event.pathname),</code><code>'[email protected]'</code><code>,</code><code>str</code><code>(event.pathname))</code>

<code>            </code><code>subprocess.call(modify_sync.cmd,shell</code><code>=</code><code>True</code><code>)</code>

<code>def</code> <code>FSMonitor(path</code><code>=</code><code>'/root/wpf'</code><code>):</code>

<code>        </code><code>wm </code><code>=</code> <code>WatchManager()</code>

<code>        </code><code>mask </code><code>=</code> <code>IN_DELETE | IN_MODIFY | IN_CREATE</code>

<code>        </code><code>notifier </code><code>=</code> <code>Notifier(wm, EventHandler(),read_freq</code><code>=</code><code>10</code><code>)</code>

<code>        </code><code>notifier.coalesce_events()</code>

<code>        </code><code># 設定受監視的事件,這裡隻監視檔案建立事件,(rec=True, auto_add=True)為遞歸處理</code>

<code>        </code><code>wm.add_watch(path,mask,rec</code><code>=</code><code>True</code><code>, auto_add</code><code>=</code><code>True</code><code>)</code>

<code>        </code><code>notifier.loop()</code>

<code>if</code> <code>__name__</code><code>=</code><code>=</code><code>'__main__'</code><code>:</code>

<code>    </code><code>try</code><code>:</code>

<code>        </code><code>pid </code><code>=</code> <code>os.fork()</code>

<code>        </code><code>if</code> <code>pid &gt; </code><code>0</code><code>:</code>

<code>            </code><code>sys.exit(</code><code>0</code><code>)</code>

<code>    </code><code>except</code> <code>OSError, e:</code>

<code>        </code><code>print</code> <code>&gt;&gt;sys.stderr, </code><code>'fork failed: %d (%s)'</code> <code>%</code> <code>(e.errno, e.strerror)</code>

<code>        </code><code>sys.exit(</code><code>1</code><code>)</code>

<code>    </code><code>os.setsid()</code>

<code>    </code><code>os.umask(</code><code>0</code><code>)</code>

<code>    </code><code>FSMonitor()</code>

<code>    </code><code>print</code> <code>'start!'</code>

本文轉自 位鵬飛 51CTO部落格,原文連結:http://blog.51cto.com/weipengfei/1195019,如需轉載請自行聯系原作者

繼續閱讀