Linux事件监控机制遗漏事件问题的相关分析

运维 系统运维
Epoll+iNotify结合的机制可以用来监控Linux下文件系统的变化,不过在过于频繁的往目录下添加文件和目录的时候,会丢事件。本文对如何解决漏事件的问题进行了探讨,提供了两种解决方案的思路。

目前比较通用的监控Linux下文件系统变化的是Epoll+iNotify结合的机制.

Epoll有两种机制,LevelTrigger和EdgeTrigger, 前者相当于fast poll, 后者可以理解为对nonblocking fd的阻塞化, 这个说法严格来讲有点儿业余,只是为了简单的说明问题.

对于从epoll_wait等待事件触发,然后进行read.这里做下说明,在读事件的时候, Linux下的epoll是异步读,而Windows下的IOCP是同步读,从后面的分析可以发现,同步读似乎更有优势.

开始的时候,对于wait事件发生并进行read的线程,并没有提高其优先级,发现在过于频繁的往目录下添加文件和目录的时候,会丢事件.这样在做实时同步时,要想办法弥补丢失的事件.

第一个方案是对新添加的目录,先把目录add_watch,然后把该目录扫描一遍.add_watch只是为了确保新建目录被加入watch,一般不会漏掉的,除非是在事件被漏掉的情况下.漏掉指的是在目录新建并上报到加入watch前的这段时间,在该目录下又发生了新建文件或目录时,会漏事件. iNotify是允许对同一个目录add_watch两遍的,但是由于add时还要访问硬盘,确保目录存在才能添加,所以做了一个缓存,path<--->wd,通过path的查找确定是否已add_watch,若没add再add下.

第一个方案里漏事件的问题通过事后扫描得到解决,但是再扫描一遍是否有意义呢? 分析了Linux的线程有限级和调度策略之后,发现实时优先级有两种SCHED_FIFO和SCHED_RR.从Linux kernel development里chapter4 RealTime看到:

“SCHED_RR is identical to SCHED_FIFO except that each process can run only until it exhausts a predetermined timeslice. That is, SCHED_RR is SCHED_FIFO with timeslicesit is a real-time round-robin scheduling algorithm. When a SCHED_RR task exhausts its timeslice, any other real-time processes at its priority are scheduled round robin. The timeslice is used only to allow rescheduling of same-priority processes.”

这也就是说,若是把读事件的线程设置为FIFO,则没有timeslice的限制,可以直到读完事件,并且不会被抢占;而用RR则在timeslice用完一个之后,就会调度到别的线程,觉得可以用FIFO的设置来替代低效的扫描。

注1:

设置线程策略可以用下面的api:

  1. pthread_attr_getschedpolicy(const pthread_attr_t *restrict attr, int *restrict policy);  
  2. pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy );  
  3.  

设置线程优先级可以用下面的api:

  1. int sched_get_priority_max(int policy);  
  2. int sched_get_priority_min(int policy);  
  3. int pthread_attr_getschedparam(const pthread_attr_t *restrict attr,  
  4.               struct sched_param *restrict param);  
  5. int pthread_attr_setschedparam(pthread_attr_t *restrict attr,  
  6.               const struct sched_param *restrict param);  
  7.  struct sched_param sched;  
  8.  sched.sched_priority = sched_get_priority_max(SCHED_FIFO);  
  9.  pthread_attr_setschedparam( attr, &sched );  
  10.  

第二个方案的产生是因为在实现了第一个方案之后,发现多CPU或多core的情况下,仍然有漏报事件发生,而且漏报无规律可循,文件或目录的个数不定,.再做了多种模拟测试之后,发现在单CPU下,读事件是没有问题的,但是在多CPU下,读事件的线程是分配了core的个数个的.这时会发现读到的事件不是一般的乱,而且无规律可循.在没有任何分析的情况下,我假定inotify会对他内部的RB-Tree的读取做了同步的,所以为了效率就肆无忌惮的用多个线程去读了,结果在多U下,就给读乱了.在把读取线程改为一个后,就没有漏事件了;但是考虑到效率问题,还是要用多个线程去读的.或者可以对每个线程的read进行加锁,这样就可以保证读的时候,在iNotify的buffer里是同步的了.具体效果如何,还有待明天验证;

在这里插一句,Windows的iocp是同步读的,是先read然后再getiocpstatus的,Linux的Epoll是反过来的,是异步读取的.个人觉得可能是ms已经对异步读的方式进行了测试,最后选定了同步读的方式,这样对写应用的人来说,是要省不少心的.而且还有一点,inotify没有加迭代监控子目录的参数,而Windows却有了这种考虑,这一点也算是win在设计上考虑比较全面的地方吧.

【编辑推荐】

  1. 善用脚本 让你的Nagios记录系统监控日志(附vmstat详解)
  2. 安全实现Linux网络监控
  3. Linux监控工具的展览馆
责任编辑:yangsai 来源: chinaunix博客
相关推荐

2010-06-23 11:24:23

Linux Bash命

2023-10-08 08:23:44

Android事件逻辑

2010-07-29 10:33:59

Flex键盘事件

2016-12-08 10:19:18

Android事件分发机制

2010-08-04 13:52:53

Flex事件机制

2023-09-07 10:31:27

2010-08-12 15:35:44

Flex事件机制

2010-08-06 09:45:50

Flex事件机制

2009-12-08 16:42:48

WCF Service

2010-08-06 09:56:06

Flex事件机制

2010-08-06 10:03:42

Flex事件

2020-10-22 10:58:23

Ryuk 勒索

2023-09-14 15:15:36

2013-04-24 11:15:56

Android开发Touch事件传递机制

2010-08-04 14:07:59

Flex事件机制

2011-07-01 14:20:59

Qt 事件

2011-07-01 14:14:34

Qt 事件

2009-12-30 10:44:38

Silverlight

2009-12-31 16:38:19

Silverlight

2009-12-29 17:25:36

Silverlight
点赞
收藏

51CTO技术栈公众号