目标:监控linux文件系统指定目录内的文件变化,并记录或提交到相应的接口。
该指定目录用于存储客户提交的文件。
提交方式可能是 ftp 或者 mount
方式一:
使用inotify机制。
相关的开发工具可以使用 inotify-tools,或者在其基础上进行再封装。
优点:开放方便,维护简单,运行稳定。
弱点:
1.事后获知,对于unlink event,无法获知被删除文件的信息,如:想知道删除的文件是否是softlink
2.海量文件或者目录的情况下,维护inode_list需要大量的内存空间,同时,在程序启动加载inode信息时耗时巨大。
方式二:
使用FUSE——file system user space。
可以参考http://www.ibm.com/developerworks/cn/linux/l-fuse/ 有一个简要介绍
实现自己的文件系统
注册自定义的文件操作方法:
InoteFS_oper.readlink = InoteFS_readlink;
InoteFS_oper.readdir = InoteFS_readdir;
InoteFS_oper.mknod = InoteFS_mknod;
InoteFS_oper.mkdir = InoteFS_mkdir;
InoteFS_oper.symlink = InoteFS_symlink;
实现对应方法,摘自本人的一个实现:
static int InoteFS_rmdir(const char *path)
{
int res;
char *aPath = getAbsolutePath(path);
path = getRelativePath(path);
res = rmdir(path);
InoteFS_log(aPath, "rmdir", res,"rmdir %s", aPath);
return res == -1 ? -errno : 0;
}
可以看到,
1,只是简单的执行系统动作rm
res = rmdir(path);
2,在rm动作前后均可以进行拦截和处理,上例仅在删除后拦截事件并记录日志
InoteFS_log(aPath, "rmdir", res,"rmdir %s", aPath);
此方式优点:灵活,高效,开发不算复杂,自由度很高,特别是解决了inotify 方式的 内存占用和启动准备时间上的弊病。
应用场景多样,特别是在某些大量依托文件系统的事务中,可以通过自定义的文件系统将底层逻辑做一个透明遮断,如:文件镜像/远程同步等。
方式三:
使用 strace ltrace 等系统工具。
这些工具可以监控进程的 system call 等。
因此,若用户使用ftp上传,可以监控 ftp server 的pid, 获得 ftp 的 system call
例如 unlink("xxxxxxxxxxxxxxxxxxx" ...)
由此,即可获得文件变动信息。
此方式无法处理mount 写文件的情况, 但是在某些快速开发场合可以使用, stick 一个pid的成本也相当低。
方式四:
切入内核,拦截system call。
优点当然是极致性能
不过对于开发技巧以及确保系统的稳定性上要求也很高。
具体开发可以参考github的部分开源项目。
如果选择此方式,可以使用一个折衷的开发方法,避免侵入内核代码,产生不可控的错误——
使用linux的 LD_PRELOAD 参数,通过chroot等方式, 自己替换掉底层模块 如 glibc 的 read unlink 等, 并进行拦截。