不差钱下载,差量页面下载技术Diffable的使用

声明:本文属乘风归去(http://www.cnblogs.com/cfgq/

首发于博客园或IBM Developerworks
转载请注明出处:http://www.cnblogs.com/cfgq/
PDF下载:
差量页面下载技术Diffable的使用不差钱下载

引言

对于大型Web应用程序,比如Google Map这样的项目,它所用到的JavaScript(后面简称JS)文件会非常大,很多都在500K以上。庆幸的是我们拥有浏览器的缓存技术,在服务器端JS文件没有修改的情况下,客户端可以不用重复的向服务器请求下载。但是,随着业务需求的变化,这些大型的JS文件会经常做局部的修改或完善,可能只是很少的修改,但是也会强制客户端更新缓存,重新下载整个的JS文件,而对于像Google Map这样访问量巨大的网站,这是不得不考虑的性能问题。聪明的程序员想到了,如果修改很少,则我们只下载增加或减少的那一部分不就可以嘛?如果可以实现这样的话,就可以大大的提高性能了。Google的开发人员实现了基于Java EE的实现版本,名为Diffable,基于该架构可以很好的实现静态资源的增量(delta)下载,大大提高性能,Google Map利用该技术提高了页面下载的25%的速度。本文介绍了Java EE版本的Diffable技术的使用,详细分析了使用该技术前后的不同。本文将逐步介绍Diffable的使用方法和实现原理,详细介绍了资源修改前后服务器与客户端的变化。附件部分是该文章使用的示例项目,读者可以下载下来导入开发环境运行查看。另外,本文所使用的静态资源文件都是JavaScript。

Diffable的原理

官方网站中给出了原理的架构图,如图1所示。

图 1. 示例项目结构图


差量页面下载技术Diffable的使用不差钱下载
文章针对Java EE这个特定实现讲解架构图,首先客户端请求JSP文件,服务器返回JSP的执行结果(该结果无需缓存,并且结果中包含了目标资源的最新版本号X,该目标资源由Diffable管理);浏览器解析HTML,请求下载Secondary Resource(官方叫法,在这里我们可以理解为控制资源,它的作用是请求增量、合并目标资源),该Secondary Resource包含了客户端缓存的目标资源版本号Y(如果客户端没有缓存,Secondary Resource请求X版本的整个资源)。Secondary Resource负责比较X与Y,如果二者相等,则直接使用本地缓存,如果二者不相等,则Secondary Resource负责请求X与Y的增量(delta)文件(Y_X.diff),并且将增量合并到本地缓存,更新本地缓存的资源号为X。从上面的叙述可以看出,要想使用Diffable,需要开启浏览器缓存、管理的必须是JS或CSS这样的静态文本资源。
如果您还不太理解,那么请记住几个关键字继续往后看,它们分别是:
目标资源(即客户端浏览器实际需要的资源文件,本文都是指JavaScript文件)、控制资源(Secondary Resource,它是一个JavaScript文件,目的是管理目标资源)、增量(delta, 对应后面的.diff文件)、版本(对应后面的.version文件)。

开发环境配置

JavaEE eclipse 3.4+ 下载链接
Tomcat5.0+ 下载链接
Diffable 环境:
以下的JAR包是保证Diffable能够运行的基础包。如果读者想进一步查看其余JAR包的下载和配置方法,请参照官方网址。
diffable-0.1.jar:下载链接
Google Guice-2.0.jar +: 下载链接
aopalliance1.0.jar +: 下载链接
commons-io-1.4.jar +: 下载链接
log4j-1.2.16.jar +: 下载链接。

Diffable的配置

第一步:在JEE Eclipse中新建Web项目,导入开发环境配置罗列的所有JAR包。示例项目完整的目录结构如图2所示。

图 2. 示例项目结构图


差量页面下载技术Diffable的使用不差钱下载
第二步:配置web.xml。

清单 1. web.xml中与Diffable有关的配置



ResourceFolders存放Diffable管理的资源(只支持JavaScript、CSS等静态文件),该配置是必须的,Diffable会监视该资源文件夹里的资源变化。如果有多个资源文件夹,使用逗号隔开,如WEB-INF/javascript,WEB-INF/CSS。

ResourceFolders
WEB-INF/javascript


DiffableListener
com.google.diffable.listeners.DiffableListener


Diffable属性配置文档,是一个properties文件,在此处可以配置Diffable的一些高级属性,例如KeepResourcesInMemory=[true/false] 该属性决定是否将资源保存在内存中以提高效率。该配置不是必须的。

DiffableConfigProperties
WEB-INF/diffable.properties


该配置是必须的,param-value的值是绝对路径,格式是/{web-app-name}/{servlet-url–pattern}.如示例项目的名为DiffableSample,后面配置的DiffableServlet的url pattern是/diffable/*, 所以ServletPrefix就是/DiffableSample/diffable。

ServletPrefix
/DiffableSample/diffable


DffiableServlet配置是必须的,这个servlet负责调度资源,解析资源请求
DiffableServlet

com.google.diffable.servlets.DiffableServlet



url-pattern的值必须与ServletPrefix对应,比如url-pattern改成/myDiffable/*,那么ServletPrefix的值就要改成/DiffableSample/myDiffable

DiffableServlet
/diffable/*

上面的配置对应着示例项目的结构,这里需要提及一点,之所以要将资源文件夹放在WEB-INFO目录下,目的是为了防止用户通过路径直接访问被Diffable管理的资源,因为我们知道WEB-INFO下的内容是不允许这样访问的。
配置完web.xml后,第三步就是使用Diffable了。传统上,我们在JSP中引用JavaScript是使用script标签,如:,然而当我们将资源交给Diffable管理时,我们就不能这么直接访问了(再说了,资源在WEB-INFO下也不允许我们那么访问)。Diffable给我们提供了资源标签diff:resource来引用资源,标签库文件.tld已经包含在了diffable-0.1.jar当中,因此无需配置。示例项目结构图中的sample.jsp的源码如清单2所示。

清单 2.使用Diffable标签

<%@ page language="java" contentType="text/html;"
pageEncoding="UTF-8" %>

<%@ taglib prefix="diff" uri="http://www.google.com/j2ee/diffable" %>









在testsample.js文件中声明了一个popUP方法,方法的代码块部分只有一句简单的alert("Hello Diffable!")作为例子。
第四步:启动服务器,使用浏览器访问sample.jsp,点击清单2,使用Diffable标签中声明的按钮,如果网页此时弹出Hello Diffable!的提示框,就说明您已经会使用Diffable了。
以上介绍的,可以说读者很容易就会使用Diffable了,但是究竟Diffable在底层都做了些什么呢?继续往后看。

首次部署运行

为了直观的让读者可以感受Diffable的不同,以及可以更好的介绍Diffable的原理和内部执行过程,本文将使用Firefox浏览器插件Firebug的网络监控功能,读者可以从监控中看出Diffable的资源请求过程。
将示例Web项目部署运行,查看TOMCAT的webapps目录里示例程序所在的目录,除了WEB-INFO和META-INF目录外会多出一个.diffable文件夹,diffable文件夹里则包含一个diffable.manifest文件和资源hash目录(存放目标资源,用hash值命名的目录),这些是Diffable启动时创建的。结果如图3中的上下部分所示。

图 3. diffable文件目录


差量页面下载技术Diffable的使用不差钱下载
这个Manifest包含Diffable所需要的一些资源控制变量。而我们程序员关注的是那个资源hash目录,它以一个hash值命名,这个hash值与清单1,web.xml中与Diffable有关的配置中配置的ResourceFolders里的资源对应,目前管理的资源只有一个testsample.js,也就是说273…85b这个hash值对应javascript/testsample.js。而我们打开这个资源hash目录,存放了一个.version文件,如图4所示。

图 4. 资源hash目录的内容


差量页面下载技术Diffable的使用不差钱下载
这个.version的文件名也是一个hash值,对应的是javascript/testsample.js文件的当前版本号,使用文本文件形式打开.version文件,可以发现该version文件的内容和testsample.js的内容完全一致,实际上Diffable是将目标资源文件的当前版本内容进行了拷贝,并拷贝到了.version文件里。
使用安装有Firebug的Firefox访问sample.jsp文件,打开网络监控功能。当访问结束时,我们查看网络监控的结果,如图5所示。

图 5.首次访问的网络监控结果


差量页面下载技术Diffable的使用不差钱下载
可以看到首次访问sample.jsp,由于浏览器没有相关缓存,所以2.8KB的数据都来自于服务器端。客户端发出了两个请求,分别是sample.jsp的请求(GET DiffableSample的原因是web.xml里的welcome file是sample.jsp,因此默认就是访问sample.jsp),以及资源文件testsample.js的请求。testsample.js的请求具体地址如图6所示。

图 6.第二个请求的地址


差量页面下载技术Diffable的使用不差钱下载
可以看到该地址的组成包含了http://{host}:{port}/{Diffable配置的ServletPrefix}/{.diffable目录下的资源hash目录名,与图3,diffable目录中的资源hash目录名对应,实际就是访问testsample.js文件},这个请求就是作用的效果。
查看GET DiffableSample这个请求的返回内容,如图7所示。

图 7.GET DiffableSample的返回内容


差量页面下载技术Diffable的使用不差钱下载
上面正文内容的第八行,显示了window[‘deltajs’][‘{资源hash目录名}’][‘cv’]=’{对应图4,资源hash目录下的版本号}’,cv代表的是Current Version,显示的服务器端的最新资源版本号。
查看testsample.js请求的响应,就是图5中第二个GET的请求响应,它的响应内容就是在Diffable的原理中介绍的控制资源(Secondary Resource),它的内容大致如清单3所示。

清单 3. 控制资源(Secondary Resource)

function DJSBootstrap(identifier, code) {
this.code_ = code;
this.identifier_ = identifier;
}
……
var djs = new DJSBootstrap('2738950c7ada0e700bf33c48fccf585b', "function popUP()\r\n{\r\n\talert(\"Hello Diffable!\");\r\n}");
djs.bootstrap('bf72f6fd3c0e70bd83ac2a0647d77173', '/DiffableSample/diffable/');
我们关注最后三行,DJSBootstrap对象构造函数的第一个参数是资源hash目录名,第二个参数则是本地缓存的资源内容,由于首次没有用到缓存,所以该部分内容就是从服务器端下载的资源最新内容。第三行调用了djs的bootstrap方法,该方法的第一个参数是缓存中的资源版本号,第二个是ServletPrefix的值。使用Firebug的调试功能单步调试bootstrap方法可以发现,控制资源(Secondary Resource)的bootstrap方法中对比了图7中响应的cv值(服务器最新的版本)和bootstrap构造方法的首个参数(缓存的资源版本),由于二者一致,所以没有请求增量。
我们在Firefox的地址栏按下回车,重新访问(不是按F5,因为F5会清空缓存),再看网络监控。结果如图8所示。

图 8.第二次加载


差量页面下载技术Diffable的使用不差钱下载
上图中,URL是灰色的代表来至于缓存(2.2KB来自缓存)。由于服务器端的资源文件没有做任何修改,所以包含testsample.js的控制资源(Secondary Resource)也没有任何改变。

修改服务器端JS文件

我们修改服务器端的testsample.js文件,将alert语句改为alert("Hello Diffable! New Change!")。保存后,我们再看图3中的资源hash目录下的版本文件,如图9所示。

图 9. 第一次修改后的资源版本


差量页面下载技术Diffable的使用不差钱下载
我们看到,除了旧版本的bf7…173.version,还多了新的版本文件196…8ee.version,这是Diffable自动生成的。打开bf7…173.version发现它的内容与旧版本testsample.js的相同, 196…8ee.version的内容则是alert("Hello Diffable! New Change!"),是最新版本的内容。还有一个文件,是以{旧版本号}_{新版本号}.diff命名的增量(delta)文件。打开该delta文件,查看结果如图10所示。

图 10. delta的文件内容


差量页面下载技术Diffable的使用不差钱下载
可以看到,该文件存放了新旧版本的增量部分。
使用Firefox再次使用地址栏回车的方式访问sample.jsp文件,查看网络监控结果,如图11所示。

图 11. 第一次修改资源后访问


差量页面下载技术Diffable的使用不差钱下载
我们看到这次访问发送了三个请求,前两个请求与图8中的请求的一样,第三个的GET请求地址如图12所示。

图 12. 第三个请求地址


差量页面下载技术Diffable的使用不差钱下载
可以看到,第三次GET请求的地址是新旧版本的增量文件。它的URL格式是{资源hash目录名}_{旧版本号}_{新版本号}.diff。访问的文件其实就是图9中的增量文件。查看这个GET请求的返回内容,如图13所示。

图 13. 第三个GET返回内容


差量页面下载技术Diffable的使用不差钱下载
可以看到,返回的响应内容就是图10增量文件中的内容。
我们再看前两个GET请求,第一个请求的返回内容如清单4所示。

清单 4. 修改后GET DiffableSample的内容










清单4获得最新版本号CV是196…8ee,再查看第二个GET请求的返回内容,与清单3中的内容完全相同。也就是说控制资源用到了缓存,这也是图11中显示2.2KB来自缓存的原因。再次使用Firebug调试bootstrap方法,可以发现DJSBootstrap对比了缓存的资源版本号(bf7…173)与服务器最新版本号CV(196…8ee),发现服务器的最新版本号与本地的缓存版本号不相同,则会发出第三个请求去下载二者的增量文件.diff,并且由控制资源进行合并更新。这也是图11,修改后的请求次数比图5,修改前的请求次数多一次的原因。最后修改后的访问结果如图14所示。

图 14. 修改后结果


差量页面下载技术Diffable的使用不差钱下载
从修改前后的请求可以看出,控制资源的访问会使用缓存,更新的仅仅就是新旧版本的增量文件。这对于大型文件的更新,效率的提高是显而易见的。

第二次修改服务器端JS文件

我们再一次修改服务器端的testsample.js文件,将alert语句改为alert("Hello Diffable! New Change! Again!")。保存后,我们再看资源hash目录下的版本、增量列表。结果如图15所示。

图 15. 第二次修改后


差量页面下载技术Diffable的使用不差钱下载
可以看到除了上面的提到的两个旧版本外,又多了一个b28…355的版本,打开这个版本文件,内容是alert("Hello Diffable! New Change! Again!"),可以知道b28…355是服务器端testsample.js的最新版本。再看增量文件,原先图9,第一次修改后的bf7…173_196…8ee.diff增量文件已经被删除,转变为各个旧版本到最新版本的增量。保留这些旧版本,同时创建各个旧版本到最新版本的增量,显而易见是考虑到各个客户端可能存在的不同缓存版本,使得他们都可以实现增量下载。

结果分析

上面共分为三个部分讲解了Diffable的内部执行过程和原理,分别是首次部署运行,修改服务器端JS文件,第二次修改服务器端JS文件。首次部署时,Diffable为每个管理的资源创建资源hash目录,并且在目录里创建了.version的版本文件,文件内容是资源的拷贝。第一次访问sample.jsp文件,发送了两个请求,一个是包含最新版本号cv的HTML,一个是包含了最新资源(bootstrap的第二个参数就是最新资源内容)的控制资源(Secondary Resource)。刷新会发现,控制资源已经被缓存;修改testsample.js资源文件的内容,出现了新的version文件以及新旧版本的增量diff文件。请求sample.jsp,会发现客户端发出了三个请求,第一个是包含最新版本号cv的HTML,这个请求得到了与缓存不同的cv,所以不能用到缓存。第二个请求用到了缓存,仍然是上一次请求的控制资源,里面包含了上一版本缓存的testsample.js的内容和版本号。通过比较缓存和最新版本的版本号判断是否下载二者增量,由于服务器的文件进行了修改,所以会发出第三个请求,下载缓存与最新版本间的增量,并且由控制资源负责整合增量与缓存,更新缓存;之后我们又修改了资源文件,资源hash目录下共出现了前后三个版本的version文件,以及两个diff文件。事实上为了保证客户端存在的不同缓存版本都可以进行增量下载,diff文件始终是各个旧版本到最新版本的增量。

该技术的利与弊

前面提及了Diffable的优点,但是使用一项技术时得知道它的适用环境,而不是随便滥用。对于一个大资源文件做少量修改的需求,Diffable的使用可以大大的提高性能。但是如果文件不大,或者修改的频率非常低,该技术的使用反而会减少效率,因为每次请求都会进行对比、执行资源,相当于在目标资源和浏览器之间增加了一层(就是控制资源),同时服务器端的DiffableServlet还需要进行一些验证、选择处理等,这些都是消耗资源的操作。因此,当资源大、修改频繁时,可以使用Diffable,而对于那些资源不大、修改频率很少的资源,就得用普通的引用资源方法。

小结

本文通过简单的例子开发,讲解了Diffable的使用方法和基本原理,对JS文件进行多次修改后,服务器端文件以及客户端请求的变化,展示了Diffable技术的优越性,同时分析了该技术的利与弊,供读者分析并合理的选择该技术。由于本人知识水平有限,文章中倘若有错误的地方,欢迎联系我批评指正。

参考资源

· 参考 Diffable官方网站,了解Diffable的最新动态。
· 查看“Google提出Web性能优化新方法——Diffable”文章,了解Diffable,作为抛砖引玉之用。
· 查看“Diffable讨论组”,了解最新的使用案例。
· 查看“Diffable博客”,了解有关Diffable的讨论。
Tags:  鬼差txt下载 就差钱小品下载 就差钱下载 不差钱小品下载 不差钱下载

延伸阅读

最新评论

发表评论