传统的文件同步方案有rsync(单向) 和 unison(双向)等,它们需要扫描所有文件后进行比对,差量传输。如果文件数量达到了百万甚至千万量级,扫描所有文件将非常耗时。而且正在发生变化的往往是其中很少的一部分,这是非常低效的方式。
之前看了Amazon的Dynamo的设计文档,它们每个节点的数据是通过Hash Tree来实现同步,既有通过日志来同步的软实时特点(msyql, bdb等),也可以保证最终数据的一致性(rsync, unison等)。Hash Tree的大体思路是将所有数据存储成树状结构,每个节点的Hash是其所有子节点的Hash的Hash,叶子节点的Hash是其内容的Hash。这样一旦某个节点发生变化,其Hash的变化会迅速传播到根节点。需要同步的系统只需要不断查询跟节点的hash,一旦有变化,顺着树状结构就能够在logN级别的时间找到发生变化的内容,马上同步。
文件系统天然的是树状结构,尽管不是平衡的数。如果文件的修改时间是可靠的,可以表征文件的变化,那就可以用它作为文件的Hash值。另一方面,文件的修改通常是按顺序执行的,后修改的文件比早修改的文件具有更大的修改时间,这样就可以把一个目录内的最大修改时间作为它的修改时间,以实现Hash Tree。这样,一旦某个文件被修改,修改时间的信息就会迅速传播到根目录。
一般的文件系统都不是这样做的,目录的修改时间表示的是目录结构最后发生变化的时间,不包括子目录,否则会不堪重负。因为我们需要自己实现这个功能,利用Linux 2.6内核的新特性inotify获得某个目录内文件发生变化的信息,并把其修改时间传播到它的上级目录(以及再上级目录)。Python 有 pyinotify,watch.py的代码如下:
复制代码代码如下:
#!/usr/bin/python
from pyinotify import *
import os, os.path
flags = IN_CLOSE_WRITE|IN_CREATE|IN_Q_OVERFLOW
dirs = {}
base = '/log/lighttpd/cache/images/icon/u241'
base = 'tmp'
class UpdateParentDir(ProcessEvent):
def process_IN_CLOSE_WRITE(self, event):
print 'modify', event.pathname
mtime = os.path.getmtime(event.pathname)
p = event.path
while p.startswith(base):
m = os.path.getmtime(p)
if m < mtime:
print 'update', p
os.utime(p, (mtime,mtime))
elif m > mtime:
mtime = m
p = os.path.dirname(p)
process_IN_MODIFY = process_IN_CLOSE_WRITE
def process_IN_Q_OVERFLOW(self, event):
print 'over flow'
max_queued_events.value *= 2
def process_default(self, event):
pass
wm = WatchManager()
notifier = Notifier(wm, UpdateParentDir())
dirs.update(wm.add_watch(base, flags, rec=True, auto_add=True))
notifier.loop()
在已经有Hash Tree的时候,同步就比较简单了,不停地获取根目录的修改时间并顺着目录结构往下找即可。需要注意的是,在更新完文件后,需要设置修改时间为原文件的修改时间,目录也是,保证Hash Tree的一致性,否则没法同步。mirror.py的代码如下
复制代码代码如下:
#!/usr/bin/python
import sys,time,re,urllib
import os,os.path
from os.path import exists, isdir, getmtime
src = sys.argv[1]
dst = sys.argv[2]
def local_mirror(src, dst):
if exists(dst) and mtime == getmtime(dst):
return
if not isdir(src):
print 'update:', dst
open(dst,'wb').write(open(src).read())
else:
if not exists(dst):
os.makedirs(dst)
for filename in os.listdir(src):
local_mirror(os.path.join(src,filename), os.path.join(dst,filename))
os.utime(dst, (mtime,mtime))
def get_info(path):
f = urllib.urlopen(path)
mtime = f.headers.get('Last-Modified')
if mtime:
mtime = time.mktime(time.strptime(mtime, '%a, %d %b %Y %H:%M:%S %Z'))
content = f.read()
f.close()
return int(mtime), content
p = re.compile(r'([\d.]+?) +([\w/]+)')
def remote_mirror(src, dst):
mtime, content = get_info(src)
if exists(dst) and mtime == int(getmtime(dst)):
return
print 'update:', dst, src
if not src.endswith('/'):
open(dst,'wb').write(content)
else:
if not exists(dst):
os.makedirs(dst)
for mt,filename in p.findall(content):
mt = int(float(mt))
lpath = dst+filename
if not exists(lpath) or int(getmtime(lpath)) != mt:
remote_mirror(src+filename, lpath)
os.utime(dst, (mtime,mtime))
if src.startswith('http://'):
mirror = remote_mirror
else:
mirror = local_mirror
while True:
mirror(src, dst)
time.sleep(1)
如果源文件不在同一台机器上,可以通过NFS等共享过来。或者可以通过支持列目录的HTTP服务器来访问远程目录,mirror.py 已经支持这种访问方式。server.py 是用webpy做的一个简单的只是列目录的文件服务器。由于瓶颈在IO上,它的性能不是关键。server.py的代码如下:
复制代码代码如下:
#!/usr/bin/python
import os,os.path
import web
import time
root = 'tmp'
HTTP_HEADER_TIME = '%a, %d %b %Y %H:%M:%S %Z'
class FileServer:
def GET(self, path):
path = root + path
if not os.path.exists(path):
return 404
mtime = time.localtime(os.path.getmtime(path))
web.header('Last-Modified', time.strftime(HTTP_HEADER_TIME, mtime))
if os.path.isdir(path):
for file in os.listdir(path):
if file.startswith('.'): continue
p = os.path.join(path,file)
m = os.path.getmtime(p)
if os.path.isdir(p):
file += '/'
print m, file
else:
print open(path,'rb').read()
urls = (
"(/.*)", "FileServer",
)
if __name__ == '__main__':
web.run(urls, globals())
为了获得更好性能,以达到更好的实时性,Hash Tree最好是平衡的,比如BTree。如果一个文件发生变化,同步它需要进行的IO操作为N*M,其中N为数的层数,M为每层的文件数目。现在我们N为2,M最大为10000,适当减少它可以获得更好的性能,比如N为4,M为100。在以后创建目录结构时,最好能够考虑这方面的因素。
之前hongqn推荐过一个利用inotify的文件同步方案,同步方式类似于mysql和bdb等,由于过于复杂导致不可靠而没有采用。上面这个方案只用了一百多行Python代码就基本解决问题了,是不是很帅?:-)
详细出处参考:http://www.jb51.net/softjc/10123.html
分享到:
相关推荐
"hashtree的小文件同步方案"提供了一种高效且可靠的解决方案,通过利用哈希树(Hash Tree)的数据结构来跟踪和同步文件的变化。这篇博文由作者willvvv在iteye博客上分享,虽然描述部分为空,但我们可以根据标题和...
2. 考虑网络状况,避免在带宽有限的环境中进行大量文件同步。 3. 对于敏感数据,使用加密的SSH连接以保护数据安全。 4. 定期检查同步日志,确保同步过程无误。 总之,通过Unison、inotify-tools、SSH和其他相关工具...
本项目"用C#实现的文件同步软件"聚焦于这个需求,旨在提供一种高效、可靠的文件传输解决方案。C#作为.NET框架的主要编程语言,具有丰富的类库和强大的跨平台能力,使得它成为开发此类应用的理想选择。 首先,我们要...
数据库同步热备解决方案是保障数据安全和业务连续性的重要手段,尤其在政府机构等关键领域,数据的安全性和可用性更是至关重要。本方案针对某区政府的需求,旨在提供一套完整的数据库同步和热备份策略,确保在主...
"多线程的批量线程同步解决方案"这个标题暗示我们探讨的是如何在多线程环境下有效地管理和同步多个任务,确保数据一致性与程序正确性。下面将详细阐述相关知识点。 一、多线程基础 多线程是指在一个进程中同时执行...
综上所述,这个开源文件同步工具提供了一种跨平台、高效率的解决方案,适用于网站备份、多服务器环境的数据一致性维护,以及在Windows和Linux系统间的数据迁移。其内置的rsync特性,结合开源社区的支持,使其在性能...
总的来说,这个基于 Electron & Vue.js 的文件同步客户端是现代开发技术与实用功能的结合,为用户提供了一种高效、安全的文件管理和同步解决方案。通过利用这两个强大框架的优势,开发者可以快速构建出具有专业级...
rsync+inotify 是一种高效的实时文件同步解决方案,尤其适用于需要确保数据安全性和可靠性的大型应用系统。rsync 是一个强大的文件同步工具,而 inotify 是 Linux 内核提供的一种文件系统事件监控机制。它们结合使用...
个人文件同步备份系统的应用广泛,无论是日常办公、学习还是创作,都可以提供高效的数据管理解决方案。尤其对于那些依赖大量文件的专业人士,如设计师、程序员、作家等,这样的系统更是不可或缺。 总的来说,个人...
这种方法虽然简单,但在处理大量文件时可能会效率低下,因为每次同步都需要检查所有文件。 第二个解决方案,"FileSystemSyncher2",可能在前一个基础上进行了优化。它可能引入了更高级的同步算法,例如哈希检查,...
2. **文件同步**:文件的更新和修改会自动同步到集群中的其他节点,确保所有副本的一致性。这种实时同步机制使得在多台服务器之间保持文件的最新状态变得简单。 3. **文件上传**:FastDFS提供了一套简单易用的API...
通过上述分析,我们可以看到这个基于SWT的文件同步程序涵盖了文件系统操作、同步算法、用户界面设计等多个方面的技术知识,对于开发人员来说,这些都是构建高效、可靠的文件同步解决方案所需掌握的关键技能。
FTP文件同步服务是一种基于FTP(File Transfer Protocol)协议的解决方案,用于在本地计算机与远程服务器之间自动保持文件和文件夹的同步。FTP是互联网上广泛使用的标准协议之一,主要用于在不同系统之间交换文件。...
在IT领域,文件同步下载程序是一个常见的需求,特别是在分布式系统、多设备协同工作或云存储服务中。...通过这个示例,开发者可以了解到文件同步的基本原理和技术实现,为构建自己的同步解决方案打下基础。
【自同步局域网免费文件同步工具】是一种实用的解决方案,尤其对于那些在同一个局域网环境下工作的用户。它能够实现在多台计算机之间自动、实时地同步指定文件夹的内容,确保所有设备上的文件数量和内容保持一致。...
总的来说,文件分析工具Besnew是一款全面的文件管理解决方案,它集文件分析、搜索、管理、备份等功能于一体,旨在帮助用户更有效地管理和优化他们的文件系统。无论是在日常办公还是在企业环境中,这款工具都能提供...
"eclipse,Myeclipse修改js文件同步插件"就是为了解决这个问题而存在的,它允许开发者在不重启项目的情况下即时查看和测试JavaScript文件的修改效果。这个插件适用于Eclipse和MyEclipse集成开发环境(IDE),极大地...
FTP自动文件同步软件...总之,FTP自动文件同步软件FileGee是企业级文件管理和保护的理想工具,它提供了一套全面的解决方案,确保文件的实时更新和安全备份,对于提升企业数据管理效率和防范数据损失具有重要意义。