歪歪猪作坊 编程是一门手艺

如何快速地拷贝大量内容相近的文件

2013-09-30

这篇文章的标题想了很久,实际上也可以是《如何快速地向远端部署新版本的大应用》,《如何快速地发布新版本的大文件供下载》等等。

起因是因为在阿里云申请了一个服务器,因为在公网,而且有BGP,所以就想把原来提供客户下载版本的服务器从公司移到那边去。原来只有一条ADSL,所以客户下载时,相对于我们是上传,也就只有ADSL上传的512k的速度,而且部分客户用的是非电信的线路,下载时断时续,非常麻烦。公网服务器至少上下行都是2M,效果会好一点。一直以来为了体现我们的高端大气国际化,我们为每个客户都会保留从他们系统上线开始的全部的应用版本,主要也是为了吵架时方便,比如他们说,你们很早以前的版本就有什么什么的功能,为什么现在没有,我们可以拿早期的版本给他们看,说当初你们就没提过这种需求。

这样一来,我们就需要把全部客户,几年迭代更新下来的所有版本的应用,全部都从公司服务器上传到阿里云的服务器,依靠的是一条512k的ADSL线路,全部文件大约有20G,计算了一下,连续不断的传,全速传,至少也需要5天时间吧。对于急性子的处女座,这是不能接受的。

我们这些版本的打包文件都有一个重要的特点,版本与版本之间的变化是很小的,所以想到了之前帮客户做远程数据库备份文件拷贝时用到的一个工具:Xdelta。它利用了压缩算法中经常用到的delta encoding 方法,用于计算两个二进制的内容(可以是文件、视频的帧等)的不同。在我们这个例子中,只需要拿着最初的文件作为蓝本,逐步按时间顺序计算两个两个文件的差异,再把差异文件和最初文件传送到服务器端,再在服务器端恢复出来。所以写了这样一个脚本:

  
	#!/usr/local/bin/bash
	
	FILES=$1/*
	count=0
	echo '#!/usr/local/bin/bash' > before.sh
	echo '#!/usr/local/bin/bash' > after.sh
	for f in $FILES
	do
        	if [ $pre ]
        	then
                	echo 'xdelta delta '$pre $f $count'.diff' >>before.sh
                	pre_base=`basename $pre`
                	f_base=`basename $f`
                	echo 'xdelta patch '$count'.diff' $pre_base $f_base >>after.sh
        	fi
        	pre=$f
        	count=`expr $count + 1`
	done

根据某个目录下的所有文件,生成两个脚本文件,一个before.sh,一个after.sh,before.sh用于在原来服务器上,生成所有相邻文件的差异文件,after.sh用于在目标服务器上,以第一个文件为基础,根据差异文件,按顺序把所有文件恢复出来。

这样一来,需要传输的文件的大小,缩小到十分之一左右。一天之内就把所有文件都传输到公网服务器上了。

这个方法其实可以应用到很多场景。例如:做Java互联网应用最头疼的事情,应该是新版本的部署,Java应用,通常支撑的jar包的大小,都有几十到上百兆,要么就要把这些支持包做成应用服务器的公共包,但这样一来如果版本升级,或者有多个不同应用使用了不同版本的jar包就非常麻烦。要么每次升级,就要把一个几十到上百兆的war包传到公网上面,对于经常需要升级的应用来说就会非常耗时。使用xdelta,每次就只需传送差异部分,可以节省很多时间。

同样,做ROM、ISO或者游戏类apk发行的厂商,也可以使用这个方法,除了把各个版本的文件放上去,最好也放多一个和上个版本的diff文件,这样大家下载一个很小的diff文件,再patch到原来版本的文件上,就可以得到一个新版本的文件了。对于动辄上百兆的ROM、几百兆apk或者上G的ISO文件来说,可以节省很多带宽和时间。


相关阅读

评论