一般来说,从文件系统中获得文件变化信息,调用操作系统提供的 API 即可。Windows 操作系统上有个名为 ReadDirectoryChangesW 的 API 接口,只要监视一个目录路径就可以获得包括其子目录下的所有文件变化信息,简单高效;接口的支持度也很广,现有主流的 Windows 操作系统都支持,往前还可以追溯到 Windows 2000。对码农来说,能提供稳定有效且好用的 API 的系统就是好系统。而本文将讨论 iGuard 网页防篡改系统在 Linux 上获取文件变化信息的方法及从 NFS 网络文件系统中获取文件变化时遇到的困难和心得。

▲ReadDirectoryChangesW

在 Linux 系统上获取文件变更信息,就没有这样的好运了,想要一个像 Windows 上一样提供 ReadDirectoryChangesW 功能的 API,似乎是一种奢望。Linux 内核版本 2.4.0 (2001) 中引入了一个叫 dnotify 的目录检测机制,不怎么好用;内核 2.6.13 (2005) 引入了新方法 inotfiy,但它与 ReadDirectoryChangesW 相比还是差一大截,一次调用只能监视当前目录下的文件变更,子目录里的变更则是无法感知的。如果要获取整个目录下的所有文件变化,应用程序需要遍历整个目录,并把所有的目录监视起来。通过 inotify 接口获得一个目录创建事件时,需要把这个新建的目录及时添加到监视列表,才有可能获得新目录下的文件变化。应用程序处理变化信息较慢时,在把新建目录添加到监视列表前,新目录下的文件事件是极有可能丢失的。对于一个巨型文件系统来说,遍历出所有的目录也是件费事耗资源的任务。如此看来,inotify 机制并不完善,小规模文件数量的场景尚能胜任,像集约化平台,文件规模太庞大,就难以满足了。

▲dnotify

▲inotify

随着 Linux 系统的演化,获取文件变化信息的手段也在发展,但一直不完善,inotify 的缺陷同样表现在 NFS 系统上。NFS 系统是天存信息的用户中一种常见的应用场景,它共享海量文件。我们的 iGuard 网页防篡改系统在 NFS 上需要一种可靠的获取文件变化的手段,来保障安全业务的 7×24h 运转。鉴于 Linux 系统公开的 API 似乎不能满足我们的要求,只有另辟蹊径。幸好 Linux 是开源的,没有现成的就改一个出来。

我们的改造目标指向了 NFS 系统的服务模块 nfsd。在 Linux 内核源代码树下的文件系统 fs 目录中很容易找到 nfsd 模块的同名目录。在 Linux 系统中,NFS 服务透过虚拟文件系统 VFS 接口来访问真实的文件系统,文件的新建、改写、改名和删除等动作是非常清晰的。我们很快就把这些文件更改相关的事件传递出来并为我所用。

最初,我们的这种 nfsd 解决方案和 iGuard 网页防篡改系统看起来是可以一起工作的,在用户生产环境下可以稳定地跑上几周几个月,基本上没有问题。随着集约化平台的兴起,大量网站集中到统一的管理平台下进行内容编辑和运维,这样的单一管理平台发布文件的规模每天可达百万级别。我们的 iGuard 系统在超大规模的文件发布量下也暴露出一些问题,文件同步任务阻塞、滞后或者遗漏等;这些问题以前可能没有出现或缺少关注,随着规模变大,这些问题现今被放大了。这些问题中,最难排解的就是文件遗漏,明明磁盘文件已经更新,但系统就是没有把文件内容同步到远端。后来追查发现,在某些情况下,我们无法获得 NFS 服务所写文件对象的完整文件路径,进而无法输出对应文件的变更消息。

在 Linux 文件系统中,inodedentry 是两个重要的数据结构 。前者对应于磁盘文件的元数据 (类型、尺寸、权限等,但不包括文件路径) 和文件数据块索引,每个 inode 都有一个编号,在文件系统中是唯一的;后者是文件系统运行过程中创建的内存对象,组合成目录项高速缓存 dcache,每个 dentry 对应文件路径上的一个节点并和一个 inode 相关联,目录树由这些 dentry 组成,可以通过遍历目录树来获取文件路径,dentry 可以被视作某种缓存信息,让文件系统运行得更快更高效。

通过 NFS 对外提供文件访问的系统需要符合文件系统可导出规范,这个规范在 Linux 的内核文档 Making Filesystems Exportable 中有简要说明,其中提到 NFS 通信协议中使用文件句柄来标识文件,而不是平时所想象的按文件路径来定位文件。这个句柄信息跟符合可导出规范的文件系统相关,包含 inode 的编号、文件系统标识等信息。这里可以看出,我们需要的文件变化消息是基于文件路径,而 NFS 操作文件是基于这种文件句柄,这里就存在从文件句柄到文件路径的转译过程。

在一般情况下,这个转译过程是正常的,每一个 NFS 文件句柄都可以在 dcache 中找到对应的文件。文档 Making Filesystems Exportable 中还提到 dcache 构建中的 2 个注意事项,大致是:

  • dcache 包含的对象有时候是没有合适前缀的节点 (可以理解为孤立的),该节点没有与根节点相连。
  • 新遍历出来的节点可能是已存在于 dcache 的孤立节点,这种情况需要将孤立节点移动到合适的位置 (可以理解为孤立节点回归到大目录树下)。

这就解释了我们在 NFS 系统中遇到的问题原因——无法获取变更文件的完整路径,因为它没有和根节点相连。我们也能重现问题,在 NFS 服务和客户端工作了一段时间后,重启 NFS 服务器,当 NFS 客户端继续读写曾经访问过的文件时,由于 NFS 服务器上的 dcache 已经复位,客户端请求过来的文件句柄是合法的,并在服务器端形成一个没有合适前缀的节点,这样的节点是无法解析出完整路径的。dcache 毕竟是一个缓存系统,不可能把磁盘上的目录树全部保存到内存,当内存不够用时,dcache 会释放一部分数据并进行内存回收。

NFS 服务的这个问题看似无解,是 NFS 工作模式引发的。为了解决问题,我们尝试采用一种看似笨拙但有效的方法,创造性地构建一张持久化的超大表来跟踪所有的 NFS 文件句柄,记录它们的文件路径信息,通过这张大表转译出那些没头脑的节点。用磁盘空间来换取 NFS 文件句柄的路径检索。方法虽不完美,但我们尽力让 iGauard 网页防篡改系统运行更加完美。(徐品华 | 天存信息)

Ref

  1. Filesystem notification series by Michael Kerrisk
  2. Making Filesystems Exportable

iGuard和NFS文件同步的解决方案的更多相关文章

  1. php中并发读写文件冲突的解决方案(文件锁应用示例)

    PHP(外文名: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,入门门槛较低,易于学习,使用广泛,主要适 ...

  2. Sersync实现触发式文件同步 替代inotify和rsync

    Sersync实现触发式文件同步 替代inotify和rsync Pyinotify是一个Python模块,用来监测文件系统的变化. Pyinotify依赖于Linux内核的功能—inotify(内核 ...

  3. 挑战以Dropbox为代表的传统“同步网盘”,Seafile推出“分布式文件同步技术”打造的私有云服务

    挑战以Dropbox为代表的传统“同步网盘”,Seafile推出“分布式文件同步技术”打造的私有云服务#36氪开放日# 其他 JasonZheng • 2012-04-07 15:14 来自36氪开放 ...

  4. Seafile 推出 “分布式文件同步技术” 打造的私有云服务

    近两年来 Dropbox 等云储存服务迅速窜红,各大巨头纷纷推出自家的云储存服务(苹果的 iCloud, 微软的 SkyDrive, Google 即将推出的 GDrive),国内也有类似的服务(金山 ...

  5. rsync+sersync+inotify实现服务器间文件同步之一

    rsync+sersync+inotify实现服务器间文件同步之一:rsync安装配置 2013年12月14日 ⁄ Linux管理, 服务器集群技术 ⁄ 共 4925字 ⁄ rsync+sersync ...

  6. 负载均衡配置下的不同服务器【Linux】文件同步问题

    负载均衡配置下的不同服务器[Linux]文件同步问题2017年04月13日 22:04:28 守望dfdfdf 阅读数:2468 标签: linux负载均衡服务器 更多个人分类: 工作 问题编辑版权声 ...

  7. 公司和家里代码文件同步方案: (git和dropbox实现)

    公司和家里代码文件同步方案: (git和dropbox实现) 参与公司福利购入了有补贴的macbook pro后, 就不用上下班背着电脑了. 但是也出现了另外一问题: 家里和公司代码同步的问题 公司有 ...

  8. java大文件上传解决方案

    最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  9. rsync nfs 实时同步,结合实战

    目录 rsync nfs 实时同步,实战 一.部署rsync服务端(backup) 二.部署rsync客户端(nfs,web01) 三.部署web代码(web01) 四.NFS服务端部署(nfs) 五 ...

随机推荐

  1. Cesium加载地形数据只显示半个地球

    Cesium第0级地形包括两个瓦片:0/0/0.terrain,0/1/0.terrain,分别为左半球和右半球(具体参考:https://blog.csdn.net/u013929284/artic ...

  2. 记一次Hvv中遇到的API接口泄露而引起的一系列漏洞

    引言 最近朋友跟我一起把之前废弃的公众号做起来了,更名为鹿鸣安全团队,后面陆续会更新个人笔记,有趣的渗透经历,内网渗透相关话题等,欢迎大家关注 前言 Hvv中的一个很有趣的漏洞挖掘过程,从一个简单的A ...

  3. C++第四十五篇 -- MFC关闭调用的窗口

    调用窗体的方法: // chart是一个MFC的窗体类 chart *chartdialog = new chart; //调用窗体,获取返回值 int ReturnValue = chartdial ...

  4. Flask db init 抛出KeyError: 'migrate’这个问题

    问题 目录下执行flask db init 结果 抛出KeyError: 'migrate'这个问题 ## 原因 初始化Migrate对象时没有加db 解决: appfactory.py import ...

  5. Django中ORM是啥?

    ORM是啥是许多Django新手的苦恼. ORM中的"O"就是object,也就是我们说的对象:R指的是relations关系:M指的是mapping也就是映射.所以ORM是对象- ...

  6. Mplus 8.3 Combo Version for Win/Mac安装破解教程

    Mplus 8.3是一个统计建模程序,它为研究人员提供了一个灵活的工具来分析数据.本文提供其破解版安装包下载,亲测可永久免费使用,支持Windows 和 Mac操作系统. Mplus 8.3界面简单, ...

  7. MP4命令行处理

    MP4Box可用于生成符合MPEG-DASH规范的内容,也就是ISO / IEC 23009-1在ISO公共可用标准中可用的内容. dash切片命令: mp4box -dash 5000 -frag ...

  8. Podman 快速入门

    今天在某云上新购一台云服务器,发现已经有了 CentOS8.2 官方镜像可选,出于对新鲜事物的好奇,我决定开始采用 CentOS8.2,即使我还没有为它的新特性做好准备. 我的应用主要以单机版容器为主 ...

  9. AT指令集及其通信测试方式

    1 前言 AT即Attention,AT指令集是从终端设备(Terminal Equipment,TE)向终端适配器(Terminal Adapter, TA)发送的.通过TA,TE发送AT指令来控制 ...

  10. 自学linux——19.TFTP服务器的搭建

    TFTP服务器的搭建 1.TFTP的认识 TFTP(Trivial File Transfer Protocol)简单文件传输协议,是一种基于UDP协议在客户端和服务器之间进行简单文件传输的协议,不需 ...