February 9th, 2010 by 张磊
Web服务器大多是支持直接发送GZip文件的。本文算是Rails中使用压缩的静态缓存的姊妹篇,谈谈在nginx中,进行适当配置使nginx直接发送压缩文件到浏览器。 配置起来非常容易。大致如下(实际情况可能更为复杂): location / { set $gzip_suffix ‘.gz’; if (-f $request_filename$gzip_suffix) { add_header Content-Type ‘text/html’; add_header Content-Encoding gzip; gzip off; rewrite (.*) $1.html$gzip_suffix break; } } 在上面这段配置中,先判断是否有xxx.gz文件存在,若有,则进入相应分支。在这个分支中,使用了两个add_header,会在响应头信息中增加相应的字段,以使客户端了解这是经过压缩的内容。若没有Content-Type ‘text/html’,打开页面时浏览器会弹出一个下载提示;若没有Content-Encoding gzip,打开只能看到一堆乱码。下面的 gzip off 则告诉nginx,不必再对这部分内容做压缩。 这样,就可以使nginx支持直接发送GZip压缩后的内容了,而且在浏览器中打开和普通html没有任何区别。但这种配置方式还遗留了一个问题,就是任何gz文件都被作为text/html而发送了。也许有这种需要:请求xxx.xml就将Content-Type设置为text/xml;请求xxx.css就将Content-Type设置为text/css。这当然有办法满足,不过我把这问题留给诸位,可以参考下这篇老文:在nginx中使用多个条件进行rewrite,相信可以助你秒杀这种需求。 此外,推荐一下RackspaceCloud。如果手头没有linux而且不方便拿服务器上的nginx做实验,可以在RackspaceCloud新建个服务器玩儿,搞完删掉就好了,既方便又干净。
February 8th, 2010 by 张磊
最近我的Linode服务器硬盘吃紧,一个16G的分区,使用率达到99%,就快无立锥之地了。某个Rails应用,生成的静态文件占用了超过9G的空间,并且还在不断增长。最初没想到好办法,想,难道要被逼升级服务器?后来联想到WP-SuperCache的原理,计上心来:用GZip压缩这些静态文件。 压缩文件做缓存有什么好处? 文本压缩的比例够大,这样做节约 压缩好之后,无需Web服务器再做压缩 那,会有什么问题? 不支持GZip的客户端,只能看到一堆乱码。据我观察,YSlurp疑似不支持GZip。 CPU的开销会增加 第一个问题也可以通过web服务器的一些逻辑判断,给不支持GZip的客户端返回未经压缩的内容(WP-SuperCache就是这么做的)——但个人感觉意义不大,大部分客户端都支持GZip,Google的SPDY(自备翻墙工具)都强制压缩强制SSL了。对第二个问题,VPS上主要是内存不够,CPU资源相对富裕。 在Rails中,做到这点非常轻松。原Controller中代码大致如下,无需改动这些代码,即可把静态页面缓存改为GZip格式。 cache_pages函数原型在action_pack/lib/action_controller/caching/pages.rb 中,大致的调用顺序为: 其中,class.cache_page函数进行了写入文件的操作,写入的位置是由class.page_cache_path决定的。看到这里,难道要撸起袖子hack Rails框架?No,只要在ApplicationController中加入几行代码,覆盖这两个函数即可做到。 def self.cache_page content, path # 若目录不存在,则创建,以免写入时报错 FileUtils.makedirs(File.dirname(page_cache_path(path))) Zlib::GzipWriter.open(page_cache_path(path)) do |gz| gz.write content end end # 使用super可以调用父类的同名方法 def self.page_cache_path path super + “.gz” end 将上面代码加入后,生成的静态缓存,就变成.gz后缀的压缩文件了。此外,Ruby的super函数真是一个很棒的玩意。 但这仅做了一半,我们还需要配置WEB服务器以支持直接发送GZip压缩文件。对Apache来说,可以大部分照搬WP-SuperCache的Rewrite规则;对nginx来说,还需要写一些配置。下一篇文章,将谈谈在nginx中如何做配置以支持直接发送GZip文件。