当谈到Rsync时候,我们将使用一些术语来指代rsync工具在完成其任务的不同阶段 下的各个角色或者进程。下面为一些后文将会用到的术语:
client/客户端 role/角色 客户端对同步过程进行初始化。
server/服务器端 role/角色 服务器是指远端的rsync进程或者客户端通过远端shell、socket所连接到的系统。
服务器(server)是一个通用的术语,注意不要将其与Deamon混为一谈。
一旦从Client到Server的链接建立起来,Client(客户 端)/Server(服务 器)的这两个角色的差别,就被Sender(发送者)/Receiver(接收者)所 取代了。
daemon/守护进程,同时也是进程 Daemon是一个rsync进程,该进程用于等待接收从Client发起的连接。在一 些平台上,Daemon也被叫做服务(Service)
remoteshell/远端shell 角色,同时也是一系列的进程 一个或多个进程,用于向client和远端的server之间提供连通性。
sender/发送者 role and process 可以存取待同步的文件资源的rsync进程。
receiver/接收者 role and process 作为角色:指同步过程中的目标系统;作为进程:指目标系统中,用于接收数据并接数据写入磁盘的进程。
generator/生产者 process/进程 生产者进程用于识别文件的变化,并维持文件级别的逻辑。
*/
当Rsync通过一个远端SHELL和一个没有启动守护程序的服务器通讯的时候,
Rsync所使用的启动方法是在远端系统上派生一个远端SHELL,然后使用这个远端SHELL启动一个Rsync进程.
Rsync的客户机和服务器通过远端SHELL的管道进行通讯.在这种模式下, Rsync服务器选项被传送给命令行,
用于启动远端SHELL.
当Rsync和一个守护程序通讯的时候, 它直接和网络插口通讯. 这是唯一一种可以被称为涉及网络的的Rsync通讯. 在这种模式下, Rsync的选项必须发送到网络插口上. 下面是具体的描述.
开始通信:
客户机和服务器最开始通讯的时候, 他们各自发送自己所支持的最高的协议版本号给对方. 两边会使用其中的小的版本作为用来传输的协议版本.
如果是一个守护模式连接,Rsync的参数会被从客户机发送给服务器. 然后, 排出列表会被传送. 然后,客户机服务器的关系就只和错误和日志发送有关了.
本地的Rsync任务(原地址和目标地址都是本地挂载的文件系统)就像一个推送.客户机:作为发送端, 派生一个服务器进程去行使服务器的功能. 客户机/发送端和服务器/接收端通过管道相互通讯.
文件列表:文件列表不仅包括路径名,也包括所有者,模式, 读写权限, 大小和修改时间. 如果设置了--checksum选项, 文件列表还要包括文件的校验值.
Rsync启动完成后的第一件事, 发送端会建立文件列表. 在建立过程中, 每个条目都会通过一种优化的网络传送方式发送给接收方.
传输结束后, 两侧会以目录对基础目录的相关性来编排顺序. (具体的算法会和每次传输实用的协议版本有关). 一旦排序开始, 所以关于文件的指向都是使用他们在文件列表中的目录顺序.
如果必要, 发送者遵从文件列表中用户和组的id->name对应表 接收者会使用它来为文件列表中的每个文件作id->name->id翻译.
接收端收到完全的文件列表, 会派生出一个生成器, 和接收端一起建立一个完整的管道.
管道 Rsync严重依赖於管道. 这意味着一组进程间的的单向通讯. 一旦文件列表被共享, 管道就表现为如下的形式, 生成器->发送端->接收端
生成器的输出是发送端的输入, 发送端的输出是接收端的输入. 每个进程独立的运行, 只有在管道延迟,或者等待硬盘读写或CPU资源的时候才会有延迟.
生成器 生成器比较文件列表和本地目录树. 如果设置了--delete参数, 在开始它的主要工作前, 它首先会甄别在本地存在而在发送端上不存在的文件, 然后在接收端删除它们.
接下来生成器会开始遍历文件列表. 每个文件都被检查, 以确定是否需要同步. 大多数情况下如果修改时间和大小不同, 文件需要同步. 如果设置了--checksum, 文件校验会被计算并比较. 目录, 设备文件和链结不会被跳过. 缺失的目录会被创建.
如果一个文件需要同步, 在接收端的任何版本的该文件都会被作为一个传输的"基础文件"."基础文件"作为一个数据源,两侧比较下来一致的数据就不需要被传输了. 为了更有效的在远端匹配数据, 基础文件的块校验被计算, 并和文件的目录号一起送给发送端.如果设置了--whole-file, 空的块校验值用于新文件.块大小, 以及在后期的版本中块校验的大小, 是基于每个文件的大小计算的.发送端
发送端进程一次从生成器读一组文件号和相关联的块校验.
对每一个生成器发送的文件号, 发送端会存储块校验, 并建立一个哈希索引以快速检索.接着本地文件会被读取, 生成一个从文件的第一个字节开始的块作的校验. 这个校验会和生成器发过来的校验比较, 如果不相符, "不匹配"的字节会被加入到不匹配的数据中, 接着比较下一个字节的块. 这被称为"循环校验"
如果一个块的校验匹配就会被认为是一个匹配的块, 已经积累的不匹配块会被发送给接收端, 一起发送的还有块的偏移量和在接受端文件中的匹配块的长度. 块校验生成器会提前去检查匹配字节后面的一个字节.
即使块的顺序或者偏移量不同,以这种方法匹配的块也能够被确认. 这个程序是Rsync最核心的算法.通过这种方式, 发送者告诉接收端如何重组源文件成为一个目标文件. 这些指令包括所有的可以从基础文件拷贝的数据(如果存在的话), 和任何本地没有的新的数据, 的细节. 在处理末尾, 一个全文件的校验会被发送, 然后发送端去处理下一个文件.
生成循环校验以及在校验中找到匹配的数据, 对CPU的能力有很大的需求. 在所有的Rsync进程中,发送端是最消耗CPU资源的.
接收端 接收端会从发送端的数据中读取由文件索引号确认的文件. 然后打开本地文件(被称为基础文件), 建立一个临时文件.
接收端会读取非匹配数据和匹配数据, 并按顺序重组他们成为最终文件. 当非匹配数据被读取, 它会被写入到临时文件. 当收到一个块匹配记录, 接收端会寻找这个块在基础文件中的偏移量, 将这个块拷贝到临时文件. 通过这种方式, 临时文件被从头到尾建立起来.
建立临时文件的时候生成了文件的校验. 重建文件结束后, 这个校验和来自发送端的校验比较. 如果校验不符, 临时文件会被删除. 如果失败一次, 文件会再被处理一次. 如果失败第二次, 一个错误会被报告.
临时文件建立后, 所有者, 权限和修改时间会被设置. 然后它会被重命名已替代基础文件.
从基础文件拷贝数据到临时文件,使接收端成为所有进程中对硬盘要求最高的一个. 小文件还有可能在缓存中, 可以减轻对硬盘的压力; 但是对于大文件,在生成器去处理下一个文件的时候,或者还有由发送端造成的时延, 缓存中已经无法容纳更多的数据,只能清除掉旧的. 另外,数据是随机的从一个文件中读取, 并被写入另外一个, 如果读写的数据超过了硬盘缓存空间, 一个所谓的"寻找风暴"有可能发生,会进一步的损害性能.
守护程序 守护程序, 向所有的其他守护进程一样, 为每一个连接派生子进程. 启动的时候, 它解释rsyncd.conf, 以确认存在的模块, 并设置一些全局变量.
当接收到一个对已经定义的模块的连接时, 守护进程派生一个子进程去处理这个连接. 这个子进程然后去读取rsyncd.conf,
为被请求的模块设置变量, 这个工作有可能改变模块的root路径, 或者抛弃已设定的用户号和组号. 然后, 它就像其他的Rsync服务进程一样,
或者作为发送端, 或者作为接收端.
Rsync协议 一个良好定义的通讯协议有以下几个特性,-所有的数据都在良好定义的包中发送, 包括包头, 可选的包体, 或者数据净荷.
-每个包头中, 明确的指定数据类型或者命令.
-每个包都有一个确定的长度.
除了这些特性以外, 协议还应支持不同等级的状态, 包与包间的独立性, 人类可读性, 和重建一个断掉连接的能力.
Rsyncs协议不具备任何以上一点优秀特性. 数据作为不间断的字节流被传输.不匹配的文件数据是一个特例,没有包长度, 没有计数器. 每个字节的意义都是根据协议等级决定的, 都是独立的.
例如, 发送端要发送一个文件列表, 它就是简单的发送文件列表中的每一条, 发送结束就是一个NULL字节. 在文件列表的每一条中,有一个比特表示数据的结构, 这些变长的字符串只是被NULL字节简单的终结. 发送端发送文件索引号和块校验对的时候, 工作方式是一样的.
在可靠的连接上, 这种方法工作的很好, 它比正式的协议拥有较少的开销. 但是很不幸, 它造成协议很难被文档化, 调试, 或者扩展. 每个版本的协议在线路上表现的都不同, 除非知道确切的版本号才可以参与.
后记
文档还在继续被整理. 作者知道一定有一些明显的疏忽, 对于有些读者来说, 它更容易造成混乱, 而不是清晰. 希望它可以进化成一个有用的参考.欢迎提意见, 甚至重写的建议.
Note:
本文前半部分翻译,原文可从rsync官方网站上得到,但是因为 时间原因,没有翻译完成,已翻译的部分也存在词不达意的现象,等以后有时间再修改吧。后半部分是转载的网友的文章,原文地址为 这里
引用的文章:
http://bbs.chinaunix.net/thread-2112273-1-1.html
http://andylin02.iteye.com/blog/1041752