在上面的一篇,我们讲到了服务器端的缓存,我的地名信息系统有70万个页面,生成该页面的过程需要我从远程的数据库加载5个SQL数据返回的内容,还有RSS格式的新闻,因此生成一个页面是很困难的,因此我使用了服务端缓存技术使性能获得了大幅的提升,不过,又遇到了新的关于硬盘空间和流量的问题。
网站的70万个地名当然不会一天之内都会被访问,不过我的网站该栏目日访问量大约为30000,考虑到重复的访问,假设只访问了10000个地名(实际上是不只的,因为地名的访问很零散),那就是会有10000个缓存文件被生成,假设每个文件只有10K(实际上也不只这么大),合起来第一天就会产生100M的缓存(实际上我的网站第一天就有300M),之后每天还是以50M的速度增加,而我的网站空间一共只有600M,我有一次10天没有关注网站,结果因为硬盘空间站用到达2G而被万网关闭了。
还有就是随着访问量的增大,网站流量也很大,一个月第8天就将万网限制的50G流量用到了20G,而网站访问量还在上涨。
在这个时候,我想到了GZIP。
GZIP是一个将压缩技术使用到HTTP上的技术,说起来很简单,就是让服务器将文件内容压缩并发给浏览器,浏览器接受之后先解压再用来解析,在这种情况下,节省网络流量开支,浏览器传送的文本是很多的,而文本压缩通常都可以到原来文件的20%,而且GZIP技术目前主流的浏览器都是支持的,这是一个通过消耗服务器性能来节省流量的模式。
不过在我的使用之中,并没有消耗服务器性能,而直接节省流量,因为我在使用的时候,文件在缓存的时候就直接使用GZIP格式来存放了,因此在客户端请求该文件的时候,我不需要先压缩再传送,而是直接传送,相对来讲,甚至还提高了服务器的性能。
我使用的时候,在缓存文件生成的时候,将文本直接压缩为GZIP格式来保存,这样的话,我的缓存文件大小由原来的15K左右变为2-3K,大大的节省了网站的空间,当用户访问该文件的时候,我进行判断,如果浏览器是支持GZIP的,我就直接将缓存文件的字节流返回到浏览器,如果浏览器不支持(这种可能性相当低),我反而需要将该文件解压,将解压后的字节流返回到客户端。
以上可以看出,我确实节省了网站的空间和流量,而且因为现在的浏览器95%以上(保守估计,因为我没有听说哪个不支持)都是支持GZIP的,实际上网站的服务端性能反而有提升,这叫有百利而五一害。
如何判断浏览器是否支持GZIP呢?浏览器在发送HTTP请求的时候,会有一个HEAD字段叫Accept-Encoding,代表浏览器支持的返回编码格式,通常为以下值(deflate代表明文):
Accept-Encoding: gzip, deflate
浏览器又如何判断服务端返回的数据是明文还是GZIP格式的呢?也是通过服务端的HEAD字段,例如:
Content-Encoding: gzip
如果该值不是GZIP,则代表为明文,而且,该字段同时也可能代表文本文件的编码,例如utf-8
以下是我具体使用GZIP的做法,首先是缓存的写入过程:
FileStream fileStream=File.Create(path);//创建缓存文件
Stream writer=new GZipOutputStream(fileStream);//将缓存文件流使用GZIP来写入
XsltArgumentList list=new XsltArgumentList();//我的网站是使用XML+XSLT来生成页面的
xslt.Transform(xml,list,writer,null);//将XSLT生成的内容传递到GZIP压缩程序
writer.Close();//完成写入
fileStream.Close();//关闭文件句秉
其次是读取缓存的过程:
if(acceptEncoding!=null && acceptEncoding.IndexOf("gzip")>=0)//通过请求的http head来判断是否支持GZIP
{//如果支持GZIP,返回gzip格式
Response.AddHeader("Content-Encoding","gzip");//通知浏览器该文件是GZIP压缩过的文件
Response.TransmitFile(path);//直接将该文件返回
}
else
{//返回明文格式,这种情况下我们要从ZIP文件之中解压缩出文件内容,不需要发送Content-Encoding Head,因为默认就是明文的
Stream reader=new GZipInputStream(File.OpenRead(path));//打开该文件
byte[] buffer=new byte[1024];//建立文件读取缓存
int p;
while((p=reader.Read(buffer,0,1024))>0)//每次读取到相应的缓存就返回内容
{
Response.OutputStream.Write(buffer,0,p);
Response.Flush();
}
}
以上就是我的实现全过程,因为我是使用XML+XSLT来实现页面的,因此使用该技术的时候显得很顺畅,而对于通过页面ASPX,JSP等技术来返回的用户可能就有一些麻烦了
本文作者:未知