iGuard和NFS文件同步的解决方案
一般来说,从文件系统中获得文件变化信息,调用操作系统提供的 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 文件系统中,inode 和 dentry 是两个重要的数据结构 。前者对应于磁盘文件的元数据 (类型、尺寸、权限等,但不包括文件路径) 和文件数据块索引,每个 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
- Filesystem notification series by Michael Kerrisk
- Making Filesystems Exportable
iGuard和NFS文件同步的解决方案的更多相关文章
- php中并发读写文件冲突的解决方案(文件锁应用示例)
PHP(外文名: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,入门门槛较低,易于学习,使用广泛,主要适 ...
- Sersync实现触发式文件同步 替代inotify和rsync
Sersync实现触发式文件同步 替代inotify和rsync Pyinotify是一个Python模块,用来监测文件系统的变化. Pyinotify依赖于Linux内核的功能—inotify(内核 ...
- 挑战以Dropbox为代表的传统“同步网盘”,Seafile推出“分布式文件同步技术”打造的私有云服务
挑战以Dropbox为代表的传统“同步网盘”,Seafile推出“分布式文件同步技术”打造的私有云服务#36氪开放日# 其他 JasonZheng • 2012-04-07 15:14 来自36氪开放 ...
- Seafile 推出 “分布式文件同步技术” 打造的私有云服务
近两年来 Dropbox 等云储存服务迅速窜红,各大巨头纷纷推出自家的云储存服务(苹果的 iCloud, 微软的 SkyDrive, Google 即将推出的 GDrive),国内也有类似的服务(金山 ...
- rsync+sersync+inotify实现服务器间文件同步之一
rsync+sersync+inotify实现服务器间文件同步之一:rsync安装配置 2013年12月14日 ⁄ Linux管理, 服务器集群技术 ⁄ 共 4925字 ⁄ rsync+sersync ...
- 负载均衡配置下的不同服务器【Linux】文件同步问题
负载均衡配置下的不同服务器[Linux]文件同步问题2017年04月13日 22:04:28 守望dfdfdf 阅读数:2468 标签: linux负载均衡服务器 更多个人分类: 工作 问题编辑版权声 ...
- 公司和家里代码文件同步方案: (git和dropbox实现)
公司和家里代码文件同步方案: (git和dropbox实现) 参与公司福利购入了有补贴的macbook pro后, 就不用上下班背着电脑了. 但是也出现了另外一问题: 家里和公司代码同步的问题 公司有 ...
- java大文件上传解决方案
最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...
- rsync nfs 实时同步,结合实战
目录 rsync nfs 实时同步,实战 一.部署rsync服务端(backup) 二.部署rsync客户端(nfs,web01) 三.部署web代码(web01) 四.NFS服务端部署(nfs) 五 ...
随机推荐
- 【排序+模拟】谁拿了最多奖学金 luogu-1051
题目描述 某校的惯例是在每学期的期末考试之后发放奖学金.发放的奖学金共有五种,获取的条件各自不同: 院士奖学金,每人$ 8000 $元,期末平均成绩高于\(80\)分(\(>80\)),并且在本 ...
- 利用C++11可变模板,封装调用dll导出函数
起因 开发中经常需要动态调用一些导出函数,试着利用C++11特性封装一下 尝试 常规使用 typedef int WINAPI (*TMessageBoxA)(HWND hWnd,LPCSTR lpT ...
- 深入刨析tomcat 之---第14篇 对应19章,使用manager管理 web应用
writedby 张艳涛 第19章讲的是管理程序,当一个tomcat启动的时候,能通过远程浏览器能访问tomcat,启动web应用,关闭web应用,查看web应用 怎么实现的呢? 在webapp 文件 ...
- intouch制作历史趋势公用弹窗
在先前项目中,历史趋势都是作为一个总体的画面,然后添加下拉菜单选择来配合使用.在新项目中,业主要求在相应的仪表上直接添加历史趋势,这就需要利用公用弹窗来制作历史趋势了. 1.窗体建立 窗体建立是比较简 ...
- java时间工具类型,格式化时间,最近7天 月初 月末 季度 月度 时间格式化 等等
package com.tz.util; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util. ...
- Spring Cloud分区发布实践(4) FeignClient
上面看到直接通过网关访问微服务是可以实现按区域调用的, 那么微服务之间调用是否也能按区域划分哪? 下面我们使用FeignClient来调用微服务, 就可以配合LoadBalancer实现按区域调用. ...
- Qt学习-ListView的拖拽
最近在学习Qt 里面的QML, 使用DropArea和MouseArea实现了ListView的拖拽. 想起了当年用Delphi, 差不多一样的东西, 不过那是2000了. Delphi也是不争气啊, ...
- ASP.NET Core下FreeSql的仓储事务
ASP.NET Core下FreeSql的仓储事务 第一步:配置 Startup.cs 注入 引入包 dotnet add package FreeSql dotnet add package Fre ...
- 我把阿里、腾讯、字节跳动、美团等Android性能优化实战整合成了一个PDF文档
安卓开发大军浩浩荡荡,经过近十年的发展,Android技术优化日异月新,如今Android 11.0 已经发布,Android系统性能也已经非常流畅,可以在体验上完全媲美iOS. 但是,到了各大厂商手 ...
- markdown的摘要测试
123456789 1 123456789 2 123456789 3 123456789 4 123456789 5 123456789 6 粗体 123456 划线 123456 斜体 12345 ...