前言
这里源站的基本架构为:2台ftp服务器(主+备),多台源站服务器。用户通过ftp或者rsync将数据上传到ftp服务器(正常情况下是“主”),ftp服务器将数据实时地同步给源站服务器。
大家都知道,常用的数据拷贝工具主要有scp和rsync两种,在数据量不大的情况下, scp和rsync没有明显的区别,性能上差不多。但是当执行大数据量两拷贝的时候, rsync有明显优势,因为rsync有增量传输功能,而scp只能老老实实地全量拷贝。
虽然rsync可以实现增量传输,但是避免不了要对文件进行扫描,查看文件的元数据(主要是size、mtime)。要避免文件的全量对比,需要有文件变化通知机制(类似于网络编程里面的epoll事件通知), 这样只需要对变化的文件(或目录)进行rsync传输, 从而减少大量不必要的文件扫描。
幸运的是,文件系统确有类似的通知机制,目前主要有dnotify、inotify、fanotify三种。dnotify已经过时,fanotify尚不成熟,而inotify是目前主流(具体对比可以baidu、google)。所以数据同步这里最终选择inotify+rsync这对黄金搭档。
数据同步工具V1.0:
inotify有很多版本的接口封装,典型的是原生的C接口,以及在其上包装的其他语言接口(golang、python等等)。考虑到性能, 一开始理所当然选择了原生的C接口,对其进行封装。
同步工具分成两个模块,文件列表生成模块(后面简称为生成模块)、文件列表拉取模块(后面简称为拉取模块)。生成模块部署在ftp服务器上面,使用inotify递归监听数据根目录的变化,生成变化(创建、删除、修改等)的目录列表,并将变化的目录列表去重后写入以分钟为粒度的文件(后面简称为列表文件)。拉取模块部署在各个源站机器上面,定期拉取列表文件,然后将列表文件通过rsync同步到源站本地。
inotify编程和epoll编程有几分类似:
初始化:inotify_init,类似于epoll的epoll_create
事件添加:inotify_add_watch,类似于epoll的epoll_ctl(EPOLL_CTL_ADD)
事件删除:inotify_rm_watch, 类似于epoll的epoll_ctl(EPOLL_CTL_DEL)
事件获取:read,类似于epoll的epoll_wait
该版本跑了一段时间,基本能满足需求。但是有2个问题:
1. 生成模块每次修改(优化或者改bug)都需要重编,而且C接口编程要非常小心,要避免出现内存越界、内存泄露之类的麻烦。
2. 同步性能不佳,同步实时性较差。该问题出现的原因,是因为每次同步的都是目录列表, 当目录里面有大量文件的时候,扫描代价是高昂的。虽然可以通过修改生成模块使其生成具体的文件列表来解决,但是C代码操作起来相对麻烦,希望寻找一种更为简单的方式。
数据同步工具V2.0:
尽量使用现有成熟的开源工具,搜索了解到有一些常用的同步工具:sersync, lsyncd等。虽然看起来都还不错,但是要么配置复杂,要么不够灵活,最终都放弃使用。要想灵活,rsync还得剥离出来,剩下的问题在于, 如何方便的使用inotify通知服务。
幸好有封装好的inotify-tools可以用,最终工具定型为inotify-tools + rsync组合. inotify-tools有2个工具:inotifywait和inotifywatch, 我们这里只需要使用inotifywait即可。
核心同步逻辑 (接近真实的伪代码):
dataroot=/data/home
inotifywait -mr --timefmt '%y-%m-%d.%H:%M:%S' --format '%T %e%w %f