Rails 使用 Rails Asset Pipeline 配合 Nginx 的 gzip_static 优化 tips

rainchen for Beansmile · 2014年05月21日 · 最后由 diguage 回复于 2014年07月15日 · 7364 次阅读
本帖已被设为精华帖!

看到大家分享了些关于 cache 的优化 tips,我也搭车来点最近在公司内部做的技术分享:

使用 Rails Asset Pipeline 配合 Nginx 的 gzip_static 优化 tips

Rails 的 Asset Pipeline 的生成文件

使用 Rails 的 Asset Pipeline,会生成 2 个文件:一个是把所有 css/js 的打包成的一个文件,一般是 application-[hash].css, 另一个是同名 gz 后缀的 gzip 文件:application-[hash].css.gz

打包成一个文件很好理解,这样可以减少 js 请求数量,因为浏览器会限制同一个域名同时发起请求的数量; 带 hash 作为文件的版本号,一旦有新的版本部署,hash 值会变化,这样浏览器也不会去 load 缓存里的文件。 但为什么还要生成一个 gz 文件呢?

nginx 的 gzip 输出

nginx 可以把输出的内容使用 gzip 压缩再发送到浏览器,浏览器如果支持 gzip 解压会在 request header 包含Accept-Encoding: compress, gzip,这样 nginx 就会发送 gzip 后的内容,并在 reponse header 加入Content-Encoding: gzip声明这是 gzip 后的内容,告诉浏览器要先解压。 让 nginx 使用 gzip 压缩内容可以减少传输数据大小,但压缩率越高 CPU 消耗越高,CPU 消耗高,意味着 nginx 能同时处理的响应能力就要下降。

nginx 的 gzip_static 模块

好在 nginx 又提供了个gzip_static模块,只要在部署时预编译好 gzip 文件,同时让 nginx 启用 gzip_static,在响应请求时 nginx 检查到有同名的.gz 文件,就会把 gz 文件的内容直接发送出去。

所以在部署时预先编译好 gzip 文件的话,可以用最高的压缩率使文件最小从而节省带宽, 而 nginx 就只需简单发送文件了,不用再做 gzip 处理,这样请求时可以省 cpu。

要启用 nginx 的 gzip_static 模块,首先我们要确认 nginx 的 gzip_static 模块已经被编译进去:

$ /opt/nginx/sbin/nginx -V

如果该命令输出有--with-http_gzip_static_module,则说明 nginx 支持 gzip_static 模块。如果没有,需要加上 --with-http_gzip_static_module 该参数重新编译 nginx。

rails asset pipeline + nginx gzip_static

在 nginx 的 http 配置里添加 gzip_static 的配置:

location ~ ^/(assets)/  {
  root /path/to/public;
  gzip_static on; # to serve pre-gzipped version
  expires max;
  add_header Cache-Control public;
}

如何检验优化结果

检查 nginx 的 gzip_static 配置是否生效:

开启 gzip_static 前:

$ curl -I -H "Accept-Encoding: gzip,deflate" http://example.com/assets/application-cfb3e4017298e9fd00a3bc04d3dea72c.css

HTTP/1.1 200 OK
Server: nginx/1.4.7
Date: Thu, 08 May 2014 14:14:48 GMT
Content-Type: text/css
Content-Length: 7167
Last-Modified: Tue, 06 May 2014 17:27:06 GMT
Connection: keep-alive
ETag: "53691b6a-1bff"
Accept-Ranges: bytes

开启 gzip_static 后:

$ curl -I -H "Accept-Encoding: gzip,deflate" http://example.com/assets/application-cfb3e4017298e9fd00a3bc04d3dea72c.css

HTTP/1.1 200 OK
Server: nginx/1.4.7
Date: Thu, 08 May 2014 14:13:24 GMT
Content-Type: text/css
Content-Length: 2284
Last-Modified: Tue, 06 May 2014 17:27:06 GMT
Connection: keep-alive
ETag: "53691b6a-8ec"
Content-Encoding: gzip
Expires: Thu, 31 Dec 2037 23:55:55 GMT
Cache-Control: max-age=315360000
Cache-Control: public

可以看到 Content-Type: text/css 没有改变,但Content-Length已经变小,而且有Content-Encoding: gzip标记。 浏览器识别到Content-Encoding: gzip的标记,自然就会用 gzip 来解压接收到的内容了。

一句话总结

rails 的 asset pipeline 搭配 nginx 的 gzip_static 使用就可以省带宽省 CPU。

楼主调整一下排版呗,略乱,另外 asspets precompile -> Assets Pipeline

#1 楼 @huacnlee 感谢指正,已经 update

gz 压缩需要适度,这不但需要考虑服务器的压缩压力,还得考虑浏览器解压缩的效率问题。帖子不错,顶一个

还有这样的功能!涨姿势了~

赞!

HTTP Status Code: 304 Not Modified 这个 feture 是不是也要提及下比较好。

location ~ ^/(assets)/  {
  root /path/to/public;
  gzip_static on; # to serve pre-gzipped version
  expires max;
  add_header Cache-Control public;
}

是不是有默认开启的啊?我记得我从来没有设置过这东西,然后 Content-Encoding:gzip 。

用得是 Nginx + Passenger。

@huacnlee 奇怪,内容怎么变了?我有加了段落标题的

#11 楼 @rainchen 我微调了一下

#10 楼 @ruby_sky 默认应该没有,你的可能只是开启了 nginx 对 js,png 等内容进行自动 gzip

哈,太赞了!

都是 @quakewang 带的好头!

赞 :plus1:

你明明请求得是 js 文件,怎么会是 text/css

#16 楼 @pynix 真眼尖,我测试用的是 css 文件,但文字开头用的是 js,所以 i 随手改了下文件名保持一致,我改一下

😃 赞!最近 Ruby-China 上这些高质量的帖子层出不穷啊

这个不错!!!

对手机页面是福音,弄起来

不错,赞一个。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册